package com.fujitsu.iflowqa.testframe;

import java.awt.Point;
import java.util.Hashtable;

import com.fujitsu.iflow.model.util.IflowEnumeration;
import com.fujitsu.iflow.model.workflow.DataItem;
import com.fujitsu.iflow.model.workflow.DataItemRef;
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.TrackedUDARecord;
import com.fujitsu.iflow.model.workflow.WFAdminSession;
import com.fujitsu.iflow.model.workflow.WFObjectFactory;

/**
* Test for UDA tracking feature. This class tests following 3 different scenarios
* 1. Test to see whether the UDA Tracking can be added sucessfully, while designing the process definition
* 2. After creating the process, it sets all the UDA track values are set sucessfully and the Initi script also
* 3. Edits this process and adds one more UDA Tracking, modifies the existing UDA tracking value and unchecks
* the UDA tracking variable to set it to non-uda tracking varaible. Checks to see if all this information
* is updated properly on process edit.
*/

public class UDATrackingTest implements TestSet
{

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

    private String UDA_TRACK1 = "UDA_Track1";
    private String UDA_TRACK2 = "UDA_Track2";
    private String UDATRACK_PROCEDIT = "UDATrack_EditProc";
    
    public
    void
    runTests(TestRecorder testRecord)
        throws Exception
    {
        try {
            tr = testRecord;
            logIn();
            Plan testPlan = createTemplate();
            ProcessInstance procInst = createProcess(testPlan);
            editProcess(procInst);
        } catch (Exception e) {
           logException("Exception caught in main test level", e);
        }
        finally
        {

        }
    }

    public
    UDATrackingTest()
    {

    }
    
    /**
     * Creates the template with the Trackable UDA's. After the sucessfull creattion of the process definition,
     * it checks to see the UDA are set as Trackable UDA.
     */
    private
    Plan
    createTemplate()
    throws Exception
    {
        Plan plan = null;

       try {
            String planName = "QA_UDATrackingTest";
            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-UDATRACK", Node.TYPE_ACTIVITY );
            firstActNode.setPosition( new Point( startX + 200, startY ) );
            firstActNode.setRole( "Role" );
            firstActNode.setDesc("ACTIVITY-UDATRACK");
            startNode.addArrow( "START", firstActNode );
            Node exitNode = plan.addNode( "EXIT", Node.TYPE_EXIT );
            exitNode.setPosition( new Point( startX + 200, startY + 200) );
            firstActNode.addArrow( "DONE", exitNode );

            DataItemRef uda1 = plan.addDataItemRef(UDA_TRACK1, "STRING", "Initial UDA_Track1");
            uda1.markUdaTracking(true);
            DataItemRef uda2 = plan.addDataItemRef(UDA_TRACK2, "STRING", "Initial UDA_Track2");
            uda2.markUdaTracking(true);
            plan.setInitScript("setProcessAttribute(\"UDA_Track1\",\"STRING\" , \"Value successfully changed by InitScript\")");
            
            plan = plan.createProcessDef();
            
            DataItemRef data1 = plan.getDataItemRef(UDA_TRACK1);
            if(data1.isUdaTracking())
                tr.markPassed("Sucessfully set UDA Tracking for UDA '"+UDA_TRACK1+"' on Process Definition");
            else
                tr.markFailed("Failed to set '"+UDA_TRACK1+"' UDA for tracking on Process Definition","Expected isUdaTracking() to return 'true'. But retrieved 'false'");
            
            DataItemRef data2 = plan.getDataItemRef(UDA_TRACK2);
            if(data2.isUdaTracking())
                tr.markPassed("Sucessfully set UDA Tracking for UDA '"+UDA_TRACK2+"' on Process Definition");
            else
                tr.markFailed("Failed to set '"+UDA_TRACK2+"' UDA for tracking on Process Definition","Expected isUdaTracking() to return 'true'. But retrieved 'false'");

       }catch (Exception e) {
            logException("UDATracking Test -- Plan creation failed", e);
        }
        return plan;
    }
    
