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

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

import java.util.Map;

public class MethodDefinition extends Definition {
	
	public static MethodDefinitionClass yclass(){
		return MethodDefinitionClass.singleton();
	}
	
	protected MethodDefinition(String name, MethodDefinitionClass yclass) {
		super(name, yclass);
	}	
	
	
	public void addParameter(String name, Reference typeLink, YObject defaultValue){
		YClass type = YClass.getYClass( typeLink );		
		getWrapped().addParameter(name, type, defaultValue);
	}
	
	public void setReturnType(Reference typeLink){
		YClass type = YClass.getYClass( typeLink );
		getWrapped().setReturnType(type);
	}
	
	public YClassDefinition getLogicalParent(){
		return (YClassDefinition) super.getLogicalParent();
	}	
	
	public void setWrapped(YMethod method){
		
//		if (getWrapped() != null) {
//			getWrapped().getOwnerClass().removeMethod(getWrapped());
//			getWrapped().getOwnerClass().addMethod(method);
//		}
		
		if (getWrapped() != null) {
			getLogicalParent().getWrapped().removeMethod(getWrapped());
			getLogicalParent().getWrapped().addMethod(method);
		}
		
		wrapped = method;
		method.setWrapperElement(this);
	}
	
	public YMethod getWrapped(){
		return (YMethod) super.getWrapped();
	}
	
//	@Override
//	public void setSource(String code){		
//		super.setSource(code);
//	}	
	

	@Override
	public void synchronize() {
		//getWrapped().getOwnerClass().getWrapperElement().synchronize();
		getLogicalParent().synchronize();
	}	
	


    public void reportRemovedElement(YObject element, YContainer parent, int index) {
    	throw new UnsupportedOperationException();
    }


    public void reportRemovedElementInRange(YObject element) {
    	throw new UnsupportedOperationException();
    }

    public void reportRenamedElement(YObject element, String oldname) {
    	throw new UnsupportedOperationException();
    }


    public void reportRelocatedElement(YObject element, YContainer oldparent) {
        throw new UnsupportedOperationException();
    }


    public void reportChangedField(SimpleObject field) {
        throw new UnsupportedOperationException();
    }
	
	
	public static class MethodDefinitionClass extends DefinitionClass {
		
		private static String CLASS_NAME = "MethodDef";
		private static MethodDefinitionClass singleton;
		
		public static MethodDefinitionClass singleton(){
			if (singleton == null) {
				singleton = new MethodDefinitionClass(CLASS_NAME);
				singleton.addSuperior( Definition.yclass() );
				singleton.addMethod(SetSource.function);
				placeClass(singleton);
			}			
			return singleton;
		}

		protected MethodDefinitionClass(String name) {
			super(name, null);
		}
		
		public YMethodDefinition create(YMethod method){
			YMethodDefinition methodDef = new YMethodDefinition(method.getName(), this);
			init(methodDef);
			
			methodDef.setWrapped(method);
			return methodDef;
		}
				
    	@Override
    	public YMethodDefinition create(String name) {
    		return create( new YMethod(name) );
    	}
    	
    	private static class SetSource extends YMethod {

    		private static final String FUNCTION_NAME = "setSource";
    		private static final String KEY_SOURCE = "source";
    		private static final YClass YCLASS_SOURCE = StringField.yclass();

    		public static final SetSource function = new SetSource();

    		protected SetSource() {
    			super(FUNCTION_NAME);
    			addParameter(KEY_SOURCE, YCLASS_SOURCE, null);
    			setReturnType( YObject.yclass() );
    		}

    		@Override
    		public YObject run(Map<String, YObject> params/*, Map<String, YObject> env*/, YObject thisElement) {
    			
    			
    			YMethodDefinition thisE = (YMethodDefinition) thisElement;
    			String source = ((StringField)params.get(KEY_SOURCE)).getValue();
    			
    			YMethodDefinition newDef = Synthetizer.createMethodDefinition(source);
    			
    			thisE.setWrapped( newDef.getWrapped() );
    			thisE.setSource( newDef.getSource() );
    			thisE.synchronize();
    			
    			return null;
    		}
    	}    	

		
	}

}
