// IFWSClient.java
// This Client application performs all procedures
package com.fujitsu.iflowqa.testframe;

// WebServices classes
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.xml.namespace.QName;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;

import com.fujitsu.iflow.webservices.ObjList;
import com.fujitsu.iflow.webservices.UdaStruct;


public class IFWSClient
{
    public static final String DFLT_WSDL_URL = "http://localhost:49950/iflowws/services/IFWebServices?wsdl";    
    public static final String DFLT_NAMESPACE = "http://www.fsw.fujitsu.com";
    public static final String USERNAME = "username";
    public static final String PASSWORD = "password";
    static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    Service srv;
    String username;
    String password;
    String wsdl_url;    
    String namespace;    
    QName portQn;    
    
    public IFWSClient(String user, String pass) 
        throws Exception
    {        
        this(user, pass, DFLT_WSDL_URL, DFLT_NAMESPACE);    
    }    
    
    public IFWSClient(String username, String password, String wsdl_url)
        throws Exception
    {        
        this(username, password, wsdl_url, DFLT_NAMESPACE);    
    }
    
    public IFWSClient(String username, String password, String wsdl_url, String namespace) 
        throws Exception
    {
        debug("IFWSClient(username, password, webservice_url, webservice_namespace");
        this.username = username;
        this.password = password;
        this.wsdl_url = wsdl_url;        
        this.namespace = namespace;        
        init();
    }
    
    void
    init()
        throws Exception
    {
        debug("init()");
        try {
            QName serviceQn = new QName(namespace, "IFWebServicesService");
            srv = new Service(wsdl_url, serviceQn);
            portQn = new QName(namespace, "IFWebServices");
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to initialize IFWSClient", e);
        }
    }

    ObjList[]
    getMyPlans()
        throws Exception
    {
        debug("getMyPlans():ObjList[]");
        return getMyIFlowObjects("getMyTemplateList");
    }

    ObjList[]
    getMyProcesses()
        throws Exception
    {
        debug("getMyProcesses():ObjList[]");
        return getMyIFlowObjects("getMyProcessList");
    }

    ObjList[]
    getMyWorkItems()
        throws Exception
    {
        debug("getMyWorkItems():ObjList[]");
        return getMyIFlowObjects("getMyWorkItemList");
    }

    ObjList[]
    getMyIFlowObjects(
        String operation)
        throws Exception
    {
        debug("getMyIFlowObjects(objectType):ObjList[]");
        Call call = null;
        ObjList[] objs = null;
        try {
            QName operationQn = new QName(namespace, operation);
            call = (Call)srv.createCall(portQn, operationQn);
            
            QName objListQn = new QName(namespace, "ObjList");
            call.registerTypeMapping(ObjList.class, objListQn, BeanSerializerFactory.class, BeanDeserializerFactory.class);

            Object result = call.invoke( new Object[] { username, password } );

            if (result instanceof String)
                prn("Error = " + result);
            else {
                objs = getObjList(result);
            }

        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getMyIFlowObjects", e);
        }
        finally {
            if (call != null) {
                call.removeAllParameters();
            }
        }
        return objs;
    }

    long
    startProcess(
        long planid)
        throws Exception
    {
        debug("startProcess(planId)");
        Call call = null;
        long processId = -1;
        try {
            QName operationQn = new QName(namespace, "startProcess");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password, new Long(planid) } );
            
