/*
 * $Id: CORBAProcessManager.java,v 1.4 2004/10/07 12:40:58 koppy Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 * 
 * Created on 13.07.2004
 *
 * $Log: CORBAProcessManager.java,v $
 * Revision 1.4  2004/10/07 12:40:58  koppy
 * Bugfix: Aktualisierung von Booleanvariablen
 *
 * Revision 1.3  2004/09/20 10:26:11  koppy
 * +javadoc Dokumentation
 *
 * Revision 1.2  2004/09/01 15:26:48  koppy
 * bugfix beim Setzen von Context-Variablen
 *
 * Revision 1.1  2004/08/30 14:49:55  koppy
 * Initiale Version der Workflow-Komponente
 *
 */
package vkc.workflow.service.corba;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.enhydra.shark.SharkConstants;
import org.enhydra.shark.api.client.wfbase.BaseException;
import org.enhydra.shark.corbaclient.WorkflowUtilities;
import org.omg.CORBA.Any;

import vkc.db.entities.VKCUser;
import vkc.util.StringUtils;
import vkc.workflow.WorkflowException;
import vkc.workflow.model.ProcessInstanceInfo;
import vkc.workflow.model.VariableInfo;
import vkc.workflow.service.CORBAWorkflowService;
import vkc.workflow.service.VKCWorkflowService;
import vkc.workflow.service.WfMConnection;
import vkc.workflow.service.manager.ProcessManager;
import vkc.workflow.util.SharkUtils;
import WfBase.NameValue;
import WorkflowModel.AlreadyRunning;
import WorkflowModel.CannotStart;
import WorkflowModel.CannotStop;
import WorkflowModel.InvalidRequester;
import WorkflowModel.NotEnabled;
import WorkflowModel.NotRunning;
import WorkflowModel.RequesterRequired;
import WorkflowModel.WfActivity;
import WorkflowModel.WfProcess;
import WorkflowModel.WfProcessIterator;
import WorkflowModel.WfProcessMgr;
import WorkflowService.AdminMisc;
import WorkflowService.ExecutionAdministration;
import WorkflowService.NotConnected;
import WorkflowService.SharkConnection;

/**
 * This class represents the CORBA client version
 * of the process manager.
 * 
 * @author Andreas Koop
 */
public class CORBAProcessManager implements ProcessManager {

    private CORBAWorkflowService wfService = null;

    public CORBAProcessManager(CORBAWorkflowService wfService) {
        this.wfService = wfService;
    }

    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#instantiateProcess(vkc.db.entities.VKCUser, java.lang.String, java.lang.String)
     */
    public String instantiateProcess(VKCUser user, String pkgId,
            String pDefId) throws WorkflowException {


        SharkConnection sConn = wfService.getShark().getSharkConnection();

        try {
            sConn.connect(user.getUser(), user.getClearPassword(), wfService.getEngine(), "");
            WfProcess proc = sConn.createProcess(pkgId, pDefId);
            return proc.key();
        } catch (NotConnected e) {
            throw new WorkflowException( "wf.error.notConnected", e);
        } catch (NotEnabled e) {
            throw new WorkflowException( "wf.error.notEnabled", e);
        } catch (InvalidRequester e) {
            throw new WorkflowException( "wf.error.invalidRequester", e);
        } catch (RequesterRequired e) {
            throw new WorkflowException( "wf.error.requesterRequired", e);
        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        } finally {

            SharkUtils.disconnect(sConn);
        }

    }
    
    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#startProcess(vkc.db.entities.VKCUser, java.lang.String)
     */
    public void startProcess(VKCUser user, String procId ) throws WorkflowException {

        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
        								.getExecutionAdministration();
        try {
            ea.connect(user.getUser(), user.getClearPassword(), wfService.getEngine(), "");
            WfProcess process = ea.getProcess( procId );
            process.start();
        } catch (CannotStart e) {
            throw new WorkflowException( "wf.error.cannotStart", e);
        } catch (AlreadyRunning e) {
            throw new WorkflowException( "wf.error.alreadyRunning", e);
        } catch (NotConnected e) {
            throw new WorkflowException( "wf.error.notConnected", e);
        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        } finally {

            SharkUtils.disconnect(ea);
        }

    }
    
    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#abortProcess(vkc.db.entities.VKCUser, java.lang.String)
     */
    public void abortProcess(VKCUser user, String procId ) throws WorkflowException {

        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
        								.getExecutionAdministration();
        try {
            ea.connect(user.getUser(), user.getClearPassword(), wfService.getEngine(), "");
            WfProcess process = ea.getProcess( procId );
            process.abort();
        } catch (NotConnected e) {
            throw new WorkflowException( "wf.error.notConnected", e);
        } catch (CannotStop e) {
            throw new WorkflowException( "wf.error.cannotStop", e);
        } catch (NotRunning e) {
            throw new WorkflowException( "wf.error.notRunning", e);
        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        } finally {

            SharkUtils.disconnect(ea);
        }

    }

