/********************************************************************
 * Copyright © 2004 EDS. All rights reserved
 ********************************************************************/
//Package
package gov.va.med.esr.messaging.builder.message;

//Java Classes

//Framework Classes
import gov.va.med.esr.common.model.ee.Application;
import gov.va.med.esr.common.model.ee.CancelDecline;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.lookup.EnrollmentSource;
import gov.va.med.esr.common.model.lookup.EnrollmentStatus;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.PreferredFacility;
import gov.va.med.esr.service.PreferredFacilityService;
import gov.va.med.fw.hl7.Segment;
import gov.va.med.fw.hl7.builder.HL7MetaData;
import gov.va.med.fw.hl7.constants.SegmentConstants;
import gov.va.med.fw.hl7.segment.ZEN;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.util.builder.BuilderException;

/**
 * Class to build the ZEN segment.
 * 
 * @author Alex Yoon
 * @version 1.0
 */
public class ZENBuilder extends AbstractSegmentBuilder {
    
    /**
    * An instance of serialVersionUID 
    */
   private static final long serialVersionUID = 6336028001312600263L;

   private PreferredFacilityService preferredFacilityService;
   /**
     * Default contructor.
     */
    public ZENBuilder() {
        super();
    }
    
    
    public PreferredFacilityService getPreferredFacilityService() {
	return preferredFacilityService;
}


public void setPreferredFacilityService(
		PreferredFacilityService preferredFacilityService) {
	this.preferredFacilityService = preferredFacilityService;
}


	/**
     * Method to build the ZEN segment.
     * 
     * @param metaData
     *           The parameter object used to build the a ZEN segment.
     * @return The ZEN segment.
     */
    public Object build(HL7MetaData metaData ) throws BuilderException {
        if((metaData == null) || 
           (metaData.getEntity() == null) ||
           !(metaData.getEntity() instanceof Person)) {
                throw new BuilderException("Invalid input parameter to build a segment");
        }
        
        ZEN segment = new ZEN();
        setDefaultValues(segment);
        
        segment.setSetID("1");
        
        Person person = (Person)metaData.getEntity();
        
        try {
            //Set segment attributes
            
            //Set EnrollmentDate, EnrollmentSource, EnrollmentPriority,
            //EffectiveDate, EnrollmentEndDate, EnrollmentSubGroup, facilityReceived
            this.setEnrollment(person, segment);
            
            segment.setEnrollmentStatus(buildEnrollmentStatus(person));
            
            //Set cancel/decline reason and remarks.
            this.setCancelDecline(person, segment);
            
            /* CCR10640 Preferred Facility. Share the most recent preferred facility with Vista */
            this.setPreferredFacility(person, segment); //(person.getPreferredFacility() != null) ? person.getPreferredFacility().getStationNumber() : null);
            segment.setEnrollmentApplicationDate(getApplicationDate(person));
        }
        catch (Exception e) {
            throw new BuilderException( "Failed to build ZEN Segment due to an exception ", e);
        }
        
        return segment;
    }
    
