package som.primitives;

import som.interpreter.nodes.nary.BinaryExpressionNode;
import som.interpreter.nodes.nary.UnaryExpressionNode;
import som.vm.Universe;
import som.vm.constants.Globals;
import som.vm.constants.Nil;
import som.vmobjects.SAbstractObject;
import som.vmobjects.SClass;
import som.vmobjects.SObject;
import som.vmobjects.SSymbol;

import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;


public final class SystemPrims {
  public static boolean receiverIsSystemObject(final SAbstractObject receiver) {
    return receiver == Globals.systemObject;
  }

  @GenerateNodeFactory
  public abstract static class BinarySystemNode extends BinaryExpressionNode {
    protected final Universe universe;
    protected BinarySystemNode() { super(null); this.universe = Universe.current(); }
  }

  @ImportStatic(SystemPrims.class)
  public abstract static class LoadPrim extends BinarySystemNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver, final SSymbol argument) {
      SClass result = universe.loadClass(argument);
      return result != null ? result : Nil.nilObject;
    }
  }

  @ImportStatic(SystemPrims.class)
  public abstract static class ExitPrim extends BinarySystemNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver, final long error) {
      universe.exit((int) error);
      return receiver;
    }
  }

  @ImportStatic(SystemPrims.class)
  public abstract static class PrintStringPrim extends BinarySystemNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver, final String argument) {
      Universe.print(argument);
      return receiver;
    }

    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver, final SSymbol argument) {
      return doSObject(receiver, argument.getString());
    }
  }

  @ImportStatic(SystemPrims.class)
  @GenerateNodeFactory
  public abstract static class PrintNewlinePrim extends UnaryExpressionNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver) {
      Universe.println();
      return receiver;
    }
  }

  @ImportStatic(SystemPrims.class)
  @GenerateNodeFactory
  public abstract static class PrintInclNewlinePrim extends BinaryExpressionNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver, final String argument) {
      Universe.println(argument);
      return receiver;
    }
  }

  @ImportStatic(SystemPrims.class)
  @GenerateNodeFactory
  public abstract static class FullGCPrim extends UnaryExpressionNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final Object doSObject(final SObject receiver) {
      System.gc();
      return true;
    }
  }

  @ImportStatic(SystemPrims.class)
  @GenerateNodeFactory
  public abstract static class TimePrim extends UnaryExpressionNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final long doSObject(final SObject receiver) {
      return System.currentTimeMillis() - startTime;
    }
  }

  @ImportStatic(SystemPrims.class)
  @GenerateNodeFactory
  public abstract static class TicksPrim extends UnaryExpressionNode {
    @Specialization(guards = "receiverIsSystemObject(receiver)")
    public final long doSObject(final SObject receiver) {
      return System.nanoTime() / 1000L - startMicroTime;
    }
  }

  {
    startMicroTime = System.nanoTime() / 1000L;
    startTime = startMicroTime / 1000L;
  }
  private static long startTime;
  private static long startMicroTime;
}

@@ -181,82 +181,11 @@
 nts.
-Globals;%0Aimport som.vm.constants.Nil;%0Aimport som.vmobjects.SAbstractObject
+Nil
 ;%0Aim
@@ -331,56 +331,8 @@
 ry;%0A
-import com.oracle.truffle.api.dsl.ImportStatic;%0A
 impo
@@ -415,138 +415,8 @@
 ms %7B
-%0A  public static boolean receiverIsSystemObject(final SAbstractObject receiver) %7B%0A    return receiver == Globals.systemObject;%0A  %7D
 %0A%0A  
@@ -649,43 +649,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   pu
@@ -735,53 +735,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -937,43 +937,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   pu
@@ -1023,53 +1023,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -1170,43 +1170,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   pu
@@ -1263,53 +1263,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -1428,53 +1428,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -1580,43 +1580,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   @G
@@ -1700,53 +1700,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -1821,43 +1821,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   @G
@@ -1946,53 +1946,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -2098,43 +2098,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   @G
@@ -2212,53 +2212,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -2322,43 +2322,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   @G
@@ -2434,53 +2434,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   
@@ -2557,43 +2557,8 @@
  %7D%0A%0A
-  @ImportStatic(SystemPrims.class)%0A
   @G
@@ -2639,32 +2639,32 @@
 xpressionNode %7B%0A
+
     @Specializat
@@ -2670,53 +2670,8 @@
 tion
-(guards = %22receiverIsSystemObject(receiver)%22)
 %0A   

Remove broken guard