package cust;

import wt.fc.*;
import wt.query.*;
import wt.util.*;
import wt.epm.EPMDocument;
import wt.part.WTPart;
import wt.folder.*;
import wt.method.*;

import wt.inf.container.*;
import wt.lifecycle.*;
import wt.enterprise.RevisionControlled;
import wt.vc.wip.*;

public class ReAssignLifeCycleNew {

    private static boolean VERBOSE;
    static {
        try {
            VERBOSE = WTProperties.getLocalProperties().getProperty("cust.ReAssignLifeCycleNew.verbose", false);
        }
        catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }

    public static void main (String[] args) {
        System.out.println("Args="+args.length);
        if (args.length !=6) {
            printUsage();
            System.exit (1);
        }
        String typeObj = null;
		String actualState = null;
		String targetState = null;
        String lifecyclename = null;
        Boolean forceLatestIteration = null;
        String container_path = null;
        String classNameStr = null;
        try {
            typeObj = args[0];
		    actualState = args[1];
		    targetState = args[2];
            lifecyclename = args[3];
            forceLatestIteration = new Boolean(args[4]);
            container_path = args[5];

            if (typeObj.equals("PART")) {
                classNameStr = "wt.part.WTPart";
            }
            else if (typeObj.equals("CADDOC")) {
                classNameStr = "wt.epm.EPMDocument";
            }
            else if (typeObj.equals("DOCUMENT")) {
                classNameStr = "wt.doc.WTDocument";
            }
        }
        catch (Throwable e) {
            printUsage();
            e.printStackTrace();
        }

        if (typeObj.equals("ALL")) {
		    reassignLF("wt.part.WTPart",actualState,targetState,lifecyclename,forceLatestIteration,container_path);
		    reassignLF("wt.epm.EPMDocument",actualState,targetState,lifecyclename,forceLatestIteration,container_path);
		    reassignLF("wt.doc.WTDocument",actualState,targetState,lifecyclename,forceLatestIteration,container_path);
			System.exit (1);
        }
        else {
			reassignLF(classNameStr,actualState,targetState,lifecyclename,forceLatestIteration,container_path);
        	System.exit (1);
		}
    }

