/*
 * See LICENSE file in distribution for copyright and licensing information.
 */
package ioke.lang;

import java.util.ArrayList;
import java.util.HashMap;

import ioke.lang.exceptions.ControlFlow;

/**
 *
 * @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a>
 */
public abstract class JavaMethod extends Method {
    public static class WithNoArguments extends JavaMethod {
        private final static DefaultArgumentsDefinition ARGUMENTS = DefaultArgumentsDefinition.empty();

        public WithNoArguments(String name) {
            super(name);
        }

        @Override
        public DefaultArgumentsDefinition getArguments() {
            return ARGUMENTS;
        }
    }

    public JavaMethod(String name) {
        super(name);
    }

    @Override
    public void init(IokeObject javaMethod) throws ControlFlow {
        javaMethod.setKind("JavaMethod");
        javaMethod.registerMethod(javaMethod.runtime.newJavaMethod("returns a list of the keywords this method takes", new WithNoArguments("keywords") {
                @Override
                public Object activate(IokeObject self, IokeObject context, IokeObject message, Object on) throws ControlFlow {
                    getArguments().getEvaluatedArguments(context, message, on, new ArrayList<Object>(), new HashMap<String, Object>());

                    return context.runtime.newList(new ArrayList<Object>());
                }
            }));
        javaMethod.registerMethod(javaMethod.runtime.newJavaMethod("returns the code for the argument definition", new WithNoArguments("argumentsCode") {
                @Override
                public Object activate(IokeObject self, IokeObject dynamicContext, IokeObject message, Object on) throws ControlFlow {
                    getArguments().getEvaluatedArguments(dynamicContext, message, on, new ArrayList<Object>(), new HashMap<String, Object>());

                    IokeData data = IokeObject.data(on);
                    if(data instanceof JavaMethod) {
                        return dynamicContext.runtime.newText(((JavaMethod)data).getArgumentsCode());
                    } else {
                        return dynamicContext.runtime.newText(((AssociatedCode)data).getArgumentsCode());
                    }
                }
            }));
    }

    public abstract DefaultArgumentsDefinition getArguments();

    public String getArgumentsCode() {
        return getArguments().getCode(false);
    }

    @Override
    public Object activate(IokeObject self, IokeObject context, IokeObject message, Object on) throws ControlFlow {
        IokeObject condition = IokeObject.as(IokeObject.getCellChain(context.runtime.condition, 
                                                                     message, 
                                                                     context, 
                                                                     "Error", 
                                                                     "Invocation",
                                                                     "NotActivatable")).mimic(message, context);
        condition.setCell("message", message);
        condition.setCell("context", context);
        condition.setCell("receiver", on);
        condition.setCell("method", self);
        condition.setCell("report", context.runtime.newText("You tried to activate a method without any code - did you by any chance activate the JavaMethod kind by referring to it without wrapping it inside a call to cell?"));
        context.runtime.errorCondition(condition);

        return self.runtime.nil;
    }

    private String getDominantClassName() {
        String name = getClass().getName();
        int dollar = name.indexOf("$");
        int dot = name.lastIndexOf(".");
        if(dollar == -1) {
            dollar = name.length();
        }
        return name.substring(dot+1, dollar);
    }

    @Override
    public String inspect(Object self) {
        return "method(" + getDominantClassName() + ((name != null) ? ("_" + name) : "") + ")";
    }
}


@@ -150,16 +150,61 @@
 HashMap;
+%0Aimport java.util.List;%0Aimport java.util.Map;
 %0A%0Aimport
@@ -2642,470 +2642,454 @@
     
-IokeObject condition = IokeObject.as(IokeObject.getCellChain(context.runtime.condition, %0A                                                                     message, %0A                                                                     context, %0A                                                                     %22Error%22, %0A                                                                     %22Invocation%22,%0A                                                     
+return activate(self, on, null, null, context, message);%0A    %7D%0A%0A    public Object activate(IokeObject self, Object on, List%3CObject%3E args,%0A            Map%3CString, Object%3E keywords, IokeObject context, IokeObject message) throws ControlFlow %7B%0A        IokeObject condition = IokeObject.as(IokeObject.getCellChain(context.runtime.condition, %0A                message, %0A                context, %0A                %22Error%22, %0A                %22Invocation%22,%0A
     
@@ -3136,32 +3136,41 @@
 sage, context);%0A
+        %0A
         conditio
@@ -3648,24 +3648,28 @@
 .nil;%0A    %7D%0A
+    
 %0A    private

Add default arguments handler.