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

//Java Classes

//Framework Classes
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.trigger.TriggerEvent;
import gov.va.med.fw.util.StopWatchLogger;

import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.service.MessagingService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.trigger.PersonTrigger;
import gov.va.med.esr.service.trigger.PersonTriggerIdentity;
import gov.va.med.esr.service.trigger.PersonTriggerEvent;
import gov.va.med.esr.service.trigger.TargetedPersonTriggerEvent;

import gov.va.med.esr.messaging.constants.HL7Constants;

/**
 * @author Alex Yoon
 * @version 1.0
 */
public class OutboundMessageVistaAdaptor extends AbstractOutboundServiceAdaptor
{

    //CCR11402: ESR provide ongoing permanent address & home telephone updates to IdM system
	//specific trigger event for address and phone update
    private static final PersonTriggerIdentity ADDR_PHONE_TRIGGER_IDENTITY = new  PersonTriggerIdentity(PersonTrigger.DestinationType.MESSAGING,
            PersonTrigger.TargetType.VISTA,
            PersonTrigger.DispatchType.NOTIFY,
            PersonTrigger.DataType.ADDRESS);

    private PersonService personService = null;

    private MessagingService messagingService;





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

    /**
     * @return Returns the messagingService.
     */
    public MessagingService getMessagingService()
    {
        return messagingService;
    }

    /**
     * @param messagingService
     *            The messagingService to set.
     */
    public void setMessagingService(MessagingService messagingService)
    {
        this.messagingService = messagingService;
    }

    /**
     * Method to process an outbound message.
     *
     * @param input
     *            The input used to build a message.
     * @throws ServiceException
     */
    public void processMessage(Object input) throws ServiceException
    {
        Object[] args = (Object[]) input;

        this.processMessage((Person) args[0], (String) args[1],
                (TriggerEvent) args[2]);
    }

    /**
     * Method to process an outbound message. This method gets corresponding
     * OutboundProcessService for message type and delegates actual creation of
     * outbound messages to the appropriate service.
     *
     * @param person
     *            The person used to build a message.
     * @param messageType
     *            The messageType used to build a message.
     *
     * @throws ServiceException
     */
    public void processMessage(Person person, String messageType,
			TriggerEvent triggerEvent) throws ServiceException {

		StopWatchLogger watch = null;

		if (logger.isDebugEnabled()) {
			watch = new StopWatchLogger((new StringBuffer(messageType)
					.append("-OutboundMessageVistaAdaptor processMessage"))
					.toString());
			if (watch != null) {
				watch.start();
			}
		}

		Set siteIdentities = null;
		try {
			OutboundMessageService service = this
					.getOutboundService(messageType);

			siteIdentities = getSitesOfRecord(person, triggerEvent);

			if (siteIdentities == null) {
				throw new ServiceException( "No site found for this outbound message " + messageType);
			}

			for (Iterator iterator = siteIdentities.iterator(); iterator
					.hasNext();) {
				SiteIdentity siteIdentity = (SiteIdentity) iterator.next();

				if (!(triggerEvent instanceof PersonTriggerEvent)) {
					service.processMessage(person, siteIdentity);

				} else if (triggerEvent instanceof PersonTriggerEvent) {
					service.processMessage(person, siteIdentity,
							(PersonTriggerEvent) triggerEvent);
				}
			}

	    	//CCR11402: ESR provide ongoing permanent address & home telephone updates to IdM system
	    	if (HL7Constants.ORUZ05.equals(messageType)) {

	    		if (logger.isDebugEnabled())
	    			logger.debug("update address and phone to IdM, personId =" + person.getPersonEntityKey().getKeyValue());

	    		//it's a address/phone update event, update IdM
	    		//11758: for message, don't let incoming person traits bleed over to MVI
	    		if (((PersonTriggerEvent)triggerEvent).getOnFileIdentityTraits() != null)
	    		{
	    			//11758: make sure this is the last statement for this method so the person traits will
	    			//not be modified back to onFile prematurely. Other places should have the normal traits passed in the event
	    			person.setIdentityTraits(((PersonTriggerEvent)triggerEvent).getOnFileIdentityTraits());
	    			getPersonService().updateProfileForESRCorrelation(person);
	    		} else {
	    			getPersonService().updateProfileForESRCorrelation(person);
	    		}
	    	}
		} finally {
			if (logger.isDebugEnabled()) {
				try {
					StringBuffer info = new StringBuffer("Total time to send outbound message to ")
						.append(siteIdentities == null ? 0 : siteIdentities.size())
						.append(" sites for Person Id ")
						.append(person == null ? "" : person.getEntityKey().getKeyValueAsString());

					if (watch != null) {
						watch.stopAndLog(info.toString());
					}
				} catch (Exception e) {
				}
			}
		}
	}