    public static void reassignLF( String classNameStr, String validState, String targetState,
                      String lifecyclename, Boolean forceLatestIteration, String container_path) {

        long qrSize=0;
        long processedLFCount=0;
        long processedStateCount=0;
        long notProcessedCount=0;
        long notProcessedCOCount=0;
        long notProcessedErrorCount=0;

        try {
            // Init parameters to do the job
            Class theClass = Class.forName(classNameStr);
            WTContainerRef wtcontainerref = WTContainerHelper.service.getByPath(container_path);
            if (wtcontainerref == null) {
                System.out.println(" ReAssignLifeCycleNew => ERROR : Container not found.");
                return;
            }
            WTContainer container = wtcontainerref.getReferencedContainer();
            LifeCycleTemplateReference newLFRef = LifeCycleHelper.service.getLifeCycleTemplateReference(lifecyclename, wtcontainerref) ;
            if (newLFRef == null) {
                System.out.println(" ReAssignLifeCycleNew => ERROR : LifeCycle not found.");
                return;
            }
            LifeCycleTemplate newLF= (LifeCycleTemplate)newLFRef.getObject();
            if (WorkInProgressHelper.isCheckedOut((Workable)newLF) || WorkInProgressHelper.isWorkingCopy((Workable)newLF)) {
                System.out.println(" ReAssignLifeCycleNew => ERROR : LifeCycle template is checkedout.");
                return;
            }
            String newLFName = newLFRef.getName();
            java.util.Vector newLFStates = LifeCycleHelper.service.findStates((LifeCycleTemplate)newLFRef.getObject());


            // Build the Query to serach for appropriate object in appropriate container
            QuerySpec qs = new QuerySpec(theClass);
            if (container != null) {
                ClassAttribute docContainer = new ClassAttribute(theClass,(String)(theClass.getField("CONTAINER_ID").get(null)));
                qs.appendWhere(new SearchCondition(docContainer, SearchCondition.EQUAL, new ConstantExpression(new Long(PersistenceHelper.getObjectIdentifier(container).getId()))), new int[] {0});
                ClassAttribute cl = new ClassAttribute(theClass,(String)(theClass.getField("LATEST_ITERATION").get(null)));
			    RelationalExpression exp = ConstantExpression.newExpression("1",cl.getColumnDescriptor().getJavaType());
			    SearchCondition cond = new SearchCondition(cl,SearchCondition.EQUAL,exp);
			    qs.appendAnd();
			    qs.appendWhere(cond);
            }
            QueryResult qr = PersistenceHelper.manager.find(qs);
            qrSize = qr.size();
            printOut(" ReAssignLifeCycleNew => qr.size()=" + qrSize);

            // Process objects found in the queryresult
            while (qr.hasMoreElements()) {
                LifeCycleManaged lfmanaged=null;
                boolean error=false;
                String errorMessage=null;
                try {
                    lfmanaged = (LifeCycleManaged)qr.nextElement();
                    String actualState = lfmanaged.getState().toString();
                    printOut(" ReAssignLifeCycleNew => actualState="+actualState);

				    logInfo("\nINFO : object in process is " + getObjDisplayInfo((RevisionControlled)lfmanaged));
				    // Test if object is checkedout or working copy. If yes log error and skip.
                    if (WorkInProgressHelper.isCheckedOut((Workable)lfmanaged) || WorkInProgressHelper.isWorkingCopy((Workable)lfmanaged)) {
                        logInfo("\tERROR : object is checkedout or is workingcopy.");
                        logInfo("\t\t[NOT PROCESSED] : " + getObjDisplayInfo((RevisionControlled)lfmanaged));
                        notProcessedCOCount++;
                        continue;
                    }

				    // We must process only objects with state equals to validState passed in command or if validState=ALL
				    if (validState.equals("ALL") || actualState.equals(validState)) {
					    lfmanaged = (LifeCycleManaged)PersistenceHelper.manager.refresh(lfmanaged);
					    LifeCycleTemplateReference actualLFTemplate = lfmanaged.getLifeCycleTemplate();
					    String actualLFName = actualLFTemplate.getName();
					    printOut(" ReAssignLifeCycleNew => actualLFName="+actualLFName);

					    // We must test if the actual lifecycle assigned to the object is the same than the one passed in the command
					    //  and also to check if it's the latest iteration.
					    // We process if : (names are different) or (names are equal and LF obj Ids are different and forceLatestIteration is true)
					    boolean processLF=false;
					    if (!(actualLFName.equals(newLFName))) {
					        logInfo("\tINFO : lifecycle names are different, ready to proceed with new lifecycle.");
					        processLF = true;
					    }
					    else if (!(actualLFTemplate.toString().equals(newLFRef.toString())) &&
					             forceLatestIteration.equals(Boolean.TRUE)) {
					        logInfo("\tINFO : same lifecycle name but object not using latest lifecycle template iteration, ready to proceed with latest iteration.");
					        processLF = true;
					    }
					    else {
					        logInfo("\tINFO : object is already using the latest iteration of the lifecycle, or forceLatestIteration is FALSE.");
					        logInfo("\t\t[NOT PROCESSED] : " + getObjDisplayInfo((RevisionControlled)lfmanaged));
					        notProcessedCount++;
					    }
    					if (processLF) {
					        LifeCycleHelper.service.reassign(lfmanaged, newLFRef);
					        logInfo("\t\t[PROCESSED] : lifecycle [" + newLFName + "] reassigned to object [" + getObjDisplayInfo((RevisionControlled)lfmanaged) +"].");
        					processedLFCount++;
					        if (!targetState.equals("FIRST")) {
					            String newStateStr=targetState.equals("SAME")?actualState:targetState;
					            State newState = State.toState(newStateStr);
					            // test if state is valid for this lifecycle
					            if (!LifeCycleHelper.service.isState((LifeCycleTemplate)newLFRef.getObject(),newState)) {
					                logInfo("\t\t[NOT PROCESSED] : state [" + newStateStr + "]is not valid in new lifecycle.");
					            }
					            // test if state if the first state of the lifecycle. Don't process setLifeCycleState is yes.
					            printOut(" ReAssignLifeCycleNew => first state of new lifecycle=" + (newLFStates.get(0)).toString());
					            if (!(newLFStates.get(0)).toString().equals(newStateStr)) {
					                // Need to wait in order the workflow launched by the reassgin is running.
					                Thread.currentThread().sleep(200);

					                LifeCycleHelper.service.setLifeCycleState(lfmanaged,newState,true);
					                logInfo("\t\t[PROCESSED] : state [" + newStateStr + "] set to object [" + getObjDisplayInfo((RevisionControlled)lfmanaged) +"].");
					                processedStateCount++;
					            }
					        }
					    }
				    } // end if(actualState.equals("ALL...
				    else {
				        logInfo("\tINFO : object is not in a state valid for proceeding (based on command parameters).");
				        logInfo("\t\t[NOT PROCESSED] : lifecycle or state not set to " + getObjDisplayInfo((RevisionControlled)lfmanaged));
				        notProcessedCount++;
				    }
				}
				catch (LifeCycleException e) {
				    error=true;
				    errorMessage = e.getLocalizedMessage();
				}
				catch (wt.util.WTInvalidParameterException e) {
				    error=true;
				    errorMessage = e.getLocalizedMessage();
				}
				finally {
				    if (error) {
				        logInfo("\tERROR : an error occured during reassign of lifecycle or during setState.");
				        logInfo("\t\terror message = " + errorMessage);
				        logInfo("\t\t[NOT PROCESSED] : " + getObjDisplayInfo((RevisionControlled)lfmanaged));
				        notProcessedErrorCount++;
				        continue;  // just for understanding of the code !
				    }
				}
            } // end while
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            logInfo("\nINFO : results");
            logInfo("\t Objects to treat = " + qrSize);
            logInfo("\t Objects with lifecycle reassigned = " + processedLFCount);
            logInfo("\t Objects with state set = " + processedStateCount);
            logInfo("\t Objects not processed because not in scope of command = " + notProcessedCount);
            logInfo("\t Objects not processed because checkedout/workingcopy = " + notProcessedCOCount);
            logInfo("\t Objects not fully processed (lifecycle + state) because of error = " + notProcessedErrorCount);
        }
    } // end public static void reassignLF(...

