// WFAppPackagingTest.java
// This class implements com.fujitsu.iflow.testframe.TestSet interface.
// 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.WFAdminSession;
import com.fujitsu.iflow.model.workflow.WFObjectFactory;
import com.fujitsu.iflow.model.workflow.WFObjectList;
import com.fujitsu.iflow.model.workflow.WorkItem;

public class UDASearchAndSortTest implements TestSet
{
    static final String AITS_UDA_SEARCH_SORT_PLAN = "TestUDASearchAndSortPlan";
    TestRecorder tr;
    Properties serverProperties;
    WFAdminSession wfSession;

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

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

        doLogin();

        getMyPlansTest(tr);

        startProcesses(tr);

        Thread.sleep(1000);

        searchAndSortByUDAs(tr);

        deleteProcessesAndPlans(tr);

      }
      finally
      {
        doLogout();
      }
    }

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

    void getMyPlansTest(TestRecorder tr) throws Exception
    {
        debug("getMyPlansTest");
        String errorDetail = "";
        boolean idMatched = false;

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

    long createPlan() throws Exception
    {
        long planId = -1;
        String planName = AITS_UDA_SEARCH_SORT_PLAN;
        try
        {
            Plan plan = WFObjectFactory.getPlan();
            plan.setWFSession(wfSession);
            plan.startEdit();
            plan.setName(planName);
            plan.setTitle(planName+" - Title");
            // 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("__usedWithLists", DataItemRef.TYPE_STRING, "uda1,uda3,uda4,uda5");
            // 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)
        {
            logError("createPlan", e);
        }
        return planId;
    }

    //////////////////////////////////////////////make choices////////////////////////////////////////

    /*
     * This mehtod makes choices
     */
    void startProcesses(TestRecorder tr) throws Exception
    {
        String errorDetail = "";
        boolean started = false;
        try
        {
            long planId = Long.parseLong(serverProperties.getProperty("planid"));
            if(planId > 0)
            {
              Plan plan = WFObjectFactory.getPlan(planId, wfSession);
              ProcessInstance pi = plan.createProcessInstance();
              pi.start();
              Thread.sleep(1000);
              pi.startEdit();
              Properties props = new Properties();
              props.put("uda1", "test");
              props.put("uda3", "1900");
              props.put("uda4", "75");
              pi.setDataItemValues(props);
              pi.commitEdit();

              plan = WFObjectFactory.getPlan(planId, wfSession);
              pi = plan.createProcessInstance();
              pi.start();
              Thread.sleep(1000);
              pi.startEdit();
              props = new Properties();
              props.put("uda3", "3100");
              props.put("uda4", "175");
              pi.setDataItemValues(props);
              pi.commitEdit();

              plan = WFObjectFactory.getPlan(planId, wfSession);
              pi = plan.createProcessInstance();
              pi.start();
              Thread.sleep(1000);
              pi.startEdit();
              props = new Properties();
              props.put("uda3", "99");
              props.put("uda4", "1000");
              pi.setDataItemValues(props);
              pi.commitEdit();

              plan = WFObjectFactory.getPlan(planId, wfSession);
              pi = plan.createProcessInstance();
              pi.start();
              Thread.sleep(1000);
              pi.startEdit();
              props = new Properties();
              props.put("uda3", "99");
              props.put("uda4", "88");
              pi.setDataItemValues(props);
              pi.commitEdit();

            }
            else
            {
                tr.markFailed("startProcesses","Possibly an error");
                throw new Exception("startProcesses Possibly an error");
            }
        }
        catch(Exception e)
        {
            logError("makeChoices",e);
        }
    }


    ///////////////////////////////////////////Search and Sort By UDAs////////////////////////////////////////////////
    /*
     * This mehtod searches and sorts by UDAs
     */

    void searchAndSortByUDAs(TestRecorder tr) throws Exception
    {
        String errorDetail = "";
        boolean started = false;
        try
        {
            WFObjectList wfObjectList = WFObjectFactory.getWFObjectList(wfSession);
            wfObjectList.addFilter(WFObjectList.LISTFIELD_WORKITEM_ASSIGNEE , "=", "'"+ tr.getRequiredProperty("username") + "'");
            wfObjectList.addFilter("uda1",DataItemRef.TYPE_STRING, WFObjectList.SQLOP_NOTLIKE, "'test'");
            wfObjectList.addFilter("uda5",DataItemRef.TYPE_FLOAT, WFObjectList.SQLOP_GREATERTHAN, "'70.0'");
            wfObjectList.addSortOrder("uda3",DataItemRef.TYPE_INTEGER,WFObjectList.SORTORDER_ASCENDING);
            wfObjectList.addSortOrder("uda4",DataItemRef.TYPE_STRING,WFObjectList.SORTORDER_DESCENDING);
            wfObjectList.addSortOrder(WFObjectList.LISTFIELD_WORKITEM_STATE,WFObjectList.SORTORDER_DESCENDING);
            wfObjectList.openBatchedList(Filter.AllWorkItems);
            Object[] wiList = wfObjectList.getNextBatch(3);
            if(wiList != null && wiList.length == 3)
            {
               for(int i=0; i < 3; i++)
               {
                  DataItem[] dataitems = ((WorkItem)wiList[i]).getWorklistDataItems();
                  String uda1 = "default";
                  String uda3 = null;
                  String uda4 = null;
                  if(i == 0)
                  {
                    uda3 = "99";
                    uda4 = "1000";
                  }
                  else if (i == 1)
                  {
                    uda3 = "99";
                    uda4 = "88";
                  }
                  else if (i == 2)
                  {
                    uda3 = "3100";
                    uda4 = "175";
                  }
                  for(int k=0; k<dataitems.length; k++)
                  {
                    DataItem dataitem = dataitems[k];
                    if(dataitem.getName().equals("uda1") == true && dataitem.getValue().equals(uda1) != true)
                       logError("searchAndSortByUDAs",new Exception("Wrong work item is returned"));
                    else if(dataitem.getName().equals("uda3") == true && dataitem.getValue().equals(uda3) != true)
                       logError("searchAndSortByUDAs",new Exception("Wrong work item is returned"));
                    else if(dataitem.getName().equals("uda4") == true && dataitem.getValue().equals(uda4) != true)
                       logError("searchAndSortByUDAs",new Exception("Wrong work item is returned"));
                  }
               }

               tr.markPassed("Test UDA searching and sorting successfully");
            }
            else
            {
               logError("searchAndSortByUDAs",new Exception("Unable to retrieve the required work items"));
            }
        }
        catch(Exception e)
        {
            logError("searchAndSortByUDAs",e);
        }
    }


    ///////////////////////////////////////////delete uda search and sort plans///////////////////////////////////////////
    /*
     * This mehtod deletes uda search and sort plans
     */
    private void deleteProcessesAndPlans(TestRecorder tr) throws Exception
    {
        try
        {
            WFObjectList wfObjectList = WFObjectFactory.getWFObjectList(wfSession);
            wfObjectList.addFilter(WFObjectList.LISTFIELD_PROCESSINSTANCE_NAME,"=","'" + AITS_UDA_SEARCH_SORT_PLAN + "'");
            wfObjectList.openBatchedList(Filter.AllProcesses);
            Object[] wiList = wfObjectList.getNextBatch(10);
            while(wiList != null && wiList.length > 0)
            {
                for(int i = 0; i < wiList.length; i++)
                {
                    ProcessInstance pi = (ProcessInstance) wiList[i];
                    wfSession.deleteProcessInstance(pi.getId());
                }
                wiList = wfObjectList.getNextBatch(10);
            }

            wfObjectList = WFObjectFactory.getWFObjectList(wfSession);
            wfObjectList.addFilter(WFObjectList.LISTFIELD_PLAN_NAME,"=","'" + AITS_UDA_SEARCH_SORT_PLAN + "'");
            wfObjectList.openBatchedList(Filter.AllPlans);
            wiList = wfObjectList.getNextBatch(10);
            while(wiList != null && wiList.length > 0)
            {
                for(int i = 0; i < wiList.length; i++)
                {
                    Plan pl = (Plan) wiList[i];
                    wfSession.deletePlan(pl.getId());
                }
                wiList = wfObjectList.getNextBatch(10);
            }
        }
        catch(Exception e)
        {
            logError("deleteProcessesAndPlans()", e);
        }
    }

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


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

    // 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 logError(String msg, Exception e) throws Exception
    {
        tr.markFailed(msg, "Exception Caught");
        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.UDASearchAndSortTest";
        TestDriver.main(newArgs);
    }

}
