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

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

// Library classes
import org.apache.commons.lang.Validate;
import org.apache.commons.collections.set.UnmodifiableSet;
import org.apache.commons.lang.builder.ToStringBuilder;

// Framework classes
import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.model.EntityKey;

// ESR classes
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
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.lookup.MilitaryServiceQueryStatus;

/**
 * This is one of the classes of the Business Object Model (BOM). This class
 * represents a Military Service. There is only 1 Military Service object
 * associated with a Person and it contains all the general Military Service
 * information that is not associated with a specific site. All site specific
 * data is defined within the collection of Military Service Site Records
 * contained within this class,.
 * 
 * @author Andrew Pach
 * @version 3.0
 */
public class MilitaryService extends AbstractKeyedEntity {
	
	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = -7702677194409852460L;

	private Person person = null;

	private Boolean disabilityRetirementIndicator = null;

	private Boolean dischargeDueToDisability = null;

	private Date combatVeteranEligibilityEndDate = null;

    private Set internalCombatServices = null;
    
    private Set internalActivations = null;        
    
    private Set internalCombatEpisodes = null;
    
	private Set internalMilitaryServiceSiteRecords = null;
	
	private boolean voaHasAttachment = false;
	
	private MilitaryServiceQueryStatus militaryServiceQueryStatus = null;	

	/**
	 * Default constructor.
	 */
	public MilitaryService() {
		super();
	}

	public Person getPerson() {
		return this.person;
	}

	public void setPerson(Person person) {
        this.validateOwner(this.person,person);        
		this.person = person;
	}

	public Boolean getDisabilityRetirementIndicator() {
		return this.disabilityRetirementIndicator;
	}

	public void setDisabilityRetirementIndicator(
			Boolean disabilityRetirementIndicator) {
		this.disabilityRetirementIndicator = disabilityRetirementIndicator;
	}

	public Boolean getDischargeDueToDisability() {
		return this.dischargeDueToDisability;
	}

	public void setDischargeDueToDisability(Boolean dischargeDueToDisability) {
		this.dischargeDueToDisability = dischargeDueToDisability;
	}

	public Date getCombatVeteranEligibilityEndDate() {
		return this.combatVeteranEligibilityEndDate;
	}

	public void setCombatVeteranEligibilityEndDate(
			Date combatVeteranEligibilityEndDate) {
		this.combatVeteranEligibilityEndDate = combatVeteranEligibilityEndDate;
	}

	private void setInternalActivations( Set activations ) {
		this.internalActivations = activations;
	}

	private Set getInternalActivations() {
		if (this.internalActivations == null) {
			this.internalActivations = new HashSet();
		}
		return this.internalActivations;
	}    

	public Set getActivations() {
		return UnmodifiableSet.decorate(getInternalActivations());
	}    
	public void addActivation( Activation activation ) {
		Validate.notNull(activation);     
		getInternalActivations().add(activation);
		activation.setMilitaryService(this);
	}

	public void addAllActivations( Set activations ) {
		if( activations != null ) {
			for( Iterator i=activations.iterator(); i.hasNext(); ) {
				Object record = i.next();
				if( record instanceof Activation ) {
					this.addActivation( (Activation)record );
				}
			}
		}
	}

	public void removeActivation( Activation activation ) {
		Validate.notNull(activation, "Null Activation specified." );
		getInternalActivations().remove(activation);
		activation.setMilitaryService(null);
	}

	public Activation getActivationByEntityKey(EntityKey identifier) {
		return (Activation) getEntityByEntityKey(getActivations(), identifier);
	}

	public Activation removeActivationByEntityKey(EntityKey identifier) {
		return (Activation) removeEntityByEntityKey(getInternalActivations(), identifier);
	}

	public void removeAllActivations() {
		getInternalActivations().clear();
	}    
	
    private void setInternalCombatServices( Set combatServices ) {
        this.internalCombatServices = combatServices;
    }

    private Set getInternalCombatServices() {
        if (this.internalCombatServices == null) {
            this.internalCombatServices = new HashSet();
        }
        return this.internalCombatServices;
    }

    public Set getCombatServices() {
        return UnmodifiableSet.decorate(getInternalCombatServices());
    }

    public void addCombatService( CombatService combatService ) {
        Validate.notNull(combatService);     
        getInternalCombatServices().add(combatService);
        combatService.setMilitaryService(this);
    }

    public void addAllCombatServices( Set combatServices ) {
        if( combatServices != null ) {
            for( Iterator i=combatServices.iterator(); i.hasNext(); ) {
                Object record = i.next();
                if( record instanceof CombatService ) {
                    this.addCombatService( (CombatService)record );
                }
            }
        }
    }

    public void removeCombatService( CombatService combatService ) {
        Validate.notNull(combatService, "Null Combat Service specified." );
        getInternalCombatServices().remove(combatService);
        combatService.setMilitaryService(null);
    }