    public List getProcessInstances(String userName, String pwd, String state) 
    	throws WorkflowException {

        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
        									.getExecutionAdministration();
        AdminMisc am = wfService.getShark().getAdminInterface().getAdminMisc();
        
        try {

            ea.connect(userName, pwd, wfService.getEngine(), "");
            am.connect(userName, pwd, wfService.getEngine(), "");
            
            WfProcessMgr[] a = ea.get_iterator_processmgr()
                    .get_next_n_sequence(0);
            
            List processInstances = new ArrayList(a.length);

            for (int i = 0; i < a.length; ++i) {
                WfProcessIterator iter = a[i].get_iterator_process();
                iter.set_query_expression("state.startsWith(\"" + state + "\")");
                WfProcess[] ps = iter.get_next_n_sequence(0);
                
                for (int j = 0; j < ps.length; j++) {
                    WfProcess process = ps[j];
                    
                    if( !am.getProcessRequesterUsername( process.key() ).equals( userName) ){
                        continue;
                    }
                    
                    ProcessInstanceInfo pInfo = new ProcessInstanceInfo(process);
                    
                    if( state.equals( SharkConstants.STATE_OPEN_RUNNING )){
                        WfActivity [] acts = process.get_activities_in_state( SharkConstants.STATE_OPEN_RUNNING )
                        					.get_next_n_sequence(0);
                        
                        String processors = "";
                        for (int k = 0; k < acts.length; k++) {
                            WfActivity activity = acts[k];
                            processors +=
                               am.getActivityResourceUsername(process.key(), activity.key());
                            processors +=", ";
                        }
                        
                        if( !StringUtils.isEmpty(processors)){
                            pInfo.setProcessors(processors.substring(0, processors.length()-2));
                        }
                        
                    }
                    
                    processInstances.add(pInfo);
                    
                    if (VKCWorkflowService.debug) {
                        System.err.println("--------process");
                        System.err.println(pInfo);
                    }
                }
            }
            return processInstances;

        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        } finally {
            SharkUtils.disconnect(ea);
            SharkUtils.disconnect(am);
        }

    }

    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#deleteClosedProcess(vkc.workflow.service.WfMConnection, java.lang.String)
     */
    public void deleteClosedProcess(WfMConnection sConn, String procId) throws WorkflowException {
        
        if( procId == null)
            return;
        
        ExecutionAdministration ea = wfService.getShark()
        								.getAdminInterface()
                    					.getExecutionAdministration();
           
        try {
            ea.connect(sConn.getUsername(),sConn.getPassword(), wfService.getEngine(), "");

            ea.deleteClosedProcess( procId );
        }catch (NotConnected e) {
            throw new WorkflowException( "wf.error.notConnected", e);
        }catch (Exception e) {
            throw new WorkflowException( "wf.error.couldNotDeleteClosedProcess", e);
        } finally {
            SharkUtils.disconnect(ea);
        }
        
    }

    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#deleteClosedProcesses(vkc.workflow.service.WfMConnection)
     */
    public void deleteClosedProcesses(WfMConnection sConn) throws WorkflowException {
        
        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
                .getExecutionAdministration();

        try {
            ea.connect(sConn.getUsername(), sConn.getPassword(), wfService
                    .getEngine(), "");

            ea.deleteClosedProcesses();
        } catch (NotConnected e) {
            throw new WorkflowException("wf.error.notConnected", e);
        } catch (Exception e) {
            throw new WorkflowException("wf.error.couldNotDeleteClosedProcesses",
                    e);
        } finally {
            SharkUtils.disconnect(ea);
}
        
    }

    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#getContextVariables(vkc.workflow.service.WfMConnection, java.util.Locale, java.lang.String, boolean)
     */
    public List getContextVariables(WfMConnection sConn, Locale locale,String procId, boolean onlyInitParameters) throws BaseException {
  
        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
										.getExecutionAdministration();
        AdminMisc am = wfService.getShark().getAdminInterface().getAdminMisc();
        List l = new ArrayList();
        try {
            am.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            ea.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            
            WfProcess process = ea.getProcess( procId );
            WfProcessMgr procMgr = process.manager();
            Map contextSig = WorkflowUtilities.
            	makeLinkedHashMap(procMgr.context_signature());
            
            NameValue [] context = process.process_context();
            
            for (int i = 0; i < context.length; i++) {
                NameValue nameValue = context[i];
                
                String varId = nameValue.the_name;
                Any varVal= nameValue.the_value;
                
                if(onlyInitParameters && !contextSig.containsKey(varId))
                    continue;
                
                String varType = ((CORBAWorklistManager)wfService.getWorklistManager())
                					.getVarType( varVal, procId, varId, am); 
                    
                VariableInfo varInfo = new VariableInfo(locale);
                varInfo.setId(varId);
                varInfo.setName( am.getVariableName(procId,varId));
                varInfo.setTypeKey(varType);
                varInfo.setDescription(am.getVariableDescription(procId,varId));
                varInfo.setReadOnly( false );
                
                if (varType.equals(WorkflowUtilities.UNKNOWN_KEY)) {
                    varInfo.setValue( varVal.toString() );
                    
                }else if (varType.equals(WorkflowUtilities.ENUMERATION_KEY)) {
                    varInfo.setValue( WorkflowUtilities.
                            extractChoicesFromDynEnum(varVal) );
                }else{
                    varInfo.setValue(WorkflowUtilities.
                            exstractValueOfAnyObject(nameValue.the_value,varType).toString());
                }

                
                l.add( varInfo );
            }
        } catch (Exception e) {
            throw new BaseException(e);
        } finally{
            SharkUtils.disconnect(am);
            SharkUtils.disconnect(ea);
        }
        return l;
    }

    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#updateInitialVariables(vkc.workflow.service.WfMConnection, java.lang.String, java.util.Map)
     */
    public void updateInitialVariables(WfMConnection sConn, String procId, Map vars) throws WorkflowException {
        if(vars == null || vars.isEmpty())
            return;
        
        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
										.getExecutionAdministration();
        AdminMisc am = wfService.getShark().getAdminInterface().getAdminMisc();
        
        try {
            am.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            ea.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            
            WfProcess process = ea.getProcess( procId );
            WfProcessMgr procMgr = process.manager();
            
            NameValue [] context = process.process_context();
            
            Map contextSig = WorkflowUtilities.
        		makeLinkedHashMap(procMgr.context_signature());
            
            ArrayList formalPars=new ArrayList();
            if (context!=null && context.length>0) {
               for (int i=0; i<context.length;i++) {
                  if (contextSig.containsKey(context[i].the_name)) {
                     formalPars.add(context[i]);
                  }
               }
            }
            if (formalPars.size()<1)
            	return;
            
            NameValue[] initContext=new NameValue[formalPars.size()];
            formalPars.toArray(initContext);
            
            
            
            for(int i = 0; i < initContext.length;i++){
                NameValue nameValue = initContext[i];
                
                Object newValue = vars.get(nameValue.the_name);
                if(newValue == null)
                    continue;
                
                String varType = ((CORBAWorklistManager)wfService.getWorklistManager())
									.getVarType( nameValue.the_value, procId, 
									        nameValue.the_name, am);
				
                Any a=WorkflowUtilities.insertValueIntoAnyObject(
                       nameValue.the_value, newValue.toString(),
                       varType);
                if (a!=null) {
                   nameValue.the_value=a;
                }
                 
            }
            
            process.set_process_context(initContext);
            
            
        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        }finally{
            SharkUtils.disconnect(am);
            SharkUtils.disconnect(ea);
        }
        
    }
    
