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

import java.util.List;
import java.util.Map;

import ioke.lang.exceptions.ControlFlow;

/**
 *
 * @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a>
 */
public class DateTime extends IokeData {
    private org.joda.time.DateTime dateTime;

    public DateTime() {
        this(new org.joda.time.DateTime());
    }

    public DateTime(org.joda.time.DateTime val) {
        this.dateTime = val;
    }

    public DateTime(long instant) {
        this(new org.joda.time.DateTime(instant));
    }

    public static org.joda.time.DateTime getDateTime(Object on) {
        return ((DateTime)IokeObject.data(on)).dateTime;
    }

    @Override
    public void init(IokeObject obj) throws ControlFlow {
        final Runtime runtime = obj.runtime;

        obj.setKind("DateTime");
        //        obj.mimics(IokeObject.as(runtime.mixins.getCell(null, null, "Comparing")), runtime.nul, runtime.nul);

        obj.registerMethod(runtime.newNativeMethod("Returns a new DateTime representing the current instant in time in the default TimeZone.", new NativeMethod.WithNoArguments("now") {
                @Override
                public Object activate(IokeObject method, Object on, List<Object> args, Map<String, Object> keywords, IokeObject context, IokeObject message) throws ControlFlow {
                    return method.runtime.newDateTime(new org.joda.time.DateTime());
                }
            }));

        obj.registerMethod(runtime.newNativeMethod("Expects to get one DateTime as argument, and returns the difference between this instant and that instant, in milliseconds.", new TypeCheckingNativeMethod("-") {
                private final TypeCheckingArgumentsDefinition ARGUMENTS = TypeCheckingArgumentsDefinition
                    .builder()
                    .receiverMustMimic(runtime.dateTime)
                    .withRequiredPositional("subtrahend").whichMustMimic(runtime.dateTime)
                    .getArguments();

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

                @Override
                public Object activate(IokeObject method, Object on, List<Object> args, Map<String, Object> keywords, IokeObject context, IokeObject message) throws ControlFlow {
                    long diff = getDateTime(on).getMillis() - getDateTime(args.get(0)).getMillis();
                    return context.runtime.newNumber(diff);
                }
            }));

        obj.registerMethod(runtime.newNativeMethod("Returns a text inspection of the object", new TypeCheckingNativeMethod.WithNoArguments("inspect", runtime.dateTime) {
                @Override
                public Object activate(IokeObject method, Object on, List<Object> args, Map<String, Object> keywords, IokeObject context, IokeObject message) throws ControlFlow {
                    return method.runtime.newText(DateTime.getInspect(on));
                }
            }));

        obj.registerMethod(runtime.newNativeMethod("Returns a brief text inspection of the object", new TypeCheckingNativeMethod.WithNoArguments("notice", runtime.dateTime) {
                @Override
                public Object activate(IokeObject method, Object on, List<Object> args, Map<String, Object> keywords, IokeObject context, IokeObject message) throws ControlFlow {
                    return method.runtime.newText(DateTime.getNotice(on));
                }
            }));
    }

    public IokeData cloneData(IokeObject obj, IokeObject m, IokeObject context) {
        return this;
    }

    public static String getInspect(Object on) throws ControlFlow {
        return ((DateTime)(IokeObject.data(on))).inspect(on);
    }

    public static String getNotice(Object on) throws ControlFlow {
        return ((DateTime)(IokeObject.data(on))).notice(on);
    }

    @Override
    public boolean isEqualTo(IokeObject self, Object other) {
        return ((other instanceof IokeObject) && 
                (IokeObject.data(other) instanceof DateTime) 
                && this.dateTime.equals(((DateTime)IokeObject.data(other)).dateTime));
    }

    @Override
    public String toString() {
        return this.dateTime.toString();
    }

    @Override
    public String toString(IokeObject obj) {
        return this.dateTime.toString();
    }

    public String inspect(Object obj) throws ControlFlow {
        return this.dateTime.toString();
    }

    public String notice(Object obj) throws ControlFlow {
        return this.dateTime.toString();
    }
}// DateTime

@@ -141,16 +141,42 @@
 til.Map;
+%0Aimport java.util.HashMap;
 %0A%0Aimport
@@ -1022,24 +1022,1388 @@
 time.nul);%0A%0A
+        obj.registerMethod(runtime.newNativeMethod(%22returns true if the left hand side datetime is equal to the right hand side datetime.%22, new TypeCheckingNativeMethod(%22==%22) %7B%0A                private final TypeCheckingArgumentsDefinition ARGUMENTS = TypeCheckingArgumentsDefinition%0A                    .builder()%0A                    .receiverMustMimic(runtime.dateTime)%0A                    .withRequiredPositional(%22other%22)%0A                    .getArguments();%0A%0A                @Override%0A                public TypeCheckingArgumentsDefinition getArguments() %7B%0A                    return ARGUMENTS;%0A                %7D%0A%0A                @Override%0A                public Object activate(IokeObject self, Object on, List%3CObject%3E args, Map%3CString, Object%3E keywords, IokeObject context, IokeObject message) throws ControlFlow %7B%0A                    getArguments().getEvaluatedArguments(context, message, on, args, new HashMap%3CString, Object%3E());%0A                    DateTime d = (DateTime)IokeObject.data(on);%0A                    Object other = args.get(0);%0A                    return ((other instanceof IokeObject) &&%0A                            (IokeObject.data(other) instanceof DateTime)%0A                            && d.dateTime.equals(((DateTime)IokeObject.data(other)).dateTime)) ? context.runtime._true : context.runtime._false;%0A                %7D%0A            %7D));%0A%0A
         obj.
@@ -5364,290 +5364,8 @@
  %7D%0A%0A
-    @Override%0A    public boolean isEqualTo(IokeObject self, Object other) %7B%0A        return ((other instanceof IokeObject) && %0A                (IokeObject.data(other) instanceof DateTime) %0A                && this.dateTime.equals(((DateTime)IokeObject.data(other)).dateTime));%0A    %7D%0A%0A
     

Make DateTime equality semantics work correctly