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

//Java Classes
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

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.ZMH;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.ee.CombatEpisode;
import gov.va.med.esr.common.model.ee.MilitaryService;
import gov.va.med.esr.common.model.ee.MilitaryServiceEpisode;
import gov.va.med.esr.common.model.ee.MilitaryServiceSiteRecord;
import gov.va.med.esr.common.model.ee.POWEpisode;
import gov.va.med.esr.common.model.ee.PrisonerOfWar;
import gov.va.med.esr.common.model.ee.PurpleHeart;
import gov.va.med.esr.common.model.ee.MedalOfHonor;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.MilitaryServiceQueryStatus;
import gov.va.med.esr.common.model.lookup.ServicePeriod;
import gov.va.med.esr.common.model.person.Person;

/**
 * Class to build the ZMH segment.
 *
 * @author Alex Yoon
 * @version 1.0
 */
public class ZMHBuilder extends AbstractSegmentBuilder {
    /**
    * An instance of serialVersionUID
    */
   private static final long serialVersionUID = -6131162998748748108L;
   private Builder dischargeTypeBuilder;
    private Builder serviceBranchBuilder;
    private Builder oefoifSourceBuilder;

    private static final String MILITARY_HISTORY_TYPE_PH = "PH";
    private static final String MILITARY_HISTORY_TYPE_POW = "POW";
    private static final String MILITARY_HISTORY_TYPE_OEIF = "OEIF";
    private static final String  MILITARY_HISTORY_TYPE_SL="SL";
    private static final String  MILITARY_HISTORY_TYPE_SNL="SNL";
    private static final String  MILITARY_HISTORY_TYPE_SNNL="SNNL";
    private static final String  MILITARY_HISTORY_TYPE_MSD="MSD";
    private static final String  MILITARY_HISTORY_TYPE_MOH = "MH";

    /**
     * Default contructor.
     */
    public ZMHBuilder() {
        super();
    }

    public Builder getDischargeTypeBuilder()
    {
        return this.dischargeTypeBuilder;
    }

    public void setDischargeTypeBuilder(
        Builder dischargeTypeBuilder)
    {
        this.dischargeTypeBuilder = dischargeTypeBuilder;
    }

    public Builder getServiceBranchBuilder()
    {
        return this.serviceBranchBuilder;
    }

    public void setServiceBranchBuilder(
        Builder serviceBranchBuilder)
    {
        this.serviceBranchBuilder = serviceBranchBuilder;
    }


    public Builder getOefoifSourceBuilder() {
		return this.oefoifSourceBuilder;
	}

	public void setOefoifSourceBuilder(Builder oefoifSourceBuilder) {
		this.oefoifSourceBuilder = oefoifSourceBuilder;
	}

	/**
     * Method to build the ZMH segment.
     *
     * @param metaData
     *           The parameter object used to build the a ZMH segment.
     * @return The ZMH 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");
        }

        List segments = new ArrayList();
        Person person = (Person)metaData.getEntity();

        try {
            //Create ZMH segment with POW and Purple Heart MSDS related information.
        	//CCR8369-Create Message, if the Military Service Data Sharing (MSDS) query status is
        	//“Queried – Pending Response”  or if the query status is null then the Z11
        	//will exclude the Military Service Episodes according to the Interface Control Document

        	//Change Request 287630 removes above rules to always share ZMH from HEC episodes regardless of
        	//what the MSDS query status is due to changes from regOnce to enterpriseRegistration

        	setMsdSegments(person, segments);

        	//commented below for CR 287630 as noted above, WI # 294530

        	/*MilitaryService militaryService=person.getMilitaryService();
        	if (militaryService !=null && militaryService.getMilitaryServiceQueryStatus() !=null){
        		MilitaryServiceQueryStatus queryStatus=militaryService.getMilitaryServiceQueryStatus();
        		if(queryStatus != null && !(queryStatus.getCode().equals(MilitaryServiceQueryStatus.QUERIED_PENDING_RESPONSE.getCode()))){
        			setMsdSegments(person, segments);
        		}
        	}*/