    /** 
     * (non-Javadoc)
     * @see vkc.workflow.service.manager.ProcessManager#updateVariables(vkc.workflow.service.WfMConnection, java.lang.String, java.util.Map)
     */
    public void updateVariables(WfMConnection sConn, String procId, Map vars) throws WorkflowException {
        if(vars == null )
            return;
        
        ExecutionAdministration ea = wfService.getShark().getAdminInterface()
										.getExecutionAdministration();
        AdminMisc am = wfService.getShark().getAdminInterface().getAdminMisc();
        
        try {
            am.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            ea.connect( sConn.getUsername(), sConn.getPassword(), wfService.getEngine(), "");
            
            WfProcess process = ea.getProcess( procId );
            
            NameValue [] context = process.process_context();
            
            for(int i = 0;i < context.length; i++){

                NameValue nameValue = context[i];
                
                Object newValue = vars.get(nameValue.the_name);
                
                String varType = ((CORBAWorklistManager)wfService.getWorklistManager())
									.getVarType( nameValue.the_value, procId, 
									        nameValue.the_name, am);
				
                if(newValue == null){
                    
                    if( !WorkflowUtilities.BOOLEAN_KEY.equals(varType))
                        continue;
                    // Boolean, ist nicht in varMap enthalten, also auf false setzen
                    newValue = new String("false");
                }
                    
                
                Any a=WorkflowUtilities.insertValueIntoAnyObject(
                       nameValue.the_value, newValue.toString(),
                       varType);
                if (a!=null) {
                   nameValue.the_value=a;
                }
                
            }
            
            process.set_process_context(context);
            
            
        } catch (Exception e) {
            throw new WorkflowException( "wf.error.general", e);
        }finally{
            SharkUtils.disconnect(am);
            SharkUtils.disconnect(ea);
        }
        
    }
}