package com.fujitsu.iflowqa.testframe;

// iflow classes.
import com.fujitsu.iflow.model.workflow.DataItem;
import com.fujitsu.iflow.model.workflow.Filter;
import com.fujitsu.iflow.model.workflow.Plan;
import com.fujitsu.iflow.model.workflow.ProcessInstance;
import com.fujitsu.iflow.model.workflow.TimerStatus;
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;
import com.fujitsu.iflow.server.dataobjects.ProcessDefinitionStatesEnum;

import java.sql.*;

import java.util.Random;
// jdk classes.


public class AnalyticsXPDLTest extends FlowPath {

    /*
     * Zero argument constructor.
     */
    public AnalyticsXPDLTest() {
        super();
    }

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

        String filename = null;
        long piId = -1;

        login();
        try {
            // the fist argument from the tr will be the xpdl file name.
            String[] commandLineArgs = tr.getCommandLineArgs();
            filename = commandLineArgs[1];
            Plan plan = createPlanFromXPDL(filename);
            long planId = plan.getId();
            wfSession.publishPlan(planId);
            SafeSleep sleeper = new SafeSleep("SafeSleeping till planId " + planId + " goes to published state.");
            while( plan.getState() != ProcessDefinitionStatesEnum._Published ) {
                sleeper.nap();    //0.1 seconds
            }

            ProcessInstance pi = createProcess(plan);
            if (!checkEvents(pi)) {
                return;
            }

            if(!checkNegativeTestCase(pi)){
                checkResultUDA(pi);
            }
        }
        finally {
            logOutWithoutException();
        }
    }
    private
    boolean
    checkEvents(
        ProcessInstance pi)
        throws Exception
    {
        debug("handleWorkItems()");
        Random randNo = new Random();
        Connection connection = null;

        try {

            // DriverControlLimite can be optionally set to the number of seconds
            // that the process can be in "stop" mode.  If this variable is not
            // set, then the default value is 10 seconds limit.
            DataItem controlLimit = pi.getDataItem("__DriverControlLimit");
            int noWorkListGuard = 300;
            int stopGuard = 100;
            if (controlLimit != null) {
                stopGuard = Integer.parseInt(controlLimit.getValue()) * 10;
            }
            connection = getDBConnect();
            if (connection == null) {
                throw new Exception("Problem in AnalyticsXPDLTest.checkEvents because we can't get a db connection for some reason.");
            }

            while (true) {

                if (pi.getState() == pi.STATE_CLOSED) {
                    tr.log("Strange condition in AnalyticsXPDLTest.checkEvents which exits before doing any test");
                    return true;
                }

                int sCount = getRows(connection);

                DataItem control = pi.getDataItem("__DriverControl");
                if (control != null) {
                    if (control.getValue().equalsIgnoreCase("stop") ){
                        if (stopGuard-- < 0) {
                            markFailed("FlowPath case timed out", "Process variable __DriverControl is in STOP mode for more than 10 seconds");
                            return false;
                        }
                        Thread.sleep(100);    //0.1 seconds
                        continue;
                    }
                }

                WFObjectList wfol = WFObjectFactory.getWFObjectList(wfSession);
                wfol.addFilter(WFObjectList.LISTFIELD_PROCESSINSTANCE_ID , "=", "'"+ pi.getId() +"'");
                wfol.openBatchedList(Filter.MyActiveWorkItems);
                Object[] workItemList = wfol.getNextBatch(0, 99);

                if ( (workItemList == null) || (workItemList.length == 0) ){
                    if (noWorkListGuard-- < 0) {
                        throw new Exception("Timeout waiting 30 seconds for workitem to appear.");
                    }
                    Thread.sleep(100);
                    continue;
                }

                WorkItem workItem = (WorkItem) workItemList[randNo.nextInt(workItemList.length )];
                com.fujitsu.iflow.model.workflow.NodeInstance nInstance = workItem.getNodeInstance();

                if (control == null) {
                    TimerStatus[] tStatus = nInstance.getStatusOfTimers();
                    for(int j = 0; j < tStatus.length; j++){
                        waitForTimerToExpire(tStatus[j].getTimerExpirationTime());
                    }
                }

                String[] choices = workItem.getChoices();
                workItem.makeChoice(choices[randNo.nextInt(choices.length)]); // always select the first choice.

                Thread.sleep(2000);
                if(connection != null) {

                    //We are sleeping here to get the current updated events from DB
                    SafeSleep sleeper = new SafeSleep(30, "sleeping here to get the current updated events from DB");
                    while(getRows(connection)-sCount != 2) {
                        sleeper.nap();
                    }
                    markPassed("XPDL Analytics Test --  passed");
                }
            }
        }
        catch (Exception e) {
            throw new ExceptionWrapper("handleWorkItems() - Possibly because of WorkItem.makeChoice()", e);
        }
        finally
        {
            try {
                if(connection!=null)
                    connection.close();
                connection = null;
            }
            catch (Exception e) {
                // have to ignore this exception
            }
        }
    }


    public
    Connection
    getDBConnect()
        throws Exception
    {

        Connection connection =  null;
        String driver = tr.getRequiredProperty("DBDriver");
        String url = tr.getRequiredProperty("DBDriverUrl");
        String username = "sa";
        String password = "";
        try
        {
            Class.forName(driver);
            connection = (Connection)DriverManager.getConnection(url, username, password);
            tr.markPassed("XPDL Test -- Successfully getDBConnection passed with driver : " + driver+",  URL :" + url + " User Name : " + username + " and Password : " + password);
        } catch(Exception e){
            throw new ExceptionWrapper("XPDL  Test --  getDBConnection Failed with driver : " + driver+",  URL :" + url + " User Name : " + username + " and Password : " + password, e);
        }
        return connection;

    }

    public
    int
    getRows(Connection connection)
        throws Exception
    {
        ResultSet rs = null;
        Statement stmt = null;
        int rows = 0;
        try{
            stmt  = connection.createStatement();
            if (stmt != null){
                StringBuffer sqlString = new StringBuffer("SELECT count(*) as noOfRows  from F_Events");
                rs = stmt.executeQuery(sqlString.toString());
                while(rs.next()) {
                    rows = rs.getInt("noOfRows");
                }
            }
        } catch(Exception e) {
            throw new ExceptionWrapper("XPDL Test -- getRows Failed", e);
        }
        finally
        {
            if(rs!=null)
                rs.close();
            if(stmt!=null)
                stmt.close();
        }
        return rows;
    }
}
