package com.fujitsu.iflowqa.testframe;

import java.awt.Point;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

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;

/**
* This class implements TestSet and the purpose of this class to test
* Analytics. To run this class JTurbo driver and iFlowClients.properties file should be in classpath.
* The results of the test are recorded using
* TestRecorder class.
*/

public class AnalyticsTest implements TestSet
{

    private TestRecorder tr = null;
    private WFAdminSession wfSession = null;
    private String serverName = null;
    private String userName = null;
    private String passWord = null;
    private String planName = null;

    public
    void
    runTests(TestRecorder testRecord)
        throws Exception
    {
        Connection connection = null;
        tr = testRecord;
        connection = getDBConnect();
        logIn();
        try {
            Plan testPlan = createTemplate();
            int sCount = getRows(connection, testPlan);
            createProcess(testPlan);
            logOut();
            int eCount = getRows(connection, testPlan);
            int count = 0;
            SafeSleep sleeper = new SafeSleep(30, "Analytics Test");
            //We are sleeping here to get the current updated events from DB
            while(eCount-sCount < 2) {
                sleeper.nap();
                eCount = getRows(connection, testPlan);
            }
            if((eCount-sCount) != 2) {
                tr.markFailed("Analytics Test" , "expected difference between start count and end count is 2, but actually difference is '" +(eCount-sCount)+"'");
            }
            else {
                tr.markPassed("Analytics Test");
            }
        }
        finally
        {
            logOut();
            if(connection!=null) {
                connection.close();
            }
            connection = null;
        }
    }

    public
    AnalyticsTest()
    {

    }

    public
    Plan
    createTemplate()
    throws Exception
    {
        Plan plan = null;
        try {

            planName = "QA_AnalyticsTest"+System.currentTimeMillis();
            plan = WFObjectFactory.getPlan();
            plan.setWFSession(wfSession);
            plan.startEdit();
            plan.setName( planName );
            plan.setTitle( planName + " title" );
            plan.setDesc( planName + " description" );
            plan.setPlanIdentifier("Global");
            Node startNode = plan.addNode( "Start", Node.TYPE_START );
            int startX = 50;
            int startY = 100;
            startNode.setPosition( new Point( startX, startY ) );
            Node firstActNode = plan.addNode( "ACTIVITY-ANALYTICS", Node.TYPE_ACTIVITY );
            firstActNode.setPosition( new Point( startX + 200, startY ) );
            firstActNode.setRole( "Role" );
            firstActNode.setDesc("ACTIVITY-ANALYTICS");
            plan.addArrow( "START", startNode, firstActNode );
            Node exitNode = plan.addNode( "EXIT", Node.TYPE_EXIT );
            exitNode.setPosition( new Point( startX + 200, startY + 200) );
            plan.addArrow( "DONE", firstActNode, exitNode);
            plan = plan.createProcessDef();
            if (plan == null) {
                throw new Exception("Tried to create plan, but got null back");
            }
            wfSession.publishPlan(plan.getId());
        } catch (Exception e) {
            logAndRethrow("createProcess FAILED", e);
        }
        return plan;
    }

    private
    void
    createProcess(Plan plan)
        throws Exception
    {
        try {
            ProcessInstance pi = plan.createProcessInstance();
            if (pi == null) {
                throw new Exception("Tried to create process instance, but got null back");
            }
            pi.start();
        } catch (Exception e) {
            logAndRethrow("createProcess FAILED", e);
        }
    }

    public
    void
    logIn()
        throws Exception
    {
        try {
            String transPortType = tr.getRequiredProperty("TWFTransportType");
            wfSession = WFObjectFactory.getWFAdminSession();
            wfSession.initForApplication(null, tr.getProps());
            serverName = tr.getRequiredProperty("servername");
            userName = tr.getRequiredProperty("username");
            passWord = tr.getRequiredProperty("password");
            wfSession.logIn(serverName+"Flow", userName, passWord);
            tr.markPassed("Analytics Test --  login successfully PASSED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord);
        } catch (Exception e) {
            logAndRethrow("login FAILED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord, e);
        }
    }

    public
    void
    logOut()
        throws Exception
    {
        try {
            wfSession.logOut();
            tr.markPassed("Analytics Test --  logout  successfully PASSED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord);
        } catch (Exception e) {
            logAndRethrow("Analytics Test --  logout FAILED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord,e);
        }
    }

    public
    Connection
    getDBConnect()
        throws Exception
    {
        String driver = tr.getRequiredProperty("DBDriver");
        String url = tr.getRequiredProperty("DBDriverUrl");
        String username = "sa";
        String password = "";
        try {
            Connection connection =  null;
            Class.forName(driver);
            connection = (Connection)DriverManager.getConnection(url, username, password);
            if (connection == null) {
                throw new Exception("Connection request returned a null");
            }
            return connection;
        }
        catch (Exception e) {
            throw new Exception("Not able to get DB connection: (" + driver+"),  URL :(" + url + "), User Name: (" + username + ") and Password: (" + password + ") because: {"+e.toString()+"}");
        }
    }

    public
    int
    getRows(Connection connection, Plan testPlan)
        throws Exception
    {
        ResultSet rs = null;
        Statement stmt = null;
        int rows = 0;
        try{
            stmt  = connection.createStatement();
            if (stmt != null){
                String sqlString = "SELECT count(*) as noOfRows  from F_Events, D_WorkClass where F_Events.WorkClass_key = D_WorkClass.WorkClass_key AND D_WorkClass.WorkflowName = '"+planName+"'";
                rs = stmt.executeQuery(sqlString);
                while(rs.next()) {
                    rows = rs.getInt("noOfRows");
                }
            }
            tr.log("Analytics Test -- Rows retrieved from database: "+rows);
        } catch(Exception e) {
            logAndRethrow("Analytics Test -- getRows Failed", e);
        }
        finally
        {
            if(rs!=null)
                rs.close();
            if(stmt!=null)
                stmt.close();
        }
        return rows;
    }

    public
    void
    logAndRethrow(
        String message,
        Exception e)
            throws Exception
    {
        tr.log(message);
        //tr.markFatalError(e);
        throw new ExceptionWrapper(message, 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.AnalyticsTest";
        TestDriver.main(newArgs);
        System.exit(0);
    }

}

