/*****************************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ****************************************************************************************/

package gov.va.med.esr.common.rule.parameter;

// Java classes
import gov.va.med.esr.common.model.cases.Assignment;
import gov.va.med.esr.common.model.cases.WorkflowCase;
import gov.va.med.esr.common.model.ee.PurpleHeart;
import gov.va.med.esr.common.model.ee.VerificationInfo;
import gov.va.med.esr.common.model.lookup.FunctionalGroup;
import gov.va.med.esr.common.model.lookup.WkfCaseType;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.workload.WorkflowCaseInfo;
import gov.va.med.esr.common.rule.WorkloadInput;
import gov.va.med.esr.service.UnknownLookupCodeException;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.service.trigger.MessageCaseTriggerEvent;
import gov.va.med.fw.rule.RuleException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

import java.util.Date;

import org.apache.commons.lang.Validate;

/**
 * Implements methods to create a work flow event. These methods are called by a rule
 * engine during an execution of specific business rules related to creating a work flow
 * event
 * 
 * @author Vu Le
 * @version 1.0
 */
public class WorkloadInputParameter extends AbstractTriggerAwareInputParameter implements
      WorkloadInput {

   /**
    * An instance of serialVersionUID
    */
   private static final long serialVersionUID = 8150949549518628909L;

   /**
    * Default constructor
    */
   public WorkloadInputParameter() {
      super();
   }

   public void createCaseIfZipCodeisInvalid(String oldZipCode, String newZipCode)
         throws RuleException {
      // No zipcode is provided - return
      if( StringUtils.isEmpty(newZipCode) )
         return;

      if( StringUtils.isNotEmpty(oldZipCode) && StringUtils.isNotEmpty(newZipCode)
            && ( oldZipCode.equals(newZipCode) ) ) {
         // zip codes have not changed
         return;
      }

      // verify that zip is valid
      try {
         if( getLookupService().getZipCodeByCode(newZipCode) != null ) {
            // Valid zip code no need to create a case
            return;
         }
      }
      catch( UnknownLookupTypeException e ) {
         throw new RuleException("UnknownLookupType", e);
      }
      catch( UnknownLookupCodeException e ) {
         // create case
      }

      // Create a new DQ case for updating reference data
      createWorkloadCase(FunctionalGroup.DQ.getCode(),
          WkfCaseType.CODE_APPLICATION_EXCEPTION.getCode(), null,
          "Update Reference Data Zip code " + newZipCode);
   }

   /**
    * Create workload case
    */

   public void createWorkloadCase(String groupType, String caseType, String issueType,
         String description) throws RuleException {
      Validate.notNull(groupType, "A Group type must not be null");
      Validate.notNull(caseType, "A case type must not be null");

      WorkflowCaseInfo caseInfo = getMessageCaseInfo();

      // Create a regular case if message info is not available
      if( caseInfo == null ) {
         caseInfo = new WorkflowCaseInfo();
         if (getPersonId() != null)
         {
             caseInfo.setPersonEntityKey(getPersonId());
         } else
         {
             caseInfo.setPersonEntityKey((PersonEntityKey)this.getIncomingPerson().getEntityKey());
         }
      }

      try {
         caseInfo.setErrorMessage(description);
         caseInfo.setGroupType(this.getLookupService()
               .getFunctionalGroupByCode(groupType));
         caseInfo.setCaseType(this.getLookupService().getWkfCaseTypeByCode(caseType));
         if( StringUtils.isNotEmpty(issueType) ) {
            caseInfo.setIssueType(this.getLookupService()
                  .getWkfIssueTypeByCode(issueType));
         }
         // Call the service to create the case. 
         //NOTE: the old code addTriggerEvent will not create multiple wkload cases for the same person id & person traits
         //VOA process can result in multiple wkcases -CCR 12092
         getWorkflowService().autoCreateCase(caseInfo);
         
      }
      catch( Exception e ) {
         if( this.logger.isDebugEnabled() ) {
            logger.debug("Case description: " + description);
            logger.debug("Case type: " + caseType);
            logger.debug("Failed to create case due to ", e);
         }
         throw new RuleException("Failed to create a case", e);
      }
   }

   /**
    * @see gov.va.med.esr.common.rule.WorkloadInput#assignPHCaseToAssignedLas()
    */
   public void assignPHCaseToAssignedLas() throws RuleException {
      try {
         // Get the PH case. Create one if needed.
         WorkflowCase wfCase = this.getWorkflowService().getWorkItem(
               this.getIncomingPerson(),
               this.getLookupService().getWkfCaseTypeByCode(
                     WkfCaseType.CODE_PURPLE_HEART.getCode()), true);
         if( wfCase != null ) {
            PurpleHeart ph = this.getIncomingPerson().getPurpleHeart();
            if( ph != null ) {
               // Assign the Las as designated by UI
               Assignment assignment = wfCase.getAssignment();
               //update assignment when assignment is changed or new assignment                           		   
               if (ph.getAssignedContactUser() != null && 
            	   (assignment.getAssignedTo() == null || 
            	   !ph.getAssignedContactUser().equals(assignment.getAssignedTo()))) {
            	   assignment.setAssignedTo(ph.getAssignedContactUser());
            	   assignment.setAssignmentDate(new Date());            	   
               }
                              
               if (wfCase.getEntityKey() != null)
                   this.getWorkflowService().update(wfCase);
               else
                   this.getWorkflowService().create(wfCase);
            }
         }
      }

      catch( ServiceException e ) {
         throw new RuleException("Failed to close a case", e);
      }
   }

   /**
    * @see gov.va.med.esr.common.rule.WorkloadInput#setWorkloadCaseToClosed()
    */
   public void setWorkloadCaseToClosed() throws RuleException {
      try {
         WorkflowCase wfCase = this.getWorkflowService().getWorkItem(
               this.getIncomingPerson(),
               this.getLookupService().getWkfCaseTypeByCode(
                     WkfCaseType.CODE_PURPLE_HEART.getCode()), false);
         if( wfCase != null ) {
            this.getWorkflowService().close(wfCase);
         }
      }

      catch( ServiceException e ) {
         throw new RuleException("Failed to close a case", e);
      }

   }

   private WorkflowCaseInfo getMessageCaseInfo() {
      VerificationInfo info = this.getAacInfo();
      WorkflowCaseInfo caseInfo = info != null ? info.getWorkflowCaseInfo() : null;
      // Set the Person entity if it is not set by the messaging
      if( caseInfo != null && caseInfo.getPersonEntityKey() == null ) {
         // set the person entity key on the object - not set by messaging
         caseInfo.setPersonEntityKey(getPersonId());
      }
      return caseInfo;
   }

}