package org.jcon.df.edit.screen.autotest;

import org.jcon.ba.system.BeanActionClose;
import org.jcon.ba.system.BeanActionPause;
import org.jcon.ba.system.BeanActionStart;
import org.jcon.param.Param;
import org.jcon.param.ParamDrivenInfo;
import org.jcon.param.ParamDrivenSupply;
import org.jcon.param.ParamSupplier;
import java.util.Vector;
import javax.swing.SwingUtilities;

/**
* This class is a single reusable test. It is defined by
* its Param, which must contain a series of commands to
* do the test. Each command is considered a step. The
* commands must match what ScreenCommandos expect.
* <p>
* Currently start() runs to completion with no pause() or
* close() ability. 
* <p>
* Due to apparent Swing bugs in paintImmediately(), a
* workaround has complicated this class. Threads are used
* to simulate another thread causing each command.
*
* @author Jack Harich
*/
public class Test implements Runnable, BeanActionStart,
    BeanActionPause, BeanActionClose, ParamDrivenSupply {

//---------- Private Fields ------------------------------
// Properties
private ParamSupplier paramSupplier;
private Param         myParam;
private String        testName;
private TestContext   testContext;
private int           stepPause = 500;
private boolean       isRepeated;
// Internal
//private boolean     isStarted;

//----------- Runnable Implementation --------------------
public void run() {
    getParam(); // Equivalent of check init
    Vector commands = myParam.getParamVector("Commands");
    if (commands.isEmpty()) {
        print(".start() - 'Commands' not found in Param or it is empty.");
        return;
    }        
    // Do commands in sequence with isRepeated feature
    boolean running = true;
    while (running) {
        for (int i = 0; i < commands.size(); i++) {
            Param cmdParam = (Param)commands.elementAt(i);
            String cmdName = cmdParam.getString("CommandName").intern();
            //print(".run() - Before command " + cmdName);
            // Do in Step 
            Step step = new Step();
            step.cmdParam = cmdParam;
            step.start(); 
            // Possibly wait();
        }
        running = isRepeated;
    }
}
//----------- BeanActionStart Implementation -------------
public void start() {
    new Thread(this).start();
}
//----------- BeanActionPause Implementation --------------
public void pause() {
    print(".pause() - Not implemented");
}
public void resume() {
    print(".resume() - Not implemented");
}
//---------- BeanActionClose Implementation --------------
public String canClose() {
    return null; // Yes
}
public void close() {
    // Do nothing
}
//---------- ParamDrivenSupply Implementation ------------
public void setParam(Param param) {
    myParam = param;
}
public Param getParam() {
    if (myParam == null) {
        paramSupplier.supplyParam(this);
        paramSupplier = null;
    }
    return myParam;
}
// Simple, will not work for started state ******
public boolean applyNewParam(Param newParam) {
    myParam = newParam;
    return true; // Successful
}
public ParamDrivenInfo getParamDrivenInfo() {
    return null;
}
public void setParamSupplier(ParamSupplier paramSupplier) {
    this.paramSupplier = paramSupplier;
}
//---------- Properties ----------------------------------
//----- testName
public void setTestName(String testName) {
    this.testName = testName;
}
public String getTestName() {
    return testName;
}
//----- stepPause
/**
* Sets the pause in milliseconds between steps. The default
* is 500, which allows a test to be easily observed in
* slow motion. We will probably change the default to zero
* after initial development.
*/
public void setStepPause(int stepPause) {
    this.stepPause = stepPause;
}
public int getStepPause() {
    return stepPause;
}
//----- isRepeat
/**
* Sets whether the test is automatically repeated over and
* over. The default is false.
*/
public void setRepeated(boolean isRepeated) {
    this.isRepeated = isRepeated;
}
public boolean isRepeated() {
    return isRepeated;
}
//----- Other
public void setTestContext(TestContext testContext) {
    this.testContext = testContext;
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("Test" + text);
}
//========== Inner Classes ===============================
private class Step implements Runnable {
    Param cmdParam;
    
    public void run() {
        //Test.this.print(".Runner.run() - Entered");
        testContext.doCommand(cmdParam);
    }
    public void start() {
        try {
            SwingUtilities.invokeAndWait(this);
            Thread.currentThread().sleep(stepPause);
            
            // ExtraPauseTime feature
            if (cmdParam.hasProperty("ExtraPauseTime")) {
                long extraPause = cmdParam.getLong("ExtraPauseTime");
                Thread.currentThread().sleep(extraPause);
            }
            // Possibly Test.this.notify();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
    
} // End inner class

} // End outer class