package exm.stc.ic.refcount;

import java.util.Map.Entry;

import exm.stc.common.Settings;
import exm.stc.common.exceptions.STCRuntimeError;
import exm.stc.common.lang.RefCounting.RefCountType;
import exm.stc.common.lang.Var;
import exm.stc.ic.aliases.AliasKey;
import exm.stc.ic.tree.ICContinuations.Continuation;
import exm.stc.ic.tree.ICContinuations.ContinuationType;
import exm.stc.ic.tree.ICTree.Block;
import exm.stc.ic.tree.TurbineOp.RefCountOp.RCDir;

public class RCUtil {

  static boolean isAsyncForeachLoop(Continuation cont) {
    return cont.isAsync() && isForeachLoop(cont);
  }

  static boolean isForeachLoop(Continuation cont) {
    return (cont.getType() == ContinuationType.FOREACH_LOOP ||
            cont.getType() == ContinuationType.RANGE_LOOP);
  }

  /**
   *
   * @param cont
   * @param block
   * @param var
   *          a var that is in scope within block
   * @return true if var is accessible outside continuation
   */
  static boolean definedOutsideCont(Continuation cont, Block block, Var var) {
    assert (block.getParentCont() == cont);
    return !block.variables().contains(var)
        && !cont.constructDefinedVars().contains(var);
  }

  static boolean mergeEnabled() {
    return Settings.getBooleanUnchecked(Settings.OPT_MERGE_REFCOUNTS);
  }

  static boolean cancelEnabled() {
    return Settings.getBooleanUnchecked(Settings.OPT_CANCEL_REFCOUNTS);
  }

  static boolean piggybackEnabled() {
    return Settings.getBooleanUnchecked(Settings.OPT_PIGGYBACK_REFCOUNTS);
  }

  static boolean batchEnabled() {
    return Settings.getBooleanUnchecked(Settings.OPT_BATCH_REFCOUNTS);
  }

  static boolean hoistEnabled() {
    return Settings.getBooleanUnchecked(Settings.OPT_HOIST_REFCOUNTS);
  }

  /**
   * Check reference counts are all set to zero
   * @param block
   * @param increments
   * @param rcType
   * @param noIncrements if true, check that they are <= 0
   * @param noDecrements if true, check that they are >= 0
   */
  static void checkRCZero(Block block, RCTracker increments,
                         RefCountType rcType,
                         boolean noIncrements, boolean noDecrements) {
    // Check that all refcounts are zero
    if (noIncrements) {
      for (Entry<AliasKey, Long> e : increments.rcIter(rcType, RCDir.INCR)) {
        if (e.getValue() != 0) {
          throw new STCRuntimeError("Refcount " + rcType  + " incr not 0 "
                + "after pass " + e.toString() + " in block " + block);
        }
      }
    }
    if (noDecrements) {
      for (Entry<AliasKey, Long> e : increments.rcIter(rcType, RCDir.DECR)) {
        if (e.getValue() != 0) {
          throw new STCRuntimeError("Refcount " + rcType  + " decr not 0 "
                + "after pass " + e.toString() + " in block " + block);
        }
      }
    }
  }
}

@@ -88,58 +88,8 @@
 gs;%0A
-import exm.stc.common.exceptions.STCRuntimeError;%0A
 impo
@@ -2243,35 +2243,38 @@
 NCR)) %7B%0A        
-if 
+assert
 (e.getValue() !=
@@ -2275,52 +2275,16 @@
 e() 
-!
+=
 = 0) 
-%7B%0A          throw new STCRuntimeError(
+: 
 %22Ref
@@ -2383,36 +2383,25 @@
 ck %22 + block
-);%0A        %7D
+;
 %0A      %7D%0A   
@@ -2513,18 +2513,22 @@
         
-if
+assert
  (e.getV
@@ -2538,52 +2538,16 @@
 e() 
-!
+=
 = 0) 
-%7B%0A          throw new STCRuntimeError(
+: 
 %22Ref
@@ -2573,32 +2573,38 @@
  %22 decr not 0 %22%0A
+      
                 
@@ -2660,20 +2660,9 @@
 lock
-);%0A        %7D
+;
 %0A   

simplify checks somewhat