package modules.dataflow;

import utils.*;
import simulator.*;
import java.util.*;
import modules.codegas.*;
import modules.gradient.*;
import modules.line.*;
import modules.node.*;

public class DFNOperator extends DFNode {
  Symbol op;

  public DFNOperator(double id, Symbol op, DFNPort io)
  { super(id,io); this.op=op; }

  Hashtable execute(Object callID,ActiveGradient ag) {
    Iterator i=getPorts();
    if(i.hasNext()) {
      Vector v = getPortValues(ag,callID,(DFNPort)i.next());
      Object output = doOp(v);
      if(output!=null)
        return sendToAll(ag,callID,output);
    }
    return new Hashtable();
  }
  
  public static Symbol plus = Symbol.GetSymbol("plus");
  public static Symbol minus = Symbol.GetSymbol("minus");
  public static Symbol times = Symbol.GetSymbol("times");
  public static Symbol divide = Symbol.GetSymbol("divide");
  public static Symbol greaterthan = Symbol.GetSymbol("gt");
  public static Symbol lessthan = Symbol.GetSymbol("lt");
  public static Symbol equal = Symbol.GetSymbol("equal");
  public static Symbol and = Symbol.GetSymbol("and");
  public static Symbol or = Symbol.GetSymbol("or");
  public static Symbol not = Symbol.GetSymbol("not");

  Object doOp(Vector v) {
    if(false) { return null; }
    else if(op==plus) return plus(v);
    else if(op==minus) return minus(v);
    else if(op==times) return times(v);
    else if(op==divide) return divide(v);
    else if(op==greaterthan) return greaterthan(v);
    else if(op==lessthan) return lessthan(v);
    else if(op==equal) return equal(v);
    else if(op==and) return and(v);
    else if(op==or) return or(v);
    else if(op==not) return not(v);
    else return null;
  }

  Object plus(Vector v) {
    double s = 0;
    Iterator i=v.iterator(); 
    while(i.hasNext()) { s+=((Number)i.next()).doubleValue();}
    return new Double(s);
  }

  Object minus(Vector v) {
    double s = 0;
    Iterator i=v.iterator(); 
    while(i.hasNext()) { s-=((Number)i.next()).doubleValue();}
    return new Double(s);
  }

  Object times(Vector v) {
    double s = 1;
    Iterator i=v.iterator(); 
    while(i.hasNext()) { s*=((Number)i.next()).doubleValue();}
    return new Double(s);
  }

  Object divide(Vector v) {
    double s = Double.NaN;
    Iterator i=v.iterator(); 
    while(i.hasNext()) { 
      double val = ((Number)i.next()).doubleValue(); 
      if(Double.isNaN(s)) { if(i.hasNext()) s=val; else s=1/val; }
      else s/=val; 
    }
    return new Double(s);
  }

  Object greaterthan(Vector v) {
    if(v.size()!=2) return null;
    double a = ((Number)v.get(0)).doubleValue();
    double b = ((Number)v.get(1)).doubleValue();
    return new Boolean(a>b); 
  }
  Object lessthan(Vector v) {
    if(v.size()!=2) return null;
    double a = ((Number)v.get(0)).doubleValue();
    double b = ((Number)v.get(1)).doubleValue();
    return new Boolean(a<b); 
  }
  Object equal(Vector v) {
    if(v.size()!=2) return null;
    return new Boolean(v.get(0).equals(v.get(1)));
  }
  Object and(Vector v) {
    Iterator i=v.iterator();
    while(i.hasNext()) { 
      if(!i.next().equals(Boolean.TRUE)) return Boolean.FALSE; 
    }
    return Boolean.TRUE;
  }
  Object or(Vector v) {
    Iterator i=v.iterator();
    while(i.hasNext()) { 
      if(i.next().equals(Boolean.TRUE)) return Boolean.TRUE; 
    }
    return Boolean.FALSE;
  }
  Object not(Vector v) {
    if(v.size()!=1) return null;
    return new Boolean(v.get(0).equals(Boolean.FALSE));
  }
}
