// TestJScript.java
// This class implements com.fujitsu.iflow.testframe.TestSet interface.
// This class consists of all possible positive testcases for IFWebServices module.
// NOTE: All methods are atomic.
package com.fujitsu.iflowqa.testframe;

import java.awt.Point;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Properties;

import com.fujitsu.iflow.model.workflow.Arrow;
import com.fujitsu.iflow.model.workflow.DataItem;
import com.fujitsu.iflow.model.workflow.DataItemRef;
import com.fujitsu.iflow.model.workflow.Filter;
import com.fujitsu.iflow.model.workflow.Node;
import com.fujitsu.iflow.model.workflow.Plan;
import com.fujitsu.iflow.model.workflow.ProcessInstance;
import com.fujitsu.iflow.model.workflow.WFObjectFactory;
import com.fujitsu.iflow.model.workflow.WFObjectList;
import com.fujitsu.iflow.model.workflow.WFSession;
import com.fujitsu.iflow.model.workflow.WorkItem;
import com.fujitsu.iflow.webservices.ObjList;

public class TestJScript implements TestSet
{
    TestRecorder tr;
    Properties serverProperties;
    WFSession wfSession;

    public
    TestJScript()
        throws Exception
    {
        serverProperties = new Properties();
    }

    public
    void
    runTests(
        TestRecorder ntr) throws Exception
    {
        tr = ntr;
        serverProperties.setProperty("role",tr.getRequiredProperty("role"));

        doLogin();
        getMyPlansTest(tr);
        startProcessTest(tr);
        getUserDataTest(tr);
        handleWorkItems(tr);
        doLogout();

        tr.markPassed("Test process with JScript successfully");
    }

    /////////////////////////////////////////test plan///////////////////////////////////////////////////

    void
    getMyPlansTest(
        TestRecorder tr)
        throws Exception
    {
        debug("getMyPlansTest");
        String errorDetail = "";
        ObjList[] objs = null;
        boolean idMatched = false;

        try
        {
            long planId = createPlan();
            debug("Plan Id= "+planId);
            serverProperties.setProperty("planid",Long.toString(planId));
            setProperties(serverProperties);
        }
        catch(Exception e) {
            wrapAndThrow("getMyPlansTest", e);
            throw e;
        }
        finally {
            ;
        }
    }

    long
    createPlan()
        throws Exception
    {
        long planId = -1;
        String planName = "TestJScriptPlan1";
        try {
            Plan plan = WFObjectFactory.getPlan();
            plan.setWFSession(wfSession);
            plan.startEdit();
            plan.setName(planName);
            plan.setTitle(planName+" - Title");
            plan.setInitScript("x=getProcessAttribute('str');x=x+' init script';setProcessAttribute('str','string',x);");

            // Start Node.
            Node startNode = plan.addNode("Start", Node.TYPE_START);
            startNode.setPosition(new Point(100, 150));
            // Activity Node1.
            Node node1 = plan.addNode(planName+"-Act1",Node.TYPE_ACTIVITY);
            node1.setPosition(new Point(200, 250));
            node1.setRole(serverProperties.getProperty("role"));
            // UDAs
            DataItemRef diRef1 = plan.addDataItemRef("uda1", DataItemRef.TYPE_STRING, "default");
            DataItemRef diRef2 = plan.addDataItemRef("uda2", DataItemRef.TYPE_BOOLEAN, "true");
            DataItemRef diRef3 = plan.addDataItemRef("uda3", DataItemRef.TYPE_INTEGER, "999");
            DataItemRef diRef4 = plan.addDataItemRef("uda4", DataItemRef.TYPE_LONG, "77777777");
            DataItemRef diRef5 = plan.addDataItemRef("uda5", DataItemRef.TYPE_FLOAT, "888.8");
            DataItemRef diRef6 = plan.addDataItemRef("str", DataItemRef.TYPE_STRING, "test");
            // Exit Node.
            Node exitNode = plan.addNode("Exit", Node.TYPE_EXIT);
            exitNode.setPosition(new Point(300,350));
            // Add Arrows.
            Arrow goArrow = plan.addArrow("Go", startNode, node1);
            Arrow stopArrow = plan.addArrow("Stop", node1, exitNode);
            Plan newPlan = plan.createProcessDef();
            Thread.sleep(500);
            planId = newPlan.getId();
        }
        catch(Exception e) {
            wrapAndThrow("createPlan", e);
        }
        return planId;
    }

    //////////////////////////////////////////////process test////////////////////////////////////////

    public
    long
    createProcess(
        long planId)
        throws Exception
    {
        debug("createProcess()");
        long id = -1;
        try {
            Plan plan = WFObjectFactory.getPlan(planId, wfSession);
            ProcessInstance pi = plan.createProcessInstance();
            pi.start();
            id  = pi.getId();
        }
        catch (Exception e) {
            wrapAndThrow("createProcess() - Possibly because of Plan.createProcessInstance() ", e);
        }
        return id;
    }