    public CombatService getCombatServiceByEntityKey(EntityKey identifier) {
        return (CombatService) getEntityByEntityKey(getCombatServices(), identifier);
    }

    public CombatService removeCombatServiceByEntityKey(EntityKey identifier) {
        return (CombatService) removeEntityByEntityKey(getInternalCombatServices(), identifier);
    }

    public void removeAllCombatServices() {
        getInternalCombatServices().clear();
    }
    
    
    
    private void setInternalCombatEpisodes( Set combatEpisodes ) {
        this.internalCombatEpisodes = combatEpisodes;
    }

    private Set getInternalCombatEpisodes() {
        if (this.internalCombatEpisodes == null) {
            this.internalCombatEpisodes = new HashSet();
        }
        return this.internalCombatEpisodes;
    }

    public Set getCombatEpisodes() {
        return UnmodifiableSet.decorate(getInternalCombatEpisodes());
    }

    public void addCombatEpisode( CombatEpisode combatEpisode ) {
        Validate.notNull(combatEpisode);     
        getInternalCombatEpisodes().add(combatEpisode);
        combatEpisode.setMilitaryService(this);
    }

    public void addAllCombatEpisodes( Set combatEpisodes ) {
        if( combatEpisodes != null ) {
            for( Iterator i=combatEpisodes.iterator(); i.hasNext(); ) {
                Object record = i.next();
                if( record instanceof CombatEpisode ) {
                    this.addCombatEpisode( (CombatEpisode)record );
                }
            }
        }
    }

    public void removeCombatEpisode( CombatEpisode combatEpisode ) {
        Validate.notNull(combatEpisode, "Null Combat Episode specified." );
        getInternalCombatEpisodes().remove(combatEpisode);
        combatEpisode.setMilitaryService(null);
    }

    public CombatEpisode getCombatEpisodeByEntityKey(EntityKey identifier) {
        return (CombatEpisode) getEntityByEntityKey(getCombatEpisodes(), identifier);
    }

    public CombatEpisode removeCombatEpisodeByEntityKey(EntityKey identifier) {
        return (CombatEpisode) removeEntityByEntityKey(getInternalCombatEpisodes(), identifier);
    }

    public void removeAllCombatEpisodes() {
        getInternalCombatEpisodes().clear();
    }
    
    
	private void setInternalMilitaryServiceSiteRecords( Set militaryServiceSiteRecords ) {
		this.internalMilitaryServiceSiteRecords = militaryServiceSiteRecords;
	}

	private Set getInternalMilitaryServiceSiteRecords() {
		if (this.internalMilitaryServiceSiteRecords == null) {
			this.internalMilitaryServiceSiteRecords = new HashSet();
		}
		return this.internalMilitaryServiceSiteRecords;
	}

	public Set getMilitaryServiceSiteRecords() {
		return UnmodifiableSet.decorate(getInternalMilitaryServiceSiteRecords());
	}

	public void addMilitaryServiceSiteRecord( MilitaryServiceSiteRecord militaryServiceSiteRecord ) {
	    Validate.notNull(militaryServiceSiteRecord);
	    Validate.notNull(militaryServiceSiteRecord.getSite());	    
		getInternalMilitaryServiceSiteRecords().add(militaryServiceSiteRecord);
		militaryServiceSiteRecord.setMilitaryService(this);
	}

	public void addAllMilitaryServiceSiteRecords( Set records ) {
		if( records != null ) {
			for( Iterator i=records.iterator(); i.hasNext(); ) {
				Object record = i.next();
				if( record instanceof MilitaryServiceSiteRecord ) {
					this.addMilitaryServiceSiteRecord( (MilitaryServiceSiteRecord)record );
				}
			}
		}
	}

	public void removeMilitaryServiceSiteRecord( MilitaryServiceSiteRecord militaryServiceSiteRecord ) {
		Validate.notNull(militaryServiceSiteRecord, "Null Military Service Site Record specified." );
		getInternalMilitaryServiceSiteRecords().remove(militaryServiceSiteRecord);
		militaryServiceSiteRecord.setMilitaryService(null);
	}

	public MilitaryServiceSiteRecord getMilitaryServiceSiteRecordByEntityKey(
			EntityKey identifier) {
		return (MilitaryServiceSiteRecord) getEntityByEntityKey(
				getMilitaryServiceSiteRecords(), identifier);
	}

	public MilitaryServiceSiteRecord removeMilitaryServiceSiteRecordByEntityKey(
			EntityKey identifier) {
		return (MilitaryServiceSiteRecord) removeEntityByEntityKey(
				getInternalMilitaryServiceSiteRecords(), identifier);
	}

	public void removeAllMilitaryServiceSiteRecords() {
		getInternalMilitaryServiceSiteRecords().clear();
	}

	/**
	 * Return a Collection of MilitaryServiceSiteRecord for a given facility.
	 * This is similar to calling
	 * <code>getMilitaryServiceSiteRecordsBySite(facility.getStationNumber())</code>
	 * 
	 * @param facility
	 * @return MilitaryServiceSiteRecord
	 */
	public MilitaryServiceSiteRecord getMilitaryServiceSiteRecordsBySite( VAFacility facility ) {
		return getMilitaryServiceSiteRecordsBySite( facility.getStationNumber() );
	}