            if (result instanceof String)
                throw new Exception("startProcess:ret error="+result);
            else {
                processId = ((Long) result).longValue();
                debug("Process Id= "+processId);
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to startProcess",e);
        }
        finally {
            call.removeAllParameters();
        }
        return processId;
    }

    UdaStruct[]
    getUserData(
        long processid)
        throws Exception
    {
        debug("getUserData");
        Call call = null;
        UdaStruct[] udas = null;
        try {
            QName operationQn = new QName(namespace, "getUserData");
            call = (Call)srv.createCall(portQn, operationQn);

            QName qn = new QName(namespace, "UdaStruct");
            call.registerTypeMapping(UdaStruct.class, qn, BeanSerializerFactory.class, BeanDeserializerFactory.class);

            Object result = call.invoke( new Object[] { username, password , new Long(processid)} );
            if (result instanceof String)
                throw new Exception("getUserData: error= "+result);
            else {
                ArrayList al = (ArrayList)result;
                if (al != null) {
                    udas = new UdaStruct[al.size()];
                    for (int i=0;i<al.size();i++) {
                        UdaStruct uda = (UdaStruct)al.get(i);
                        udas[i] = uda;
                        debug("Uda Name = " + uda.getName());
                        debug("Uda Type = " + uda.getType());
                        debug("Uda Value = " + uda.getValue());
                    }
                }
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getUserData", e);
        }
        finally {
            call.removeAllParameters();
        }
        return udas;
    }

    boolean
    addUserDataItem(
        long processid,
        String udaName,
        String udaType,
        String udaValue)
        throws Exception
    {
        debug("addUserDataItem");
        Call call = null;
        boolean retVar = false;
        try {
            QName operationQn = new QName(namespace, "addUserDataItem");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(processid), udaName, udaType, udaValue} );
            if (result instanceof String)
                throw new Exception("addUserDataItem:error= "+result);
            else {
                retVar = new Boolean(result.toString()).booleanValue();
                debug("addUserDataItem= "+result.toString());
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to addUserDataItem", e);
        }
        finally {
            call.removeAllParameters();
        }
        return retVar;
    }

    void
    modifyUserDataItem(
        long processid,
        String udaName,
        String udaValue)
        throws Exception
    {
        debug("modifyUserDataItem");
        Call call = null;
        try {
            QName operationQn = new QName(namespace, "modifyUserDataItem");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(processid), udaName, udaValue} );
            
            if (result instanceof String)
                throw new Exception("modifyUserDataItem:error= "+result);
            else
                debug("modifyUserDataItem= "+result.toString());
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to modifyUserDataItem", e);
        }
        finally {
            call.removeAllParameters();
        }
    }

    String
    getWorkItemChoices(
        long workitemid)
        throws Exception
    {
        debug("getWorkItemChoices");
        Call call = null;
        String choice = "";
        try {
            QName operationQn = new QName(namespace, "getWorkItemChoices");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(workitemid)} );

            if (result instanceof String)
                choice = (String) result;
            else {
                ArrayList al = (ArrayList)result;
                if (al != null) {
                    for (int i=0;i<al.size();i++) {
                        String str = (String)al.get(i);
                        choice = str;
                    }
                }
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getWorkItemChoices",e);
        }
        finally {
            call.removeAllParameters();
        }
        return choice;
    }

    void
    submitWorkItem(
        long workitemid,
        String choice)
        throws Exception
    {
        debug("submitWorkItem");
        Call call = null;
        try {
            QName operationQn = new QName(namespace, "submitWorkItem");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(workitemid), choice} );

            if (result instanceof String)
                throw new Exception("submitWorkItem:error= "+result);
            else
                debug("submitWorkItem: "+result.toString());
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to submitWorkItem",e);
        }
        finally {
            call.removeAllParameters();
        }
    }

    String
    getTemplateState(
        long planid)
        throws Exception
    {
        debug("getPlanState");
        Call call = null;
        String planState = "";
        try {
            QName operationQn = new QName(namespace, "getTemplateState");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(planid)} );
            
            if (result instanceof String) {
                planState = (String) result;
                debug("getPlanState: "+result);
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getPlanState",e);
        }
        finally {
            call.removeAllParameters();
        }
        return planState;
    }

    String
    getProcessState(
        long processid)
        throws Exception
    {
        debug("getProcessState");
        Call call = null;
        String piState = "";
        try {
            QName operationQn = new QName(namespace, "getProcessState");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(processid)} );

            if (result instanceof String) {
                piState = (String) result;
                debug("getProcessState: "+result);
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getProcessState",e);
        }
        finally {
            call.removeAllParameters();
        }
        return piState;
    }

    String
    getWorkItemState(
        long workitemid)
        throws Exception
    {
        debug("getWorkItemState");
        Call call = null;
        String workItemState = "";
        try {
            QName operationQn = new QName(namespace, "getWorkItemState");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(workitemid)} );

            if (result instanceof String) {
                workItemState = (String) result;
                debug("getWorkItemState: "+result);
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getWorkItemState",e);
        }
        finally {
            call.removeAllParameters();
        }
        return workItemState;
    }

    String
    getAttachmentList(
        long processid)
        throws Exception
    {
        debug("getAttachmentList");
        Call call = null;
        String attachment = "";
        try {
            QName operationQn = new QName(namespace, "getAttachmentList");
            call = (Call)srv.createCall(portQn, operationQn);

            Object result = call.invoke( new Object[] { username, password , new Long(processid)} );
            
            if (result instanceof String)
                attachment = (String) result;
            else {
                ArrayList al = (ArrayList)result;
                if (al != null) {
                    for (int i=0;i<al.size();i++) {
                        String str = (String)al.get(i);
                        attachment = str;
                    }
                }
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getAttachmentList", e);
        }
        finally {
            call.removeAllParameters();
        }
        return attachment;
    }

    void
    writeTheFile(
        InputStream is)
        throws Exception
    {
        try {
            byte[] bytes = new byte[is.available()];
            int tmp = 0;
            StringBuffer sb = new StringBuffer();
            while ((tmp = is.read(bytes)) != -1) {
                sb.append(new String(bytes));
            }
            debug("The content of Attachment: ");
            debug(sb.toString());
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to writeTheFile", e);
        }
    }

    ObjList[]
    getObjList(
        Object result)
        throws Exception
    {
        debug("printObjListArray");
        ObjList[] objs = null;
        try {
            ArrayList al = (ArrayList)result;
            if (al != null) {
                objs = new ObjList[al.size()];
                for (int i=0;i<al.size();i++) {
                    ObjList obj = (ObjList)al.get(i);
                    objs[i] = obj;
                    debug("Name = "+obj.getName());
                    debug("Id = "+obj.getId());
                }
            }
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to printObjListArray",e);
        }
        return objs;
    }

    public
    static
    void
    main(
        String[] s)
    {
        try
        {
            if (s.length < 4) {
                prn("Usage: java IFWSClient username password WEBSERVICE_URL WebService_namespace");
                System.exit(0);
            }
            IFWSClient client = new IFWSClient(s[0], s[1], s[2], s[3]);
            int option = 0;
            do {
                option = client.getOptions();
                switch(option) {
                    case 1: {
                        client.getMyPlans();
                        break;
                    }
                    case 2: {
                        client.getMyProcesses();
                        break;
                    }
                    case 3: {
                        client.getMyWorkItems();
                        break;
                    }
                    case 4: {
                        long planid = Long.parseLong(getInput("Plan Id"));
                        client.startProcess(planid);
                        break;
                    }
                    case 5: {
                        long processid = Long.parseLong(getInput("Process Id"));
                        client.getUserData(processid);
                        break;
                    }
                    case 6: {
                        long processid = Long.parseLong(getInput("Process Id"));
                        String udaName = getInput("UserDataItem Name:");
                        prn("Supported Types: BOOLEAN,INTEGER,FLOAT,STRING,LONG");
                        String udaType = getInput("UserDataItem Type:");
                        String udaValue = getInput("UserDataItem Value:");
                        client.addUserDataItem(processid, udaName, udaType, udaValue);
                        break;
                    }
                    case 7: {
                        long processid = Long.parseLong(getInput("Process Id"));
                        String udaName = getInput("UserDataItem Name:");
                        String udaValue = getInput("UserDataItem Value:");
                        client.modifyUserDataItem(processid, udaName, udaValue);
                        break;
                    }
                    case 8: {
                        long workitemid = Long.parseLong(getInput("WorkItem Id"));
                        client.getWorkItemChoices(workitemid);
                        break;
                    }
                    case 9: {
                        long workitemid = Long.parseLong(getInput("WorkItem Id"));
                        String choice = getInput("Choice");
                        client.submitWorkItem(workitemid, choice);
                        break;
                    }
                    case 10: {
                        long planid = Long.parseLong(getInput("Plan Id"));
                        client.getTemplateState(planid);
                        break;
                    }
                    case 11: {
                        long processid = Long.parseLong(getInput("Process Id"));
                        client.getProcessState(processid);
                        break;
                    }
                    case 12: {
                        long workitemid = Long.parseLong(getInput("WorkItem Id"));
                        client.getWorkItemState(workitemid);
                        break;
                    }
                    case 13: {
                        long processid = Long.parseLong(getInput("Process Id"));
                        client.getAttachmentList(processid);
                        break;
                    }
                    case 14: {
                        prn("bye..bye..");
                        break;
                    }
                    default: {
                        prn("Invalid Option.");
                        break;
                    }
                }
            } while (option != 14);
        }
        catch (Exception e) {
            System.out.println("FATAL ERROR, EXCEPTION = "+e.toString());
            e.printStackTrace();
            System.out.println("IFWSClient.java ABORTED");
        }
    }

    int
    getOptions()
        throws Exception
    {
        prn("*** IFWSClient Options ***");
        prn("1. getMyTemplateList");
        prn("2. getMyProcessList");
        prn("3. getMyWorkItemList");
        prn("4. startProcess");
        prn("5. getUserData");
        prn("6. addUserDataItem");
        prn("7. modifyUserDataItem");
        prn("8. getWorkItemChoices");
        prn("9. submitWorkItem");
        prn("10. getTemplateState");
        prn("11. getProcessState");
        prn("12. getWorkItemState");
        prn("13. getAttachmentList");
        prn("14. Exit.");
        int input = Integer.parseInt(getInput("Option[1-14]:"));
        return input;
    }

    static
    String
    getInput(
        String title)
        throws Exception
    {
        String input = "";
        try {
            prn("Enter value for "+title);
            input = br.readLine();
        }
        catch(Exception e) {
            throw new ExceptionWrapper("unable to getInput",e);
        }
        return input;
    }

    void
    debug(
        String msg)
    {
        // add in here a printline capability
        // if you need debugging
    }

    static
    void
    prn(
        String s)
    {
        System.out.println(s);
    }

    static
    void
    prn(
        String s,
        Exception e)
    {
        prn(s);
        e.printStackTrace();
    }
}