        	setPrisonerOfWar(person, segments);
            setPurpleHeart(person, segments);
            setCombatEpisodes(person, segments);
            setMedalOfHonor(person, segments);

            // Set setID attribute for all segments in the array.
			for (int i = 0; i < segments.size(); i++)
			{
				((ZMH) segments.get(i)).setSetID(String.valueOf(i + 1));
			}
        }
        catch (Exception e) {
            throw new BuilderException( "Failed to build ZMH Segment due to an exception ", e);
        }

        return segments;
    }
    private void setMsdSegments(Person person, List segments) throws Exception {
    	// Get MilitaryService object.

    	MilitaryService militaryService = person.getMilitaryService();
    	MilitaryServiceSiteRecord militaryServiceSiteRecord = (MilitaryServiceSiteRecord) militaryService.getHECMilitaryServiceSiteRecord();
    	int counter = 0;

    	if(militaryServiceSiteRecord != null && militaryServiceSiteRecord
    			.getMilitaryServiceEpisodes() != null && !militaryServiceSiteRecord
    			.getMilitaryServiceEpisodes().isEmpty()){

    		Set militaryServiceEpisodeSet = militaryServiceSiteRecord
    		.getMilitaryServiceEpisodes();

    		Iterator iteratormilitaryServiceEpisode = sortServiceSeparationDateRecentToOld(militaryServiceEpisodeSet)
    		.iterator();
    		while (iteratormilitaryServiceEpisode.hasNext()) {
    			ZMH segment = new ZMH();
    			counter = counter + 1;
    			MilitaryServiceEpisode militaryServiceEpisode = (MilitaryServiceEpisode) iteratormilitaryServiceEpisode
    			.next();

    			if (counter == 1) {
    				segment
    				.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_SL);
    			} else if (counter == 2) {
    				segment
    				.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_SNL);
    			} else if (counter == 3) {
    				segment
    				.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_SNNL);
    			} else{
    				segment
    				.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_MSD);
    			}
    			segment.setServiceIndicator((ElementFormatter.formatCodedElement( militaryServiceEpisode.getServiceBranch() !=null &&
    					militaryServiceEpisode.getServiceBranch().getDescription() !=null ?
    							militaryServiceEpisode.getServiceBranch().getDescription():null,
    							militaryServiceEpisode.getServiceNumber() !=null?militaryServiceEpisode.getServiceNumber():null,
    									militaryServiceEpisode.getDischargeType() !=null &&	militaryServiceEpisode.getDischargeType().getDescription() !=null ?
    											militaryServiceEpisode.getDischargeType().getDescription():null)));
    			segment
    			.setServiceEntryDateAndServiceSeparationDate(ElementFormatter
    					.formatCodedElement(
    							DateFormatter
    							.formatDate(militaryServiceEpisode
    									.getStartDate()),
    									DateFormatter
    									.formatDate(militaryServiceEpisode
    											.getEndDate())));
    			if(militaryServiceEpisode !=null && militaryServiceEpisode.getMilitaryServiceComponent() !=null &&
    					militaryServiceEpisode.getMilitaryServiceComponent().getDescription() !=null){
    				segment.setServiceComponent(militaryServiceEpisode.getMilitaryServiceComponent().getCode());

    			}
    			segments.add(segment);

    		}

    	}

    }

    /**
	 * Method that sets Eligibility Status and Date
	 *
	 * @param person
	 *            The Person Object.
	 * @param segments
	 *            The List object. test
	 */
    private void setPurpleHeart(Person person, List segments) throws Exception {
        //Get PurpleHeart object.
        PurpleHeart ph = getHelperService().getPurpleHeart(person);

        if (ph != null) {
            ZMH segment = new ZMH();
            String phIndicator = null;
            String rejectedRemarks = null;

            if (ph.getRejectionRemark() == null) {
                phIndicator = "Y";

            }
            else {
                phIndicator = "N";
                rejectedRemarks = super.build(ph.getRejectionRemark());
            }

	        //Set segment attributes.
	        segment.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_PH);
	        segment.setServiceIndicator((ElementFormatter.formatCodedElement(phIndicator,
	                ph.getStatus() == null ? null:ph.getStatus().getCode(), rejectedRemarks)));
	        segment.setServiceEntryDateAndServiceSeparationDate(null);

	        segments.add(segment);
        }
    }

    /**
     * James Picklesimer
     * Method that sets MOH indicator
     * MedalOfHonor
     * @param person
     *            The Person Object.
     * @param segments
     *            The List object. test
     */
    private void setMedalOfHonor(Person person, List segments) throws Exception {

        MedalOfHonor moh = person.getMedalOfHonor();
        if (moh != null) {
            Boolean mohIndicator = moh.getMhIndicator();
            //If MOH Indicator is null or unknown, no ZMH needs to be sent out
            if (mohIndicator == null || StringUtils.equals(Indicator.UNKNOWN.getCode(), String.valueOf(mohIndicator)))
                return;
            ZMH segment = new ZMH();
            segment.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_MOH);
            if (mohIndicator.booleanValue() == true) {
             segment.setServiceIndicator("Y");
            } else {
             segment.setServiceIndicator("N");
            }
            segment.setServiceEntryDateAndServiceSeparationDate(null);
            // add to list of segments
            segments.add(segment);
        }

    }




    private void setPrisonerOfWar(Person person, List segments)
			throws Exception {
		// Get PurpleHeart object.
		PrisonerOfWar pow = person.getPrisonerOfWar();

		if (pow != null) {

			Indicator powIndicator = pow.getPowIndicator();

			//If POW Indicator is null or unknown, no ZMH needs to be sent out
			if (powIndicator == null || StringUtils.equals(Indicator.UNKNOWN.getCode(), powIndicator.getCode()))
				return;

			ZMH segment = new ZMH();
			segment.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_POW);

			String indicator = buildBooleanFor0136FromIndicator(pow
					.getPowIndicator());

			if (StringUtils.equals(Indicator.NO.getCode(), pow.getPowIndicator().getCode())) {
				segment.setServiceIndicator(ElementFormatter.formatCodedElement(indicator,null));
				segment.setServiceEntryDateAndServiceSeparationDate(ElementFormatter.formatCodedElement(null , null));

				segments.add(segment);

			} else if (StringUtils.equals(Indicator.YES.getCode(), pow.getPowIndicator().getCode())) {

				// If the veteran has more than one POW Episode then the system
				// shall transmit the POW episode information that has the most
				// current Capture and Release Dates.
				Set episodes = pow.getEpisodes();
				List episodesAsList = new ArrayList();

				POWEpisode mostRecentEpisode = null;

				if (episodes != null && !episodes.isEmpty()) {
					for (Iterator iter = episodes.iterator(); iter.hasNext();) {
						POWEpisode episode = (POWEpisode) iter.next();
						episodesAsList.add(episode);
					}
					Collections.sort(episodesAsList,
							new POWEpisodeDateComparator());

					mostRecentEpisode = (POWEpisode) episodesAsList
							.get(episodesAsList.size() - 1);
				}

				// Set segment attributes.
				// Create a ZMH  for POW only if a POW episode exists.
				if (mostRecentEpisode != null) {
					segment.setServiceIndicator(
							ElementFormatter.formatCodedElement(indicator,
									(mostRecentEpisode.getConfinementLocation() == null ? null :
										mostRecentEpisode.getConfinementLocation().getCode())));

					segment.setServiceEntryDateAndServiceSeparationDate(ElementFormatter.formatCodedElement(
							DateFormatter.formatDate(mostRecentEpisode.getCaptureDate()),
									DateFormatter.formatDate(mostRecentEpisode.getReleaseDate())));

					segments.add(segment);

				}
			}
		}
	}
   /**
	 * Create ZMH Segments for Combat Episodes
	 *
	 * @param person
	 * @param segments
	 */
   private void setCombatEpisodes(Person person, List segments) throws Exception{
	   MilitaryService ms = person.getMilitaryService();
	   Set combatEpisodes = ms.getCombatEpisodes();
	   if (combatEpisodes != null && combatEpisodes.size() > 0) {
		   //create the table
		   for (Iterator i=combatEpisodes.iterator(); i.hasNext();) {
	       	   CombatEpisode episode = (CombatEpisode)i.next();
	       	   String location = episode.getConflictLocation() == null ? null :episode.getConflictLocation().getDescription();

	       	   //The location is not a valid one to be included in the message
	       	   if (location == null)
	       		   continue;

	            ZMH segment = new ZMH();
		        segment.setMilitaryHistoryType(MILITARY_HISTORY_TYPE_OEIF);
		        //location~facility(source)~unused

		        String oefoifSource =
		        	super.build(oefoifSourceBuilder,episode.getOEFOIFSource());

		        //Source is set from the UI (CEV/EM/FHIE/VIS). Station number is set from the message.
		        //If source is set as Do not share if it is CEV/EM/FHIE/VIS.
		        if (oefoifSource == null && episode.getOEFOIFStationNumber() != null){

		        	oefoifSource = episode.getOEFOIFStationNumber().getStationNumber();

		        } else {
		        	//source is not shared with other sites
		        	oefoifSource = null;
		        }
		        //location, source
		        segment.setServiceIndicator(location + "~" + (oefoifSource == null ? "" : oefoifSource));

		        //start and end dates
		        String dateRange = DateFormatter.formatDate(episode.getStartDate()) + "~"
                				 + DateFormatter.formatDate(episode.getEndDate());
		        segment.setServiceEntryDateAndServiceSeparationDate(dateRange);
		        segments.add(segment);
       	    }
       }
   }

   protected void setDefaultValues(Segment segment)
   {
       ZMH zmh = (ZMH)segment;
       zmh.setMilitaryHistoryType(SegmentConstants.DEFAULT_VALUE);
       zmh.setServiceIndicator(SegmentConstants.DEFAULT_VALUE);
       zmh.setServiceEntryDateAndServiceSeparationDate(SegmentConstants.DEFAULT_VALUE);
   }
    private class POWEpisodeDateComparator  implements java.util.Comparator {

        public int compare(Object o1, Object o2) {
        POWEpisode pow1 = (POWEpisode) o1;
        POWEpisode pow2 = (POWEpisode) o2;

        return pow1.getCaptureDate().compareTo(pow2.getCaptureDate());

      }
    }

    private List sortServiceSeparationDateRecentToOld(Collection incomingMSEs)
	{
		List sortedIncomingMSEs = new ArrayList();
	    if(incomingMSEs != null && !incomingMSEs.isEmpty()) {
	    	sortedIncomingMSEs.addAll(incomingMSEs);
	        Comparator comparator = new Comparator() {
	            public int compare(Object pObject1, Object pObject2) {
	                Date date1 = (pObject1 instanceof MilitaryServiceEpisode) ? ImpreciseDateUtils.getDateWithDefault(((MilitaryServiceEpisode)pObject1).getEndDate()) : null;
	                Date date2 = (pObject2 instanceof MilitaryServiceEpisode) ? ImpreciseDateUtils.getDateWithDefault(((MilitaryServiceEpisode)pObject2).getEndDate()) : null;
	                return (date1 != null && date2 != null) ? (-date1.compareTo(date2)) : 0;
	            }
	        };
	        Collections.sort(sortedIncomingMSEs,comparator);
	    }
	    return sortedIncomingMSEs;
	}
}