package com.fujitsu.iflowqa.testframe;

import java.util.Random;

import com.fujitsu.iflow.model.workflow.ArrowInstance;
import com.fujitsu.iflow.model.workflow.ConditionSpec;
import com.fujitsu.iflow.model.workflow.DataItem;
import com.fujitsu.iflow.model.workflow.DataItemMappingElement;
import com.fujitsu.iflow.model.workflow.Filter;
import com.fujitsu.iflow.model.workflow.FormRef;
import com.fujitsu.iflow.model.workflow.JavaAction;
import com.fujitsu.iflow.model.workflow.JavaActionSet;
import com.fujitsu.iflow.model.workflow.Node;
import com.fujitsu.iflow.model.workflow.NodeInstance;
import com.fujitsu.iflow.model.workflow.Plan;
import com.fujitsu.iflow.model.workflow.ProcessInstance;
import com.fujitsu.iflow.model.workflow.TimerDef;
import com.fujitsu.iflow.model.workflow.VotingRule;
import com.fujitsu.iflow.model.workflow.WFObjectFactory;
import com.fujitsu.iflow.model.workflow.WorkItem;


public class UTF8Test extends BPMTestBase implements TestSet
{
    private String planName = null;
    private String piName = null;
    private String userName = null;
    private long aiId = -1;
    private Plan parentPlan = null;
    private Plan childPlan = null;
    private String uda1ExpectedName = "\u6210\u679c\u767c\u8868";
    private String uda1ExpectedValue = "\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";
    private NodeInstance subPrNode = null;
    
    /*
     * Zero argument constructor.
     */
     public UTF8Test()
    {
    }

    /*
     * This method runs the rest.
     */
    public void runTests(TestRecorder recorder) throws Exception
    {
        init(recorder);

        String parentXPDLFileName = recorder.getTestDir()+"utf8testV1.xpdl";
        String childXPDLFileName = recorder.getTestDir()+"utf8test_childV1.xpdl";
        long piId = -1;

        try {
            login();
            String[] commandLineArgs = tr.getCommandLineArgs();
            if(commandLineArgs.length >= 3) {
               parentXPDLFileName = commandLineArgs[1];
               childXPDLFileName = commandLineArgs[2];
            }

            //debug("UTF8 Test started for " +  parentXPDLFileName);
            childPlan = createPlanFromXPDL(childXPDLFileName);
            parentPlan = createPlanFromXPDL(parentXPDLFileName);

            ProcessInstance pi = createProcess(parentPlan);
            piName = pi.getName();
            debug("Process created: "+getLit(piName));

            if(!validateUTFStrings(pi, parentPlan)){
                this.markFailed("UTF8 Test", "could not validate the strings in validateUTFStrings");
                return;
            }
            else if(handlWorkItem(pi)) {
                this.markPassed("UTF8 Test");
            }
            else {
                this.markFailed("UTF8 Test", "Handle workitem failed");
            }

        } catch (Exception e) {
            throw new ExceptionWrapper("Exception caught in main test level", e);
        }
        finally
        {
            logOutWithoutException();
        }
    }