	/**
	 * Return a MilitaryServiceSiteRecord for a given station number.
	 * 
	 * @param stationNum the station number to search for
	 * @return The found MilitaryServiceSiteRecord or null if one wasn't found
	 */
	public MilitaryServiceSiteRecord getMilitaryServiceSiteRecordsBySite(String stationNum) {
		
		Set siteRecords = getInternalMilitaryServiceSiteRecords();
		if (siteRecords != null) {
			for (Iterator iter = siteRecords.iterator(); iter.hasNext();) {
				if (iter != null)
				{
					MilitaryServiceSiteRecord siteRecord = 
						(MilitaryServiceSiteRecord) iter.next();
					
					if (siteRecord != null) {
						VAFacility site = siteRecord.getSite();
						if (site.getStationNumber().equals(stationNum)) {
							return siteRecord;
						}
					}
				}
			}
		}
		return null;
	}

	/**
	 * Return a MilitaryServiceSiteRecord for a given station number.
	 * 
	 * @param stationNum The station number to search for
	 * @return The found MilitaryServiceSiteRecord or null if one wasn't found
	 */
	public MilitaryServiceSiteRecord getHECMilitaryServiceSiteRecord() {
		// A code is typically not a station number; however, our current
		// implementation uses the same value for code and station number.
		// If VAFacility code for HEC is changed to be different from a station number
		// this method needs to get a VAFacility look up for HEC then get a station number
		// to pass to getMilitaryServiceSiteRecordsBySite( String stationNumber ) - VL
		return this.getMilitaryServiceSiteRecordsBySite( VAFacility.CODE_HEC.getName() );
	}
    
    /**
     * Return Service entry date from military service episodes
     * @return
     */
    public Date getServiceEntryDate(){ 
        Date serviceEntryDate = null;
        Set siteRecords = getMilitaryServiceSiteRecords();
        for (Iterator j=siteRecords.iterator(); j.hasNext();) {
            MilitaryServiceSiteRecord siteRec = (MilitaryServiceSiteRecord)j.next();
            Set msEpisodes = siteRec.getMilitaryServiceEpisodes();
            for (Iterator i = msEpisodes.iterator(); i.hasNext();) {
                MilitaryServiceEpisode msEpisode = (MilitaryServiceEpisode)i.next();
                Date msStartDate = ImpreciseDateUtils.getDateWithDefault(msEpisode.getStartDate());
                if (serviceEntryDate == null || 
                        (msStartDate != null && serviceEntryDate.after(msStartDate)) ){
                    serviceEntryDate = msStartDate;
                }
            }                        
        }
        return serviceEntryDate;     
    }
    /**
     * Return Service seperation date from military service episodes
     * @return
     */
    public Date getServiceSeperationDate() {         
        Date serviceSeperationDate = null;
        Set siteRecords = getMilitaryServiceSiteRecords();
        for (Iterator j=siteRecords.iterator(); j.hasNext();) {
            MilitaryServiceSiteRecord siteRec = (MilitaryServiceSiteRecord)j.next();
            Set msEpisodes = siteRec.getMilitaryServiceEpisodes();
            for (Iterator i = msEpisodes.iterator(); i.hasNext();) {
                MilitaryServiceEpisode msEpisode = (MilitaryServiceEpisode)i.next();
                Date msEndDate = ImpreciseDateUtils.getDateWithDefault(msEpisode.getEndDate());
                if (serviceSeperationDate == null || 
                        (msEndDate != null && serviceSeperationDate.before(msEndDate)) ){
                    serviceSeperationDate = msEndDate;
                }
            }            
        }
        return serviceSeperationDate;     
    }

	public MilitaryServiceQueryStatus getMilitaryServiceQueryStatus() {
		return militaryServiceQueryStatus;
	}

	public void setMilitaryServiceQueryStatus(
			MilitaryServiceQueryStatus militaryServiceQueryStatus) {
		this.militaryServiceQueryStatus = militaryServiceQueryStatus;
	}     
    
	/**
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.model.AbstractKeyedEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
	 */
	protected void buildToString(ToStringBuilder builder) {
		builder.append( "disabilityRetirementStatus", this.disabilityRetirementIndicator )
				 .append( "dischargeDueToDisability", this.dischargeDueToDisability )
				 .append( "combatVeteranEligibilityEndDate", this.combatVeteranEligibilityEndDate )
				 .append( "internalMilitaryServiceSiteRecords", this.internalMilitaryServiceSiteRecords );
	}
	
	public boolean  isVoaHasAttachment()
	{
		return voaHasAttachment;
	}
	
	public void setVoaHasAttachment(boolean voaHasAttachment)
	{
		this.voaHasAttachment = voaHasAttachment;
	}
}
	