package hu.swankey.ammo.common.yggdrasil.definition;

import hu.swankey.ammo.common.script.AmmoScriptException;
import hu.swankey.ammo.common.script.yunits.YClass;
import hu.swankey.ammo.common.script.yunits.YMethod;
import hu.swankey.ammo.common.yggdrasil.basics.StringField;
import hu.swankey.ammo.common.yggdrasil.basics.YContainer;
import hu.swankey.ammo.common.yggdrasil.basics.YObject;

import java.util.Map;

public class ComplexClassDefinition extends YClassDefinition {

    public static final String KEY_FIELDS = "fields";

    protected ComplexClassDefinition(String name,
            ComplexClassDefinitionClass yclass) {
        super(name, yclass);
    }

    public static ComplexClassDefinitionClass yclass() {
        return ComplexClassDefinitionClass.singleton();
    }

    public YContainer getFieldContainer() {
        return (YContainer) get(KEY_FIELDS);
    }

    public void addElement(AttributeDefinition var) {
        getWrapped().addElement(var);
    }

    @Override
    public ComplexYClass getWrapped() {
        return (ComplexYClass) wrapped;
    }

    @Override
    public void synchronize(boolean report) {
        super.synchronize(false);

        boolean changed = false;

        // Insert new fields:
        for (AttributeDefinition varDef : getWrapped().getFields()) {
            if (!getFieldContainer().containsKey(varDef.getName()))
                getFieldContainer().put(varDef);
            varDef.setLogicalParent(this);
            changed = true;
        }

        // Remove removed superiors:
        // Iterator<YObject> it =
        // getSuperiorsContainer().getElements().iterator();
        // while (it.hasNext()) {
        // YClass superior = (YClass)
        // YObject.yclass().getRootPackage().get((SoftLink)it.next());
        // if ( !getWrapped().getSuperiors().contains(superior))
        // it.remove();
        // }

        if (changed && report)
            reportChange();
    }

    public static class ComplexClassDefinitionClass extends
            ClassDefinitionClass {

        private static String CLASS_NAME = "ComplexClassDef";
        private static ComplexClassDefinitionClass singleton;

        public static ComplexClassDefinitionClass singleton() {
            if (singleton == null) {
                singleton = new ComplexClassDefinitionClass(CLASS_NAME);
                singleton.addSuperior(YClassDefinition.yclass());
                singleton.addMethod(AddField.function);
                singleton.addMethod(RemoveField.function);
                singleton.addElement(AttributeDefinition.yclass().create(
                        KEY_FIELDS,
                        ContainerClass.getContainerClass(AttributeDefinition
                                .yclass()), null));
                placeClass(singleton);
            }
            return singleton;
        }

        protected ComplexClassDefinitionClass(String name) {
            super(name);
        }

        public ComplexClassDefinition create(ComplexYClass wrappedYClass) {
            ComplexClassDefinition classDef = new ComplexClassDefinition(
                    wrappedYClass.getName(), this);
            init(classDef);
            classDef.setWrapped(wrappedYClass);
            return classDef;
        }

        @Override
        public ComplexClassDefinition create(String name) {
            ComplexClassDefinition classDef = new ComplexClassDefinition(name,
                    this);
            init(classDef);

            ComplexYClass newClass = new ComplexYClass(name, null);
            classDef.setWrapped(newClass);
            placeClass(newClass);

            return classDef;
        }

        // @Override
        // public ComplexClassDefinition create(String name) {
        // ComplexClassDefinition classDef = create( new ComplexClass(name,
        // null) );
        // placeClass(classDef.getWrapped());
        // return classDef;
        // }

    }

    private static class AddField extends YMethod {

        private static final String FUNCTION_NAME = "addField";
        private static final String KEY_CLASS = "yclass";
        private static final String KEY_NAME = "name";
        private static final YClass YCLASS_CLASS = YClassDefinition.yclass();
        private static final YClass YCLASS_NAME = StringField.yclass();

        public static final AddField function = new AddField();

        protected AddField() {
            super(FUNCTION_NAME);
            addParameter(KEY_CLASS, YCLASS_CLASS, null);
            addParameter(KEY_NAME, YCLASS_NAME, null);
        }

        @Override
        public YObject run(Map<String, YObject> params, YObject thisElement)
                throws AmmoScriptException {
            YClass yclass = ((YClassDefinition) params.get(KEY_CLASS))
                    .getWrapped();
            String name = ((StringField) params.get(KEY_NAME)).getValue();

            AttributeDefinition varDef = AttributeDefinition.yclass()
                    .create(name);
            varDef.setVarClass(yclass);

            ((ComplexClassDefinition) thisElement).getWrapped().addElement(
                    varDef);

            return null;
        }
    }

    private static class RemoveField extends YMethod {

        private static final String FUNCTION_NAME = "removeField";
        private static final String KEY_FIELD = "field";
        private static final YClass YCLASS_FIELD = AttributeDefinition.yclass();

        public static final RemoveField function = new RemoveField();

        protected RemoveField() {
            super(FUNCTION_NAME);
            addParameter(KEY_FIELD, YCLASS_FIELD, null);
        }

        @Override
        public YObject run(Map<String, YObject> params, YObject thisElement) throws AmmoScriptException {
            
            AttributeDefinition varDef = ((AttributeDefinition) params.get(KEY_FIELD));

            ((ComplexClassDefinition) thisElement).getWrapped().removeElement(varDef);

            return null;
        }
    }

}