    /**
     * Creates the Process instance and validates all the Trackable UDA's, also validates the History information
     * for a Trackable UDA value set by the Init script in the Process definition 
     */
    private
    ProcessInstance
    createProcess(Plan plan)
        throws Exception
    {
        ProcessInstance pi = null;
        try{
            pi = plan.createProcessInstance();
            pi.start();
            DataItem data1 = pi.getDataItem(UDA_TRACK1);
            if(data1.isUdaTracking())
                tr.markPassed("Sucessfully retrieved UDA Tracking status for UDA '"+UDA_TRACK1+"' on Process Instance");
            else
                tr.markFailed("Failed to retrieve the UDA Tracking status for UDA '"+UDA_TRACK1+"' on Process Instance","Expected isUdaTracking() to return 'true'. But retrieved 'false'");
            
            DataItem data2 = pi.getDataItem(UDA_TRACK2);
            if(data2.isUdaTracking())
                tr.markPassed("Sucessfully retrieved UDA Tracking status for UDA '"+UDA_TRACK2+"' on Process Instance");
            else
                tr.markFailed("Failed to retrieve the UDA Tracking status for UDA '"+UDA_TRACK2+"' on Process Instance","Expected isUdaTracking() to return 'true'. But retrieved 'false'");
            // validate the UDA Track History
            valiateUDATrackHistory(pi);
            
        } catch (Exception e) {
            logException("UDATracking Test -- Process creation failed", e);
        }
        return pi;
    }
    
    /**
     * Validates the UDA Tracking History information for a 'UDA_Track1' UDA
     */
    private
    void
    valiateUDATrackHistory(ProcessInstance procInst) throws Exception
    {
        try
        {
            IflowEnumeration sElements = getUDATrackHistory(procInst);
            Integer udaHistoryKey = new Integer(ProcessInstance.HISTORY_MODIFIED_TRACKEDUDAS);
            boolean bSuccess = false;
            while(sElements.hasMoreElements()) 
            {
                Hashtable historyData = (Hashtable) sElements.nextElement();
                TrackedUDARecord[] tUdas = (TrackedUDARecord[] )historyData.get(udaHistoryKey);
                if (tUdas != null) 
                {
                    for(int i=0; i< tUdas.length; i++)
                    {
                        if(tUdas[i].getName().equals(UDA_TRACK1) && 
                                tUdas[i].getUDAOperation() == TrackedUDARecord.UDA_MODIFIED)
                        {
                            if(tUdas[i].getOldValue().equals("Initial UDA_Track1") &&
                                    tUdas[i].getNewValue().equals("Value successfully changed by InitScript"))
                            {
                                bSuccess = true;
                                break;
                            }
                        }
                    }
                }
                if(bSuccess)
                    break;
            }
            if(bSuccess)
                tr.markPassed("Modified value for '"+UDA_TRACK1+"' from the History has been sucessfully retrieved");
            else
                tr.markFailed("Failed to retrieve the modified value from the History for the '"+UDA_TRACK1+"'","Expected value 'Value successfully changed by InitScript' for '"+UDA_TRACK1+"'");
        }
        catch(Exception ex){
            logException("UDATracking Test -- Validation for UDA History Failed", ex);
        }
        
    }
    
    /**
     * Edits the process instance, adds the new Trackable UDA 'UDATrack_EditProc', sets the 'UDA_Track2' to non-trackable UDA,
     * modifies the value for the 'UDA_Track1' trackable UDA and finally commits all the changes to process instance
     */
    private
    void
    editProcess(ProcessInstance process)
        throws Exception
    {
        DataItem[] data_items = new DataItem[3];
        process.startStructuralEdit();
        
        DataItem data3 = process.addDataItem(UDATRACK_PROCEDIT, "STRING", "Initial UDATrack For EditProcess");
        data3.markUdaTracking(true);
        data_items[0] = data3;
        
        data_items[1] = process.getDataItem(UDA_TRACK2);
        data_items[1].markUdaTracking(false);

        data_items[2] = process.getDataItem(UDA_TRACK1);
        data_items[2].setValue("Modified in Process Edit");
        
        process.setDataItems(data_items);
        process.commitStructuralEdit();
        // validate the UDA History in Process Edit
        valiateProcEditUDATrack(process);
    }
    