    /*
     * This mehtod handles all the workitems for the give user and on the given process.
     */
    public
    boolean
    validateUTFStrings(
        ProcessInstance pi,
        Plan parentPlan)
        throws Exception
    {
        //ASSIGNING EXPECTED VALUES
        String planName = "\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";
        String piName = "\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";

        String[] expUDAName = new String[3];
        String[] expUDAValues = new String[3];
        expUDAName[0] = "\u6210\u679c\u767c\u8868";
        expUDAName[1] = "a.\u958B\u653E\u6587\u5B78\u4FEE\u6539\u898F\u683C";
        expUDAName[2] = "\u958B\u653E\u6587\u5B78\u4FEE\u6539\u898F\u683C";
        expUDAValues[0] = "\u958B\u653E\u6587\u5B78\u4FEE\u6539\u898F\u683C";
        expUDAValues[1] = "0";
        expUDAValues[2] = "0";

        String ai1Name = "\u4e0b\u8f09\u5730\u5740";
        String javaActionName = "\u4e0b\u8f09\u5730\u5740";
        String inputUDA1 = "\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";
        String inputUDA2 = "Hello - \u4e0b\u8f09\u5730\u5740";
        String timerLabel = "\u4e0b\u8f09\u5730\u5740";
        String timerDescr = "\u4e0b\u8f09\u5730\u5740 - akljkldjklajkldf";
        String formName1 = "\u4e0b\u8f09\u5730\u5740";
        String formName2 = "\u958b\u653e\u6587\u5b78";
        String formPath2 ="What is left here ? \u958b\u653e\u6587\u5b78";

        String condUdaNmae ="\u6210\u679c\u767c\u8868";
        String condArrLabel="\u6210\u679c\u767c\u8868";

        String votingActName = "\u4e0b\u8f09\u5730\u5740";
        String vtRuleArrowlevel = "\u6210\u679c\u767c\u8868" ;

        String sourceDataSetElementName="\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";

        String andNodeName = "\u6210\u679c\u767c\u8868";
        String  chainSourceDataSetElementName="\u958b\u653e\u6587\u5b78\u4fee\u6539\u898f\u683c";

        String rulesJaSet = "\u6210\u679c\u767c\u8868";

        testAndReport("Test UTF-8 Plan_Name", parentPlan.getName(), planName);
        testAndReport("Test UTF-8 Process_Name", pi.getName(), piName);

        waitForWorkItem(ai1Name, wfSession.getUserName(), Filter.MyActiveWorkItems, null, pi.getId(), tr);

        //Verify UDA Names
        DataItem[] dit = pi.getDataItems();
        boolean isdataItemValuePassed = false;
        String gotUdaValue = null;
        if(dit == null)  {
            throw new Exception("Test UTF-8 UDA_Name failed because NO UDA AVAILABLE");
        }

        int count = 0;
        String gotNames = "";
        boolean[] found = new boolean[3];
        for(int i=0; i<dit.length; i++) {
            String thisUDAName = dit[i].getName();
            for (int j=0; j<3; j++) {
                if (thisUDAName.equals(expUDAName[j])) {
                    found[j] = true;
                    testAndReport("Test UTF-8 UDA Name "+j, thisUDAName, expUDAName[j]);
                    testAndReport("Test UTF-8 UDA Value "+j, dit[i].getValue(), expUDAValues[j]);
                }
            }
        }

        for (int j=0; j<3; j++) {
            if (!found[j]) {
                markFailed("Test UTF-8 UDA Name "+j, "Never found uda named "+getLit(expUDAName[j]));
                markFailed("Test UTF-8 UDA Value "+j, "Never found the uda with this name");
            }
        }

        //Activity + Form + JavaAction
        NodeInstance[]  nis =  pi.getNodeInstances();

        NodeInstance actNode = null;
        NodeInstance actNode2 = null;
        NodeInstance actNode3 = null;
        NodeInstance votingNode = null;
        NodeInstance condNode = null;
        NodeInstance chainPrNode = null;
        NodeInstance andNode = null;

        if(nis == null){
            throw new Exception("Test UTF-8 Activity failed -- NO Activity AVAILABLE");
        }
        for(int i=0; i < nis.length; i++){
            if(nis[i].getType() == Node.TYPE_ACTIVITY){
                if(nis[i].getName().equals("Act_2"))
                    actNode2 = nis[i];
                else if(nis[i].getName().equals("Act_3"))
                    actNode3 = nis[i];
                else
                    actNode = nis[i];
            }
            else if(nis[i].getType() == Node.TYPE_VOTING_ACTIVITY)
                votingNode = nis[i];
            else if (nis[i].getType() == Node.TYPE_CONDITION)
                condNode = nis[i];
            else if (nis[i].getType() == Node.TYPE_SUB_PROCESS)
                subPrNode = nis[i];
            else if (nis[i].getType() == Node.TYPE_CHAINED_PROCESS)
                chainPrNode = nis[i];
            else if (nis[i].getType() == Node.TYPE_AND)
                andNode = nis[i];
        }

        testAndReport("Test UTF-8 Regular_Activity_Name", actNode.getName(), ai1Name);

        aiId = actNode.getNodeInstanceId();
        try {
            boolean form1pass = false;
            boolean form2pass = false;
            FormRef[] forms = actNode.getForms();
            if(forms != null){
                for(int i=0; i< forms.length; i++)
                {
                    FormRef aForm = forms[i];
                    if(aForm.getName().equals(formName1) )
                    {
                        form1pass = true;
                        markPassed("Test UTF-8 Form1_Name");
                        testAndReport("Test UTF-8 Form2_Path", aForm.getPath(),
                            "C:/iflow_attachments/abc.xml");
                    }
                    else if(aForm.getName().equals(formName2))
                    {
                        form2pass = true;
                        markPassed("Test UTF-8 Form2_Name");
                        testAndReport("Test UTF-8 Form2_Path", aForm.getPath(),
                            "What is left here ? \u958B\u653E\u6587\u5B78");
                    }
                }
            }
            if(!form1pass) {
                 markFailed("Test UTF-8 Form1_Name",
                        "Never found form named "+ getLit(formName1));
                 markFailed("Test UTF-8 Form1_Path",
                        "Never found form named "+ getLit(formName1));
            }
            if(!form2pass) {
                 markFailed("Test UTF-8 Form1_Name",
                        "Never found form named "+ getLit(formName2));
                 markFailed("Test UTF-8 Form2_Path",
                        "Never found form named "+ getLit(formName2));
            }
        }
        catch(Exception e)
        {
             markFailed("Test UTF-8 Form failed", " Got Exception: " + e);
        }


        String gotJAname = null;
        try {
            boolean isJaNamePassed = false;
            JavaActionSet jas = actNode.getPrologueJavaActionSet();
            JavaAction[] ja = jas.getJavaActions();
            if(ja != null)
            {
                for(int i=0; i<ja.length; i++)
                {
                    if(ja[i].getActionName().equals(javaActionName)){
                        markPassed("Test UTF-8 JavaAction_Name");
                        isJaNamePassed = true;
                    }
                }
            }
            if(!isJaNamePassed) {
                markFailed("Test UTF-8 JavaAction_Name",
                    "Never found java action named " + getLit(javaActionName));
            }
       }
       catch(Exception jae) {
           throw new ExceptionWrapper("Test UTF-8 JavaAction failed ", jae);
       }


       boolean isTimerNamePassed = false;
       try {
            TimerDef[] td = actNode.getTimers();
            if( td != null)
            {
                for(int i=0; i<td.length; i++)
                {
                    if(td[i].getName().equals(timerLabel)){
                        isTimerNamePassed = true;
                        markPassed("Test UTF-8 TimeDef_Name");
                        testAndReport("Test UTF-8 Timer_Desc", td[i].getDescription(), timerDescr);
                        break;
                    }
                }
            }
            if(!isTimerNamePassed) {
                markFailed("Test UTF-8 Timer_Name",
                    "Never found timer named  " + getLit(timerLabel));
                markFailed("Test UTF-8 Timer_Desc",
                    "Never found timer named  " + getLit(timerLabel));
            }
       }
       catch(Exception te) {
           throw new ExceptionWrapper("Test UTF-8 TimerDef failed ", te);
       }


        testAndReport("Test UTF-8 And_Activity_Name",
                      andNode.getName(), andNodeName);

        testAndReport("Test UTF-8 Voting_Activity_Name",
                      votingNode.getName(), votingActName);

        //Verify Voting Activity
        try {
            VotingRule vr = votingNode.getVotingRule(vtRuleArrowlevel);
            if(vr == null) {
                markFailed("Test UTF-8 Voting_Activity_RulesArrow_Name",
                           "Voting rule is missing (null)");
            }
            else {
                testAndReport("Test UTF-8 Voting_Activity_RulesArrow_Name",
                              vr.getArrowName(), vtRuleArrowlevel);
            }
        }
        catch(Exception e) {
            throw new Exception("Test UTF-8 Voting_Activity_RulesArrow_Name", e);
        }

        //Verify Condition  Activity
        try {
            ConditionSpec conSp = condNode.getConditionSpec();
            testAndReport("Test UTF-8 Condition_Activity_Attribute_Name",
                conSp.getConditionAttribute(), condUdaNmae);
        }
        catch(Exception e) {
            throw new ExceptionWrapper("Test UTF-8 Condition_Activity_Attribute_Name", e);
        }

        ArrowInstance[] arw = condNode.getOutgoingArrowInstances();
        boolean arrowNamePassed = false;
        if(arw == null) {
            throw new Exception("Test UTF-8 Condition_Activity_outgoingArrow_Name failed - NO OUTGOING ARROWS");
        }
        for(int i=0; i<arw.length; i++)
        {
            if(arw[i].getName().equals(condArrLabel)) {
                arrowNamePassed = true;
                break;
            }
        }

        if(arrowNamePassed)
            markPassed("Test UTF-8 Condition_Activity_outgoingArrow_Name");
        else
            markFailed("Test UTF-8 Condition_Activity_outgoingArrow_Name",
                "Never found arrow named " + getLit(condArrLabel));

        try {
            DataItemMappingElement[] dsm = subPrNode.getDataMappingElements();
            boolean subpDataItemNamePasssed = false;
            if(dsm != null && dsm.length > 0)
            {
                for(int i=0; i<dsm.length; i++) {
                    DataItemMappingElement ds = dsm[i];
                    if(ds.getParentDataItemName().equals(sourceDataSetElementName)){
                        subpDataItemNamePasssed = true;
                        break;
                    }
                }
            }

            if(subpDataItemNamePasssed)
                markPassed("Test UTF-8 SubProcess_sourceDataSetElement_Name");
            else
                markFailed("Test UTF-8 SubProcess_sourceDataSetElement_Name",
                        "Never found  "+ getLit(sourceDataSetElementName));


        }
        catch(Exception e)
        {
            throw new ExceptionWrapper("Test UTF-8 SubProcess_sourceDataSetElement_Name", e);
        }


        try {
            DataItemMappingElement[] dsm = chainPrNode.getDataMappingElements();
            boolean subpDataItemNamePasssed = false;
            if(dsm == null) {
                throw new Exception("no Data Mapping Elements");
            }
            for(int i=0; i<dsm.length; i++) {
                DataItemMappingElement ds = dsm[i];
                if(ds.getParentDataItemName().equals(chainSourceDataSetElementName)){
                    subpDataItemNamePasssed = true;
                    break;
                }
            }

            if(subpDataItemNamePasssed)
                markPassed("Test UTF-8 ChainedProcess_sourceDataSetElement_Name");
            else
                markFailed("Test UTF-8 ChainedProcess_sourceDataSetElement_Name",
                       "Never found chained node with name "
                        + getLit(sourceDataSetElementName));

        }
        catch(Exception e)
        {
            throw new ExceptionWrapper("Test UTF-8 ChainedProcess_sourceDataSetElement_Name fatal error", e);
        }


       //Verify Rules Name
       boolean ruleNamePassed = false;
       try {
            JavaActionSet jas = actNode2.getRoleJavaActionSet();
            JavaAction[] ja = jas.getJavaActions();
            if(ja == null) {
                throw new Exception("Test UTF-8 Rules_Name failed -- NO JavaAction AVAILABLE");
            }
            for(int i=0; i<ja.length; i++)
            {
                if(ja[i].getActionName().equals(rulesJaSet)){
                     ruleNamePassed = true;
                     break;
                }
            }
            if(ruleNamePassed)
                markPassed("Test UTF-8 Rules_Name");
            else
                markFailed("Test UTF-8 Rules_Name",
                           "Never found java action with name " + getLit(rulesJaSet));
        }
        catch(Exception jae) {
            throw new ExceptionWrapper("Test UTF-8 Rules_Name", jae);
        }

        return true;

    }