    void
    startProcessTest(
        TestRecorder tr)
        throws Exception
    {
        String errorDetail = "";
        boolean started = false;
        String piState = "";
        try {
            long planId = Long.parseLong(serverProperties.getProperty("planid"));
            long processId = createProcess(planId);
            Thread.sleep(500);
            if (processId > 0)
            {
                serverProperties.setProperty("processid",Long.toString(processId));
                setProperties(serverProperties);
            } else {
                tr.markFailed("startProcessTest","Possibly an error");
                throw new Exception("startProcessTest Possibly an error");
            }
        }
        catch(Exception e) {
            wrapAndThrow("startProcessTest",e);
        }
    }


    ///////////////////////////////////////////UDA Test////////////////////////////////////////////////
    void
    getUserDataTest(
        TestRecorder tr)
        throws Exception
    {
        debug("getUserDataTest()");
        try {
            long processId = Long.parseLong(serverProperties.getProperty("processid"));
            ProcessInstance pi = WFObjectFactory.getProcessInstance(processId, wfSession);
            DataItem di = null;
            try
            {
                di = pi.getDataItem("str");
            } catch (Exception e) {
                tr.markFailed("Unable to get UDA named '"+ "str" +"'", "May be the UDA is missing");
                return;
            }

            if (di.getValue().equals("test init script")) {
                ;
            }
            else {
                tr.markFailed("Test case failed", "The Result UDA value is wrong");
            }
        } catch (Exception e) {
            wrapAndThrow("checkResultUDA() - Possibly because of ProcessInstance.getDataItem()", e);
        }

    }


    ///////////////////////////////////////////work item test///////////////////////////////////////////
    /*
     * This mehtod handles all the workitems for the give user and on the given process.
     */
    private
    void
    handleWorkItems(
        TestRecorder tr)
        throws Exception
    {
        debug("handleWorkItems()");
        try {
            long procInstId = Long.parseLong(serverProperties.getProperty("processid"));
            while (true) {
                WFObjectList wfol = WFObjectFactory.getWFObjectList(wfSession);
                wfol.addFilter(WFObjectList.LISTFIELD_PROCESSINSTANCE_ID , "=", "'"+ procInstId +"'");
                wfol.openBatchedList(Filter.MyActiveWorkItems);
                //tRecorder.markPassed("WFObjectList.openBatchedList()");
                Object[] workItemList = wfol.getNextBatch(0, 99);

                if ( (workItemList == null) || (workItemList.length == 0) ) {
                    debug("No more Wotkitems on this process for this user to make choice on.");
                    return ;
                }

                WorkItem workItem = (WorkItem) workItemList[0];
                String[] choices = workItem.getChoices();
                //tRecorder.markPassed("WorkItem.getChoices()");
                workItem.makeChoice(choices[0]); // always select the first choice.
                //tRecorder.markPassed("WorkItem.makeChoice()");
            }
        }
        catch (Exception e) {
            wrapAndThrow("handleWorkItems() - Possibly because of WorkItem.makeChoice()", e);
        }
    }

   private
    void
    doLogin()
        throws Exception
    {
        try {
            wfSession = WFObjectFactory.getWFSession();
            wfSession.initForApplication(null, tr.getProps());
            wfSession.logIn(tr.getRequiredProperty("servername")+"Flow",
                        tr.getRequiredProperty("username"),
                        tr.getRequiredProperty("password"));
         }
        catch(Exception e) {
            wrapAndThrow("doLogin", e);
        }
    }


    private
    void
    doLogout()
        throws Exception
    {
        debug("doLogout()");
        try {
            wfSession.logOut();
        }
        catch(Exception e) {
            wrapAndThrow("doLogout",e);
        }
    }

    void
    setProperties(
        Properties srvProperties)
        throws Exception
    {
    }


    // this converts an exception stack trace to a string.  Seems like
    // the wrong thing to be doing, since the TestRecorder can be made to
    // print out stack traces.  The exceptoin objects already has the
    // stack trace within it, so why convert it to a string???????
    // Consider removing this.
    String
    stringify(
        Exception e)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.getBuffer().toString();
    }

    void
    debug(
        String msg)
    {
        ;
    }

    void
    wrapAndThrow(String msg, Exception e)
        throws Exception
    {
        throw new ExceptionWrapper(msg,e);
    }

    /**
    * TestDriver is the class that knows how to run these tests.
    * So just call it with the name of this class in there.
    */
    public
    static
    void
    main(String[] args) {
        String[] newArgs = new String[1];
        newArgs[0] = "com.fujitsu.iflowqa.testframe.TestJScript";
        TestDriver.main(newArgs);
    }

}