    private Set getSitesAfterFiltering(TargetedPersonTriggerEvent triggerEvent, Set allSitesOfRecord)
    {
    	Set sitesAfterFiltering = new HashSet();

        for (Iterator iterator = allSitesOfRecord.iterator(); iterator.hasNext();)
        {
            SiteIdentity siteIdentity = (SiteIdentity) iterator.next();

            if(!(isSiteToBeFiltered(siteIdentity, triggerEvent.getFilterSites())))
            {
            	sitesAfterFiltering.add(siteIdentity);
            }
        }
    	return sitesAfterFiltering;
    }

    /**
     * @param siteIdentity
     * @param triggerEvent
     * @return
     */
    private boolean isSiteToBeFiltered(SiteIdentity siteIdentity, Set filteredSites)
    {
        boolean isSiteToBeFiltered = false;

        VAFacility facility = siteIdentity.getVaFacility();

        if(filteredSites != null)
        {
	        for (Iterator iter = filteredSites.iterator(); iter.hasNext();)
	        {
	            VAFacility filterSite = (VAFacility) iter.next();
	            if(filterSite != null
	            		&& filterSite.getStationNumber().equals(facility.getStationNumber()))
	            {
	                isSiteToBeFiltered = true;
	            }
	        }
        }
        return isSiteToBeFiltered;
    }

    private Set getSitesOfRecord(Person person, TriggerEvent triggerEvent) throws ServiceException
    {
        Set sitesOfRecord = new HashSet();

        if (triggerEvent instanceof TargetedPersonTriggerEvent)
        {
        	TargetedPersonTriggerEvent targetedPersonTriggerEvent = (TargetedPersonTriggerEvent)triggerEvent;

        	//Send messages to the targeted sites only
        	if(targetedPersonTriggerEvent.getTargetSites() != null)
        	{
                Set vaFacilitySites = targetedPersonTriggerEvent.getTargetSites();
		        //Get the list of all the targeted sites to send out the
		        // message
		        if (vaFacilitySites != null)
		        {
		            SiteIdentity siteIdentity = null;
		            for (Iterator iter = vaFacilitySites.iterator(); iter
		                    .hasNext();)
		            {
		            	Object nextSite = iter.next();

		            	if (nextSite instanceof SiteIdentity)
		            	{
		            	  	// Code_CR6852: for ORFZ10 and ORFZ11, take the station+dfn directly
			            	// from the inbound message (as SiteIdentity).
			           		siteIdentity =	(SiteIdentity)nextSite;
		            	}
		            	else
		            	{
		            		VAFacility facility = (VAFacility)nextSite;
		            		siteIdentity = messagingService.getIdentity(person,
		                        facility);
		            	}

	            		sitesOfRecord.add(siteIdentity);
		            }
		        }
        	}else if (targetedPersonTriggerEvent.getFilterSites() != null)
        	{
        		Set allSitesOfRecord = this.messagingService.findSitesOfRecord(person);
        		sitesOfRecord = getSitesAfterFiltering(targetedPersonTriggerEvent, allSitesOfRecord);

        	}else
        	{
        		sitesOfRecord = this.messagingService.findSitesOfRecord(person);
        	}
        }else
        {
            //Notify all sites
            sitesOfRecord = this.messagingService.findSitesOfRecord(person);

        }

        return sitesOfRecord;

    }

	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}




}