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

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

// Library classes
import org.apache.commons.collections.set.UnmodifiableSet;
import org.apache.commons.lang.Validate;
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.model.lookup.VAFacility;
import gov.va.med.esr.common.model.lookup.ServicePeriod;
import gov.va.med.esr.common.model.lookup.FilipinoVeteranProof;
import gov.va.med.esr.common.model.person.Person;

/**
 * This is one of the classes of the Business Object Model (BOM). This class
 * represents a Military Service Site Record. Each site that has military
 * service information, including the HEC, will have one instance of this
 * object.
 * 
 * @author Andrew Pach
 * @version 3.0
 */
public class MilitaryServiceSiteRecord extends AbstractKeyedEntity {
	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 906614410400008170L;

	private MilitaryService militaryService;

	private VAFacility site;

	private ServicePeriod servicePeriod = null;

	private FilipinoVeteranProof filipinoVeteranProof = null;

	private Set internalMilitaryServiceEpisodes = null;

	private Set internalConflictExperiences = null;

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

	public VAFacility getSite() {
		return this.site;
	}

	public void setSite(VAFacility site) {
		this.site = site;
	}

	public ServicePeriod getServicePeriod() {
		return this.servicePeriod;
	}

	public void setServicePeriod(ServicePeriod periodOfService) {
		this.servicePeriod = periodOfService;
	}

	public FilipinoVeteranProof getFilipinoVeteranProof() {
		return this.filipinoVeteranProof;
	}

	public void setFilipinoVeteranProof(FilipinoVeteranProof filipinoVeteranProof) {
		this.filipinoVeteranProof = filipinoVeteranProof;
	}

	private void setInternalMilitaryServiceEpisodes(Set militaryServiceEpisodes) {
		this.internalMilitaryServiceEpisodes = militaryServiceEpisodes;
	}

	private Set getInternalMilitaryServiceEpisodes() {
		if (this.internalMilitaryServiceEpisodes == null) {
			this.internalMilitaryServiceEpisodes = new HashSet();
		}
		return this.internalMilitaryServiceEpisodes;
	}

	public Set getMilitaryServiceEpisodes() {
		return UnmodifiableSet.decorate(getInternalMilitaryServiceEpisodes());
	}
	
	public void addMilitaryServiceEpisode(
			MilitaryServiceEpisode militaryServiceEpisode) {
		getInternalMilitaryServiceEpisodes().add(militaryServiceEpisode);
		militaryServiceEpisode.setMilitaryServiceSiteRecord(this);
	}

	public void removeMilitaryServiceEpisode(
			MilitaryServiceEpisode militaryServiceEpisode) {
		Validate.notNull(militaryServiceEpisode,
				"Null Military Service Episode Record specified.");
		getInternalMilitaryServiceEpisodes().remove(militaryServiceEpisode);
		militaryServiceEpisode.setMilitaryServiceSiteRecord(null);
	}

	public MilitaryServiceEpisode getMilitaryServiceEpisodeByEntityKey(
			EntityKey identifier) {
		return (MilitaryServiceEpisode) getEntityByEntityKey(
				getMilitaryServiceEpisodes(), identifier);
	}

	public MilitaryServiceEpisode removeMilitaryServiceEpisodeByEntityKey(
			EntityKey identifier) {
		return (MilitaryServiceEpisode) removeEntityByEntityKey(
				getInternalMilitaryServiceEpisodes(), identifier);
	}

	public void removeAllMilitaryServiceEpisodes() {
		getInternalMilitaryServiceEpisodes().clear();
	}

	public void addAllMilitaryServiceEpisodes(Set episodes) {
	    
        Validate.notEmpty(episodes, "MilitaryServiceEpisodes cannot be null or empty");

        // Call addMilitaryServiceEpisode to handle bidirectional relationship
        for (Iterator i = episodes.iterator(); i.hasNext();) {
            Object episode = i.next();
            if (episode instanceof MilitaryServiceEpisode) {
                this.addMilitaryServiceEpisode((MilitaryServiceEpisode) episode);
            }
        }
	}

