/********************************************************************
 * 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.trigger.PersonTriggerEvent;
import gov.va.med.esr.service.trigger.TargetedPersonTriggerEvent;

/**
 * @author Alex Yoon
 * @version 1.0
 */
public class OutboundMessageMSDSAdaptor extends AbstractOutboundServiceAdaptor {
	private MessagingService messagingService;

	/**
	 * Default constructor.
	 */
	public OutboundMessageMSDSAdaptor() {
		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);

			//setting null for the site because this is going to be sent to MSDS for VADIR/BIRL Query

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

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

		} 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;

	}

}