/*******************************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ******************************************************************************/
package gov.va.med.esr.common.rule.parameter;

// Java classes
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

// Library classes
import org.apache.commons.lang.ObjectUtils;

// Framework classes
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.rule.RuleException;
import gov.va.med.fw.service.ServiceException;

// EDB Classes
import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
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.PrisonerOfWar;
import gov.va.med.esr.common.model.ee.POWEpisode;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.PrisonerOfWarLocation;
import gov.va.med.esr.common.model.lookup.RegistryType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.registry.Registry;
import gov.va.med.esr.common.persistent.registry.RegistryDAO;
import gov.va.med.esr.common.rule.PrisonerOfWarInput;
import gov.va.med.esr.common.rule.data.POWInputData;
import gov.va.med.esr.common.infra.PreciseDateUtils;

/**
 * @author Yi He
 * @version 1.0
 */
public class PrisonerOfWarInputParameter extends BaseParameter implements
        PrisonerOfWarInput {

    private POWEpisode powEpisode = null;

    private String registryDaoName = null;

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

    /**
     * 
     */
    public PrisonerOfWarInputParameter() {
        super();
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#isPrisonerOfWarRecordDiscrepant()
     */
    public boolean isPrisonerOfWarRecordDiscrepant() {
        if (logger.isDebugEnabled())
            logger.debug("+isPrisonerOfWarRecordDiscrepant");

        PrisonerOfWar incoming = this
                .getPrisonerOfWar(this.getIncomingPerson());
        PrisonerOfWar onFile = this.getPrisonerOfWar(this.getPristinePerson());
        Iterator iterIncoming = incoming != null ? incoming.getEpisodes()
                .iterator() : null;
        POWInputData data = this.getPOWInputData();
        if (iterIncoming != null) {
	        while (iterIncoming.hasNext()) {
	            POWEpisode incomingPOWEpisode = (POWEpisode) iterIncoming.next();
	            if (data != null) {
	                data.setPowEpisode(incomingPOWEpisode); // for later use in
	                                                        // bulletin
	            }
	            if (incomingPOWEpisode.getConfinementLocation() == null) {
	                if (logger.isDebugEnabled())
	                    logger.debug("confinement location is null");
	                return true;
	            }
	            Iterator iterOnFile = onFile != null ? onFile.getEpisodes()
	                    .iterator() : null;
	            if (iterOnFile != null) {
	                while (iterOnFile.hasNext()) {
	                    POWEpisode onFilePOWEpisode = (POWEpisode) iterOnFile
	                            .next();
	                    if (incomingPOWEpisode.getConfinementLocation().equals(
	                            onFilePOWEpisode.getConfinementLocation())) {
	                        if (ObjectUtils.equals(incomingPOWEpisode
	                                .getCaptureDate(), onFilePOWEpisode
	                                .getCaptureDate())
	                                && ObjectUtils.equals(incomingPOWEpisode
	                                        .getReleaseDate(), onFilePOWEpisode
	                                        .getReleaseDate()))
	                            return false;
	                        else {
	                            if (logger.isDebugEnabled())
	                                logger
	                                        .debug("start date or end date is discrepant");
	                            return true;
	                        }
	                    } else {
	                        if (logger.isDebugEnabled())
	                            logger.debug("confinement location is discrepant");
	                    }
	                }
	            }
	        }
        }
        if (logger.isDebugEnabled())
            logger.debug("-isPrisonerOfWarRecordDiscrepant");
        return true;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPrisonerOfWarIndicator()
     */
    public Boolean getPrisonerOfWarIndicator() {
        return this.getPrisonerOfWarIndicator(this.getIncomingPerson());
    }

    public Boolean getPrisonerOfWarIndicator(Person person) {
    	//ccr 10434 adding null check in pow.getPowIndicator().toBoolean()
        PrisonerOfWar pow = person !=null? this.getPrisonerOfWar(person):null;
        if (pow != null && pow.getPowIndicator() != null && pow.getPowIndicator().toBoolean() !=null) {
            return pow.getPowIndicator().toBoolean();
        }
         return Boolean.FALSE;
    }
  
    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getVeteranPrisonerOfWarIndicator()
     */
    public Boolean getVeteranPrisonerOfWarIndicator() {
        return getPrisonerOfWarIndicator(this.getPristinePerson());
       }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPOWIndicatorCode()
     */
    public String getPOWIndicatorCode() {
        PrisonerOfWar pow = this.getPrisonerOfWar(this.getIncomingPerson());
        if (pow != null && pow.getPowIndicator() != null) {
            return pow.getPowIndicator().getCode();
        }
        return null;
    }
 
    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getVeteranPOWIndicatorCode()
     */
    public String getVeteranPOWIndicatorCode() {
        PrisonerOfWar pow = this.getPrisonerOfWar(this.getPristinePerson());
        if (pow != null && pow.getPowIndicator() != null) {
            return pow.getPowIndicator().getCode();
        }
        return null;
    }
    public boolean isPrisonerOfWarIndicatorChanged()throws RuleException{
    	//10434.
    	 boolean result=getPrisonerOfWarIndicator(getResultPerson()).booleanValue();
         boolean prior=getPrisonerOfWarIndicator(getPristinePerson()).booleanValue();
         if (prior!= result ){
        	return true;
          }
        	 return false;
        
    }
    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#updatePrisonerOfWar()
     */
    public void updatePrisonerOfWar() throws RuleException {

        try {
            PrisonerOfWar pow = this.getPrisonerOfWar(this.getIncomingPerson());
            if (pow != null) {
                Set episodes = pow.getEpisodes();
                for (Iterator iter = episodes.iterator(); iter.hasNext();) {
                    POWEpisode powe = ((POWEpisode) iter.next());
                    Integer days = null;
                    if (powe.getCaptureDate() != null
                            && powe.getCaptureDate().isPrecise()
                            && powe.getReleaseDate() != null
                            && powe.getReleaseDate().isPrecise()) { // Only
                                                                    // calculate
                                                                    // if both
                                                                    // capture
                                                                    // date and
                                                                    // release
                                                                    // date are
                                                                    // precise
                        days = calculateCaptivityDays(powe.getCaptureDate()
                                .getDate(), powe.getReleaseDate().getDate());
                    }
                    powe.setNumberOfDaysInCaptivity(days);
                    if (powe.getDateEntered() == null)
                        powe.setDateEntered(this.getCurrentDate());
                }
            }
            this.getMergeRuleService().mergePrisonerOfWar(pow,
                    this.getResultPerson());
        } catch (ServiceException e) {
            throw new RuleException("Failed to merge prisoner of war record", e);
        }
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#calculateCaptivityDays()
     */
    public Integer calculateCaptivityDays() {
        // TODO remove since not used in rules
        return null;
    }

    public Integer calculateCaptivityDays(Date capture, Date release) {

        // Only calculate if both capture and release are not null
        if (capture != null && release != null) {
            Calendar captureCalendar = Calendar.getInstance();
            captureCalendar.setTime(capture);
            Calendar releaseCalendar = Calendar.getInstance();
            releaseCalendar.setTime(release);
            return new Integer(PreciseDateUtils.getDays(captureCalendar,
                    releaseCalendar).intValue());
        }

        return null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPOWEntityKey()
     */
    public EntityKey getPOWEntityKey() {
        PrisonerOfWar prisonerOfWar = this.getPrisonerOfWar(this
                .getIncomingPerson());
        return prisonerOfWar != null ? prisonerOfWar.getEntityKey() : null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPristinePOWEntityKey()
     */
    public EntityKey getPristinePOWEntityKey() {
        PrisonerOfWar pristine = this
                .getPrisonerOfWar(this.getPristinePerson());
        return pristine != null ? pristine.getEntityKey() : null;
    }

    public POWEpisode getIncomingPOWEpisode() {
        if (powEpisode == null) {
            if (this.getPOWInputData() != null) {
                this.powEpisode = this.getPOWInputData().getPowEpisode();
            }
        }
        return this.powEpisode;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPristineConfirmedStatus()
     */
    public String getPristineConfirmedStatus() {
        // TODO REMOVE this since not in BOM
        return null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#removePOWRecord()
     */
    public void removePOWRecord() {
        this.getResultPerson().setPrisonerOfWar(null);
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#setCapitivityDays(java.lang.Integer)
     */
    public void setCapitivityDays(Integer days) {
        // TODO remove since not referenced in rules
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getCapturedate()
     */
    public ImpreciseDate getCaptureDate() {
        POWEpisode powe = this.getIncomingPOWEpisode();
        return powe != null ? powe.getCaptureDate() : null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getConfinementLocation()
     */
    public String getConfinementLocation() {
        POWEpisode powe = this.getIncomingPOWEpisode();
        PrisonerOfWarLocation prisonerOfWarLocation = (powe != null) ? powe
                .getConfinementLocation() : null;
        return prisonerOfWarLocation != null ? prisonerOfWarLocation.getCode()
                : null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getReleaseDate()
     */
    public ImpreciseDate getReleaseDate() {
        POWEpisode powe = this.getIncomingPOWEpisode();
        return powe != null ? powe.getReleaseDate() : null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#getPriorPrisonerOfWarIndicator()
     */
    public Boolean getPriorPrisonerOfWarIndicator() throws RuleException {
        Person priorPerson = this.getPriorEEPerson();
        if (priorPerson != null) {
            PrisonerOfWar pow = this.getPrisonerOfWar(priorPerson);
            if (pow != null && pow.getPowIndicator() != null) {
                return pow.getPowIndicator().toBoolean();
            }
        }
        return Boolean.FALSE;
    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.esr.common.rule.PrisonerOfWarInput#isPOWCaptureAndReleaseDatesValid()
     */
    public Boolean isCaptureAndReleaseDateswithinMSE() throws RuleException {
        // TODO activate if the requirements are confimred
        if (true)
            return Boolean.TRUE;

        // if required values are available validate
        if (getCaptureDate() != null || getReleaseDate() != null) {

            // Convert Imprecise dates to dates for comparison with default
            // values
            Date captureDate = ImpreciseDateUtils
                    .getDateWithDefault(getCaptureDate());
            Date releaseDate = ImpreciseDateUtils
                    .getDateWithDefault(getReleaseDate());

            // Get Military Service Episodes from HEC Record
            Set msEpisodes = getMilitrayServiceEpisodes(this
                    .getIncomingPerson());

            if (msEpisodes != null && msEpisodes.size() > 0) {
                for (Iterator i = msEpisodes.iterator(); i.hasNext();) {
                    MilitaryServiceEpisode msEpisode = (MilitaryServiceEpisode) i
                            .next();
                    ImpreciseDate startDate = msEpisode.getStartDate();
                    ImpreciseDate endDate = msEpisode.getEndDate();
                    if (startDate == null || endDate == null) {
                        // Episode has invalid dates (shouldn't happen)
                        continue;
                    }
                    Date mseStartDate = ImpreciseDateUtils
                            .getDateWithDefault(startDate);
                    Date mseEndDate = ImpreciseDateUtils
                            .getDateWithDefault(endDate);
                    // validate that confinement persion is within this MSE
                    if (isInRange(captureDate, mseStartDate, mseEndDate)
                            && isInRange(releaseDate, mseStartDate, mseEndDate)) {
                        return Boolean.TRUE;
                    }
                }
            }
        }
        return Boolean.FALSE;
    }

    public Registry getPOWRegistry(Person person) throws RuleException {
        try {
            if (person != null) {
                RegistryType registryType = (RegistryType) this
                        .getLookupService().getByCode(RegistryType.class,
                                RegistryType.CODE_POW_REGISTRY.getCode());
                return this.getRegistryDAO().getRegistry(person, registryType);
            }
        } catch (Exception ex) {
            throw new RuleException("Error while getting the registry", ex);
        }
        return null;
    }

    /**
     * Get HEC Military Service Episodes
     * 
     * @param person
     * @return
     */
    private Set getMilitrayServiceEpisodes(Person person) {

        MilitaryService ms = person.getMilitaryService();

        Set mse = new HashSet();
        // Add all episodes from all site records including HEC
        if (ms != null) {
            for (Iterator iter = ms.getMilitaryServiceSiteRecords().iterator(); iter
                    .hasNext();) {
                MilitaryServiceSiteRecord msHECRecord = (MilitaryServiceSiteRecord) iter
                        .next();

                if (msHECRecord != null) {
                    mse.addAll(msHECRecord.getMilitaryServiceEpisodes());
                }
            }
        }
        return mse;
    }

    private boolean isInRange(Date date, Date lower_range, Date upper_range) {
        if ((date.equals(lower_range) || date.after(lower_range))
                && (date.equals(upper_range) || date.before(upper_range))) {
       
            return true;
        }
        return false;
    }

    private PrisonerOfWar getPrisonerOfWar(Person person) {
        return person.getPrisonerOfWar();
    }

    public void setRegistryDaoName(String registryDaoName) {
        this.registryDaoName = registryDaoName;
    }

    private RegistryDAO getRegistryDAO() throws ServiceException {
        return (RegistryDAO) this.getComponent(this.registryDaoName);
    }
   
   public boolean isVOA(){
     
	 //	 CCR10081 -- add guards against NullPointerException
     if (this.getSendingFacility()!= null && 
    		 VAFacility.CODE_MHV.getCode().equals(this.getSendingFacility().getCode())){
                return true;
     }
     else{
         return false;
     }
    }
  
}