    private boolean handlWorkItem(ProcessInstance pi)throws Exception
    {
        //Handle Parent WorkItem
        int count = 0;
        int noWorkListGuard = 300;
        Random randNo = new Random();
        while(true)
        {
            try {
                Object[] workItemList = getProcessWorkitems(Filter.MyActiveWorkItems, null, pi.getId());
                //We know that first workitem is already available
                if (workItemList.length > 0) {
                    markPassed("workItemList.length  : " + workItemList.length);
                }
                else {
                    markFailed("handlWorkItem", "Workitem for first node not found");
                }

                WorkItem workItem = (WorkItem) workItemList[randNo.nextInt(workItemList.length )];
                //Verify UDA update by script. Get The ProcessInstance again incase it is not refreshed
                long piId = pi.getId();
                pi = WFObjectFactory.getProcessInstance(piId, wfSession);
                String gotUda1FinalValue = pi.getDataItem(uda1ExpectedName).getValue();
                testAndReport("Test UTF-8 UDA_VALUE_ASSIGNMENT_JavaScript",
                         gotUda1FinalValue, uda1ExpectedValue);

                String[] choices = workItem.getChoices();
                workItem.makeChoice(choices[randNo.nextInt(choices.length)]);
                break;
            }
            catch(Exception e)
            {
                e.printStackTrace();
                throw new ExceptionWrapper("handleWorkItems() - Possibly because of WorkItem.makeChoice()", e);
            }

        }

        // Wait till sub process is created.
        String msg = "SafeSleeping till sub process is created";
        debug(msg);                                              
        SafeSleep sleeper = new SafeSleep(msg);
        long subProcId = subPrNode.getSubProcessId();
        while(subProcId == -1) {
            sleeper.nap();
            subProcId = subPrNode.getSubProcessId();
        }
        WorkItem subProcWi = waitForWorkItem("utf8test_child", wfSession.getUserName(), Filter.MyActiveWorkItems, null, subProcId, tr);
        String[] choices = subProcWi.getChoices();
        subProcWi.makeChoice(choices[0]);
        markPassed("Choice made on sub process workitem");

        //Wait For ProcessInstance to Close
        String msg2 = "SafeSleeping till parent process id " + pi.getId() + " completes";
        debug(msg2);                                              
        SafeSleep sleeper2 = new SafeSleep(msg2);
        while(pi.getState() != ProcessInstance.STATE_CLOSED) {
            sleeper2.nap();
        }
        markPassed("Parent process has completed.");
        
        //wfSession.deletePlan(this.parentPlan.getId());
        //wfSession.deletePlan(this.childPlan.getId());
        markPassed("Parent and child plans deleted.");

        return true;

    }


    public
    void
    debug(String msg)
    {
        tr.log(msg);
    }



    public
    void
    markFailed(
        String message1,
        String message2)
    {
        tr.log("Process " + getLit(this.piName));
        tr.markFailed(message1, message2);
    }

    public
    void
    markPassed(
        String message1)
    {
        //message1 = "Process (" + this.piName  + "): " + message1;
        tr.markPassed(message1);
    }

}