	private void setInternalConflictExperiences(Set conflictExperiences) {
		this.internalConflictExperiences = conflictExperiences;
	}

	private Set getInternalConflictExperiences() {
		if (this.internalConflictExperiences == null) {
			this.internalConflictExperiences = new HashSet();
		}
		return this.internalConflictExperiences;
	}

	public Set getConflictExperiences() {
		return UnmodifiableSet.decorate(getInternalConflictExperiences());
	}

	public void addConflictExperience(ConflictExperience conflictExperience) {
		getInternalConflictExperiences().add(conflictExperience);
		conflictExperience.setMilitaryServiceSiteRecord(this);
	}

	public void addAllConflictExperiences(Set conflictExperiences) {
	    Validate.notEmpty(conflictExperiences, "ConflictExperiences cannot be null or empty");
	    
        // Call addConflictExperience to handle bidirectional relationship
        for (Iterator i = conflictExperiences.iterator(); i.hasNext();) {
            Object conflictExperience = i.next();
            if (conflictExperience instanceof ConflictExperience) {
                this.addConflictExperience((ConflictExperience) conflictExperience);
            }
        }
	}

	public void removeConflictExperience(ConflictExperience conflictExperience) {
		Validate.notNull(conflictExperience,
				"Null Combat Experience Record specified.");
		getInternalConflictExperiences().remove(conflictExperience);
		conflictExperience.setMilitaryServiceSiteRecord(null);
	}

	public ConflictExperience getConflictExperienceByEntityKey(
			EntityKey identifier) {
		return (ConflictExperience) getEntityByEntityKey(
				getConflictExperiences(), identifier);
	}

	public ConflictExperience removeConflictExperienceByEntityKey(
			EntityKey identifier) {
		return (ConflictExperience) removeEntityByEntityKey(
				getInternalConflictExperiences(), identifier);
	}

	public void removeAllConflictExperiences() {
		getInternalConflictExperiences().clear();
	}

    public boolean isEmpty() {
        if(servicePeriod == null && filipinoVeteranProof == null &&
           (internalMilitaryServiceEpisodes == null || internalMilitaryServiceEpisodes.isEmpty()) &&
           (internalConflictExperiences == null || internalConflictExperiences.isEmpty()) ) {
            return true;
        }
        return false;
    }
    
	/**
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.model.AbstractKeyedEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
	 */
	protected void buildToString(ToStringBuilder builder) {
		builder.append("site", this.site).append("servicePeriod",
				this.servicePeriod).append("filipinoVeteranProof",
				this.filipinoVeteranProof).append(
				"internalMilitaryServiceEpisodes",
				this.internalMilitaryServiceEpisodes).append(
				"internalConflictExperiences", this.internalConflictExperiences);
	}

	public MilitaryService getMilitaryService() {
		return militaryService;
	}

	public void setMilitaryService(MilitaryService militaryService) {
        this.validateOwner(this.militaryService,militaryService);        
		this.militaryService = militaryService;
	}

	/**
	 * This getter returns the person object that is stored in the military
	 * service parent object.
	 * 
	 * @return The person who is associated with this military service site
	 *         record.
	 */
	public Person getPerson() {
		// TODO: ***** REVISIT *****
		// Can we make this method private?
		return (this.militaryService == null) ? null : this.militaryService
				.getPerson();
	}

	/**
	 * This setter doesn't actually set the person object since we are relying on
	 * getting it from the parent. Instead, it sets the military service back
	 * reference based on the person being passed in. This is because this setter
	 * is only called by Hibernate and we want to maintain a back reference to
	 * the parent military service object. If we don't set it here, there is no
	 * other easy place to set it. Note that although a MilitaryServiceSiteRecord
	 * is contained by a MilitaryService object, the database stores all site
	 * record information in the MILITARY_SERVICE table which is contained
	 * directly by PERSON (i.e. there is no middle table associated with the
	 * MilitaryService object).
	 * 
	 * @param person
	 *           The person back reference.
	 */
	private void setPerson(Person person) {
		this.militaryService = (person == null) ? null : person
				.getMilitaryService();
	}
}