    public static String getObjDisplayInfo(RevisionControlled obj) {
	    //7.0 code : String ret = "[" + obj.getClass().getName() + "] "+ obj.getName() + " [" + obj.getVersionLineage().getValue() + "] " + obj.getState() ;
	   String ret = obj.getIdentity() + " [" + obj.getVersionIdentifier().getValue() + "," + obj.getIterationIdentifier().getValue() + "] " + obj.getState();
	    return ret;
	}

    private static void printOut(String str) {
        if (VERBOSE)
            System.out.println(str);
    }

    private static void logInfo (String message) {
        // TO DO : implement log file
        System.out.println(message);
    }

    private static void printUsage() {
        System.out.println ("Usage 'windchill ext.generic.util.ReAssignLifeCycleNew [PART|CADDOC|DOCUMENT] <actual state to consider | ALL> <target state to set | SAME | FIRST> <new lifecycle name> <force latest lifecycle iteration> <container_path>");
        System.out.println (" Ex 1 :  windchill ext.generic.util.ReAssignLifeCycleNew CADDOC INWORK FIRST Default true /wt.inf.container.OrgContainer=PTC/wt.inf.library.WTLibrary=MYLIB ");
        System.out.println (" Ex 2 :  windchill ext.generic.util.ReAssignLifeCycleNew PART \"DEFINING REQUIREMENTS\" SAME Default true /wt.inf.container.OrgContainer=PTC/wt.pdmlink.PDMLinkProduct=MYPRODUCT ");
        System.out.println (" Ex 3 :  windchill ext.generic.util.ReAssignLifeCycleNew DOCUMENT ALL RELEASED ACME_lifecycle false /wt.inf.container.OrgContainer=PTC/wt.pdmlink.PDMLinkProduct=MYPRODUCT ");
    }
} // end class
