/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.nanos.script;

import foam.core.*;
import foam.dao.*;
import foam.nanos.logger.Logger;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class ScriptRunnerDAO
  extends ProxyDAO
{
  final public static int DEFAULT_WAIT_TIME = 2000;

  public ScriptRunnerDAO(DAO delegate) {
    super();
    setDelegate(delegate);
  }

  public FObject put_(final X x, FObject obj) {
    Script script = (Script) obj;

    if ( script.getStatus() == ScriptStatus.SCHEDULED ) {
      obj = this.runScript(x, script);
    }

    return getDelegate().put_(x, obj);
  }

  /**
   * Unmodelled subclasses will revert to their base-class when sent
   * to the client and back (to be shown in GUI). This method converts
   * the script object back to its original class.
   **/
  Script fixScriptClass(Script script) {
    Script oldScript = (Script) find(script.getId());
    return oldScript == null ?
      (Script) script.fclone() :
      (Script) oldScript.fclone().copyFrom(script);
  }

  Script runScript(final X x, Script newScript) {
    Logger log = (Logger) x.get("logger");
    Script script = fixScriptClass(newScript);
    long   estimatedTime = this.estimateWaitTime(script);
    final CountDownLatch latch = new CountDownLatch(1);

    try {
      ((Agency) x.get("threadPool")).submit(x, new ContextAgent() {
        @Override
        public void execute(X y) {
          Script s = script;
          try {
            s.setStatus(ScriptStatus.RUNNING);
            s = (Script) getDelegate().put_(x, s).fclone();
            s.runScript(x);
            s.setStatus(ScriptStatus.UNSCHEDULED);
          } catch(Throwable t) {
            s.setStatus(ScriptStatus.ERROR);
            t.printStackTrace();
            log.error("Script.run", s.getId(), t);
          }
          // save the state
          getDelegate().put_(x, s);

          latch.countDown();
        }
      }, "Run script. Script id: " + script.getId());

      latch.await(estimatedTime, TimeUnit.MILLISECONDS);
    } catch(InterruptedException e) {
      e.printStackTrace();
      log.error("Script.submit", script.getId(), e);
    }

    return script;
  }

  long estimateWaitTime(Script script) {
    return script.getLastRun() == null || DEFAULT_WAIT_TIME > script.getLastDuration() * 2 ?
      DEFAULT_WAIT_TIME :
      1 ; //  1 ms so it returns right away

  }
}

@@ -1530,37 +1530,8 @@
 ) %7B%0A
-          Script s = script;%0A
     
@@ -1547,32 +1547,37 @@
  %7B%0A            s
+cript
 .setStatus(Scrip
@@ -1609,21 +1609,8 @@
     
- s = (Script)
  get
@@ -1629,16 +1629,21 @@
 ut_(x, s
+cript
 ).fclone
@@ -1659,16 +1659,21 @@
        s
+cript
 .runScri
@@ -1684,32 +1684,37 @@
 );%0A            s
+cript
 .setStatus(Scrip
@@ -1781,16 +1781,21 @@
        s
+cript
 .setStat
@@ -1888,16 +1888,21 @@
 .run%22, s
+cript
 .getId()
@@ -1980,16 +1980,21 @@
 ut_(x, s
+cript
 );%0A%0A    

Revert changes during testing