/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
// Package
package gov.va.med.esr.service.impl;

// Java classes
import java.util.Date;

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

// Framework classes
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.util.StringUtils;

// ESR classes
import gov.va.med.esr.common.model.person.Association;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.service.AssociationService;
import gov.va.med.esr.service.PersonService;

/**
 * Provides methods to process business rules related to Association
 * <p/>
 * Project: Common</br> Created on: 1:26:15 PM </br>
 *
 * @author DNS   LEV
 */
public class AssociationServiceImpl extends AbstractHistoricalInfoServiceImpl implements AssociationService
{

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

    /**
     * A default constructor
     */
    public AssociationServiceImpl()
    {
        super();
    }

    /**
     * <b> [2181UC20.1]</b> This use case describes how the actor adds or </br> modifies current association information, and views association information.</br> This information consists of Next of
     * Kin,, Power of Attorney, and Guardian information</br> </br>
     * <p/>
     * <b>Following are the use cases covered in this method</b></br> [UC20.3] Display Person Association Information </br> [UC20.4] Update Person Association Information </br> [UC20.5] Manage Person
     * Demographic Information </br> [UC20.6] Manage Address/Contact Information </br> [UC20.7] Send Update Message (Z05) </br>
     *
     * @param incoming An person created from incoming data
     * @param association New/Updated/Deleted association
     *
     * @return An updated person with association data
     * @throws ServiceException Thrown if failed to update association
     */
    public Person updateAssociation(Person incoming, Association association) throws ServiceException
    {
        Validate.notNull(incoming, "A veteran must not be null");
        Validate.notNull(association, "An association must not be null");

        // This call should always return a person since a person must have
        // already been querried through a search to display insurance info
        // on a screen
        PersonService personService = this.getPersonService();
        Person result = personService.getPerson((PersonEntityKey)incoming.getEntityKey());

        // Ensure that something changed on the incoming entity as compared to the onFile entity
        ensureEntityChanged(incoming, result);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(result);

        // Set the entity key and onFile association.  They will both be null if this is an add.
        Association resultAssociation = null;
        EntityKey entityKey = association.getEntityKey();
        if (entityKey != null)
        {
            resultAssociation = result.getAssociationByEntityKey(entityKey);
        }

        // Check if the association is deleted by the user
        if ((entityKey != null) && (incoming.getAssociationByEntityKey(entityKey) == null))
        {
            result.removeAssociation(association);
        }
        else
        {
            // If the association is being added (i.e. no entity key) or any part of the association has changed,
            // then update the last update date so the rules will process this association.
            if ((entityKey == null) || (!AbstractEntity.matchesDomainValues(association, resultAssociation)))
            {
                association.setLastUpdateDate(new Date(getTimestampManager().getTransactionTimestamp().getTime()));
            }

            // If the primary phone has been changed, then update the primary phone change date
            if (!StringUtils.equals(association.getPrimaryPhone(), (resultAssociation == null ? null : resultAssociation.getPrimaryPhone())))
            {
                association.setPrimaryPhoneChangeDate(new Date(getTimestampManager().getTransactionTimestamp().getTime()));
            }

            // Step 1: Update a veteran on file with association information and send Z05 message.
            result = this.getAssociationRuleService().manageAssociation(association, result);
        }
        
        // calling handbook rule here for dayton trigger.
        // removing it 3.6
        // this.getEventRuleService().manageHandBookEvents(result);
        // Save the updated person
        result = personService.save(result);

        return result;
    }
}