/* Copyright (c) 2008 Charles Rich and Worcester Polytechnic Institute.
 * All Rights Reserved.  Use is subject to license terms.  See the file
 * "license.terms" for information on usage and redistribution of this
 * file and for a DISCLAIMER OF ALL WARRANTIES.
 */
package edu.wpi.cetask;

import javax.script.*;

/**
 * Base class for instances of classes.
 */
abstract class Instance {
   
   private final TaskModel.Member type;
   
   public TaskModel.Member getType () { return type; }
   
   protected final TaskEngine engine; 
   
   Instance (TaskModel.Member type, TaskEngine engine) { 
      if ( type == null ) 
         throw new IllegalArgumentException("Type of instance cannot be null");
      this.type = type;
      this.engine = engine;
      // $id and $model are future extensions to standard
      bindings.put("$id", type.getId());
      bindings.put("$model", type.getNamespace());
   }
   
   // store slot values in JavaScript form
   protected final Bindings bindings = new SimpleBindings();
   
   public Object eval (String expression, String where) {
      return eval(expression, bindings, where);
   }
  
   protected Object eval (String script, Bindings extra, String where) {
      return engine.eval(script, extra, where); 
   }
   
   public void eval (String expression, Object value, String where) {
      try {
         bindings.put("$$value", value); // convert to JavaScript value
         eval(expression, bindings, where);
      } finally { bindings.remove("$$value"); }
   }

   protected Boolean evalCondition (String expression, String where) { 
      return (Boolean) eval(expression, where);
   }
   
   protected Boolean evalCondition (String expression, Bindings extra, String where) { 
      return (Boolean) eval(expression, extra, where);
   }
   
   protected Boolean evalCondition (String condition, CompiledScript compiled, String where) {
      return TaskEngine.COMPILABLE ? evalCondition(compiled, bindings, where) :
         evalCondition(condition, bindings, where);
   }
   
   protected Boolean evalCondition (CompiledScript compiled, Bindings extra, 
                                    String where) {
      if ( compiled == null ) return null;
      try { 
         extra.put(ScriptEngine.FILENAME, where);
         return (Boolean) compiled.eval(extra);
      } 
      catch (ScriptException e) { throw new RuntimeException(e); }
      finally { extra.remove(ScriptEngine.FILENAME); } 
   }

   @Override
   public String toString () { 
      return TaskEngine.VERBOSE ? toStringVerbose() : getType().toString();
   }
   
   protected String toStringVerbose () { 
      return TaskEngine.DEBUG ? 
         getType()+"@"+Integer.toHexString(System.identityHashCode(this))
         : getType().toString();
   }

}