    /**
     * Validates the Trackable UDA History information for all the edits performed in the Process instance edit
     */
    private
    void
    valiateProcEditUDATrack(ProcessInstance procInst) throws Exception
    {
        try
        {
            IflowEnumeration sElements = getUDATrackHistory(procInst);
            Integer udaHistoryKey = new Integer(ProcessInstance.HISTORY_MODIFIED_TRACKEDUDAS);
            boolean editUda = false, udatrack1 = false, udatrack2 = false;
            while(sElements.hasMoreElements()) 
            {
                Hashtable historyData = (Hashtable) sElements.nextElement();
                TrackedUDARecord[] tUdas = (TrackedUDARecord[] )historyData.get(udaHistoryKey);
                if (tUdas != null) 
                {
                    for(int i=0; i< tUdas.length; i++)
                    {
                        int udaOperation = tUdas[i].getUDAOperation();
                        if(tUdas[i].getName().equals(UDATRACK_PROCEDIT))
                        {
                            if(udaOperation == TrackedUDARecord.UDA_ADD)
                                tr.markPassed("Successfully retrieved UDAOperation 'ADD(1)' for '"+UDATRACK_PROCEDIT+"'");
                            else
                                tr.markFailed("Failed to retrieve UDAOperation for '"+UDATRACK_PROCEDIT+"'", "Expected value '1', but retrieved value: "+udaOperation);
                            String curVal = tUdas[i].getNewValue();
                            if(curVal.equals("Initial UDATrack For EditProcess"))
                                tr.markPassed("Successfully retrieved New Value for '"+UDATRACK_PROCEDIT+"'");
                            else
                                tr.markFailed("Failed to retrieve New Value for '"+UDATRACK_PROCEDIT+"'", "Expected value 'Initial UDATrack For EditProcess', but retrieved value: "+curVal);
                            editUda = true;
                        }
                        else if(tUdas[i].getName().equals(UDA_TRACK2))
                        {
                            if(udaOperation == TrackedUDARecord.UDA_DELETE)
                                tr.markPassed("Successfully retrieved UDAOperation 'DELETE(2)' for '"+UDA_TRACK2+"'");
                            else
                                tr.markFailed("Failed to retrieve UDAOperation for '"+UDA_TRACK2+"'", "Expected value '2', but retrieved value: "+udaOperation);
                            udatrack2 = true;
                        }
                        else if(tUdas[i].getName().equals(UDA_TRACK1))
                        {
                            if(udaOperation == TrackedUDARecord.UDA_MODIFIED)
                                tr.markPassed("Successfully retrieved UDAOperation 'MODIFIED(3)' for '"+UDA_TRACK1+"'");
                            else
                                tr.markFailed("Failed to retrieve UDAOperation for '"+UDA_TRACK1+"'", "Expected value '3', but retrieved value: "+udaOperation);
                            
                            String prevVal = tUdas[i].getOldValue();
                            String curVal = tUdas[i].getNewValue();
                            if(prevVal.equals("Initial UDA_Track1") && curVal.equals("Value successfully changed by InitScript"))
                                tr.markPassed("First Set: Successfully retrieved Old & New Value for '"+UDA_TRACK1+"'");
                            else if(prevVal.equals("Value successfully changed by InitScript") && curVal.equals("Modified in Process Edit"))
                                tr.markPassed("Second set: Successfully retrieved Old & New Value for '"+UDA_TRACK1+"'");
                            else
                                tr.markFailed("Failed to retrieve Old Value for '"+UDA_TRACK1+"'", "Expected value 'Initial UDA_Track1', but retrieved value: "+prevVal);
                            udatrack1 = true;
                        }
                    }
                    
                }
            }
            if(!editUda)
                tr.markFailed("Failed to retrive the '"+UDATRACK_PROCEDIT+"' UDA informatation from the history","");
            if(!udatrack2)
                tr.markFailed("Failed to retrive the '"+UDA_TRACK2+"' UDA informatation from the history","");
            if(!udatrack1)
                tr.markFailed("Failed to retrive the '"+UDA_TRACK1+"' UDA informatation from the history","");
        }
        catch(Exception ex){
            logException("UDATracking Test -- Validation for UDA History in edit process Failed ", ex);
        }
        
    }
    
    /**
     * Retrieves the History information for the UDA Tracking 
     */
    private
    IflowEnumeration
    getUDATrackHistory(ProcessInstance procInst) throws Exception
    {
        int _processHistoryFields[] = {ProcessInstance.HISTORY_MODIFIED_TRACKEDUDAS};
        IflowEnumeration sElements = procInst.getHistory(_processHistoryFields);
        return sElements;
    }

    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("UDATracking Test -- login successfully PASSED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord);
        } catch (Exception e) {
            logException("UDATracking Test -- login FAILED on Server : " + serverName + " with  User Name : " + userName + " and Password : " + passWord, e);
        }
    }

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


    public
    void
    logException(
        String message,
        Exception e)
            throws Exception
    {
        tr.log(message);
        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.UDATrackingTest";
        TestDriver.main(newArgs);
    }
}