    protected void setDefaultValues(Segment segment) 
    {
        ZEN zen = (ZEN) segment;
        
        zen.setEnrollmentDate(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentSource(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentStatus(SegmentConstants.DEFAULT_VALUE);;        
        zen.setFacilityReceived(SegmentConstants.DEFAULT_VALUE);
        zen.setPreferredFacility(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentPriority(SegmentConstants.DEFAULT_VALUE);
        zen.setEffectiveDate(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentApplicationDate(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentEndDate(SegmentConstants.DEFAULT_VALUE);
        zen.setEnrollmentSubGroup(SegmentConstants.DEFAULT_VALUE);   
        
    }
    /**
     * Method that gets application date.
     * 
     * @param person
     *           The Person Object.
     * @return application date.
     */
 	private String getApplicationDate(Person person) {
 	    String applicationDate = null;
 	    
 	    Application application = person.getApplication();
 	    
 	    if (application != null) {
 	        applicationDate = DateFormatter.formatDate(application.getApplicationDate());
 	    }
 	    
 	    return applicationDate;
 	}
    
    /**
     * Method that sets EnrollmentDate, EnrollmentSource, EnrollmentPriority,
     * EffectiveDate, EnrollmentEndDate, and EnrollmentSubGroup.
     * 
     * @param person
     *           The Person Object.
     * @param segment
     *           The ZEN segment.
     */
    private void setEnrollment(Person person, ZEN segment) throws Exception {
        String enrollmentDate = null;
        String enrollmentSource = null;
        String enrollmentPriority = null;
        String enrollmentEffectiveDate = null;
        String enrollmentEndDate = null;
        String enrollmentSubgroup = null;
        String facilityReceived = null;
        
        //Get EnrollmentDetermination object
        EnrollmentDetermination enrollment = getHelperService().getEnrollmentDetermination(person);
        
        if (enrollment != null) {
            enrollmentDate = DateFormatter.formatDate(enrollment.getEnrollmentDate());
            enrollmentSource = this.buildEnrollmentSourceCode(enrollment.getCalculationSource());
            
            enrollmentPriority = enrollment.getPriorityGroup() != null ? enrollment.getPriorityGroup().getCode() : null;
            enrollmentSubgroup = enrollment.getPrioritySubGroup() != null ? enrollment.getPrioritySubGroup().getCode() : null;
            
            enrollmentEffectiveDate = DateFormatter.formatDate(enrollment.getEffectiveDate());
            enrollmentEndDate = DateFormatter.formatDate(enrollment.getEndDate());
            
            facilityReceived = enrollment.getFacilityReceived() == null ? null:enrollment.getFacilityReceived().getStationNumber();
            
        }
        segment.setEnrollmentDate(enrollmentDate);
        segment.setEnrollmentSource(enrollmentSource);
        segment.setFacilityReceived(facilityReceived);
        segment.setEnrollmentPriority(enrollmentPriority);
        segment.setEffectiveDate(enrollmentEffectiveDate);
        segment.setEnrollmentEndDate(enrollmentEndDate);
        segment.setEnrollmentSubGroup(enrollmentSubgroup);
    }
    
    /**
     * Method that sets cancel/decline reason and remarks.
     * 
     * @param person
     *           The Person Object.
     * @param segment
     *           The ZEN segment.
     */
    private void setCancelDecline(Person person, ZEN segment) throws Exception {
                
        EnrollmentStatus enrollmentStatus = person.getEnrollmentDetermination() == null ? null
                : person.getEnrollmentDetermination().getEnrollmentStatus();
        
        if (enrollmentStatus != null)        	 
        {
        	//If ESR changes the enrollment status to something other than 
        	//Cancelled/Declined, then cancel decline reason will be stored in the database but will not be sent out.  
        	if(StringUtils.equals(enrollmentStatus.getCode(), EnrollmentStatus.CODE_CANCELLED_DECLINED.getCode()))
        	{
	            CancelDecline cancel = person.getCancelDecline();	            
	            if (cancel != null) {
	            	segment.setReason(cancel.getReason() == null ? null: cancel.getReason().getCode());
	                segment.setRemarks(cancel.getRemarks());
	            }
        	}
        }else {
        	//If enrollmentStatus is null, set double quotes
        	segment.setReason(SegmentConstants.DEFAULT_VALUE);
            segment.setRemarks(SegmentConstants.DEFAULT_VALUE);
        }
        
    }
    
    /**
     * Method that builds enrollment status code
     * 
     * @param person
     *           The Person Object.
     * @return enrollment status code.
     */
    private String buildEnrollmentStatus(Person person) throws Exception {
        String enrollmentStatusCode = null;
        
        EnrollmentStatus enrollmentStatus = person.getEnrollmentDetermination() == null ? null
                : person.getEnrollmentDetermination().getEnrollmentStatus();
 
        if (enrollmentStatus != null) {
            enrollmentStatusCode = super.build(enrollmentStatus);
        }
        
        return enrollmentStatusCode;
    }
    
    /**
     * Method that builds enrollment source code.
     * 
     * @param source
     *           The EnrollmentSource Object.
     * @return enrollment source code.
     */
    private String buildEnrollmentSourceCode(EnrollmentSource source) throws BuilderException {
        return super.build(source);
    }
    
    /**
     * CCR10640 -- preferred facility. 
     * 
     * Check if there is at least one record in preferred_facility table with PF_assignment_end_date as null or future dated. 
     * If there is one, share that with VistA. If there is one or more, select the one with the most recent PF_assignment_start_date 
     * and the source designation.
	 * If there is no record with PF_Assignment_end_date as null, select the one with the most recent 
	 * PF_assignement_end_date and the source designation. 

     * @param person
     * @param segment
     * @throws Exception
     */
    private void setPreferredFacility(Person person, ZEN segment) throws Exception {
    	PreferredFacility mostRecent = this.getPreferredFacilityService().getMostRecentPreferredFacility(person);
    	if (mostRecent != null) {
    		segment.setPreferredFacility(mostRecent.getFacility().getStationNumber());
    		segment.setSourceDesignation(mostRecent.getSourceDesignation().getCode());
    	}
    }
}