package som.primitives.threading;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

import som.interpreter.nodes.nary.UnaryExpressionNode;
import som.primitives.Primitive;
import som.vmobjects.SClass;


public final class MutexPrimitives {
  @GenerateNodeFactory
  @Primitive(primitive = "threadingLock:")
  public abstract static class LockPrim extends UnaryExpressionNode {
    public LockPrim(final boolean ew, final SourceSection s) { super(ew, s); }

    @TruffleBoundary
    @Specialization
    public ReentrantLock doLock(final ReentrantLock lock) {
      lock.lock();
      return lock;
    }
  }

  @GenerateNodeFactory
  @Primitive(primitive = "threadingUnlock:")
  public abstract static class UnlockPrim extends UnaryExpressionNode {
    public UnlockPrim(final boolean ew, final SourceSection s) { super(ew, s); }

    @TruffleBoundary
    @Specialization
    public ReentrantLock doLock(final ReentrantLock lock) {
      lock.unlock();
      return lock;
    }
  }

  @GenerateNodeFactory
  @Primitive(primitive = "threadingIsLocked:")
  public abstract static class IsLockedPrim extends UnaryExpressionNode {
    public IsLockedPrim(final boolean ew, final SourceSection s) { super(ew, s); }

    @Specialization
    public boolean doLock(final ReentrantLock lock) {
      return lock.isLocked();
    }
  }

  @GenerateNodeFactory
  @Primitive(primitive = "threadingConditionFor:")
  public abstract static class ConditionForPrim extends UnaryExpressionNode {
    public ConditionForPrim(final boolean ew, final SourceSection s) { super(ew, s); }

    @Specialization
    public Condition doLock(final ReentrantLock lock) {
      return lock.newCondition();
    }
  }

  @GenerateNodeFactory
  @Primitive(primitive = "threadingMutexNew:")
  public abstract static class MutexNewPrim extends UnaryExpressionNode {
    public MutexNewPrim(final boolean ew, final SourceSection s) { super(ew, s); }

    // TODO: should I guard this on the mutex class?
    @Specialization
    public final ReentrantLock doSClass(final SClass clazz) {
      return new ReentrantLock();
    }
  }
}

@@ -328,30 +328,253 @@
 api.
-source.SourceSection;%0A
+frame.VirtualFrame;%0Aimport com.oracle.truffle.api.source.SourceSection;%0A%0Aimport som.interpreter.nodes.dispatch.BlockDispatchNode;%0Aimport som.interpreter.nodes.dispatch.BlockDispatchNodeGen;%0Aimport som.interpreter.nodes.nary.BinaryExpressionNode;
 %0Aimp
@@ -658,16 +658,45 @@
 mitive;%0A
+import som.vmobjects.SBlock;%0A
 import s
@@ -1015,32 +1015,45 @@
 tion%0A    public 
+static final 
 ReentrantLock do
@@ -1042,35 +1042,33 @@
 l ReentrantLock 
-doL
+l
 ock(final Reentr
@@ -1406,16 +1406,29 @@
  public 
+static final 
 Reentran
@@ -1433,19 +1433,19 @@
 antLock 
-doL
+unl
 ock(fina
@@ -1511,32 +1511,683 @@
 ock;%0A    %7D%0A  %7D%0A%0A
+  @GenerateNodeFactory%0A  @Primitive(selector = %22critical:%22, receiverType = ReentrantLock.class)%0A  public abstract static class CritialPrim extends BinaryExpressionNode %7B%0A    public CritialPrim(final boolean ew, final SourceSection s) %7B super(ew, s); %7D%0A%0A    @Child protected BlockDispatchNode dispatchBody = BlockDispatchNodeGen.create();%0A%0A    @Specialization%0A    public Object critical(final VirtualFrame frame,%0A        final ReentrantLock lock, final SBlock block) %7B%0A      LockPrim.lock(lock);%0A      try %7B%0A        return dispatchBody.executeDispatch(frame, new Object%5B%5D %7Bblock%7D);%0A      %7D finally %7B%0A        UnlockPrim.unlock(lock);%0A      %7D%0A    %7D%0A  %7D%0A%0A
   @GenerateNodeF

Add eager primitive for Mutex>>#critical: