// Created Apr 28, 2005 11:44:37 AM

/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.esr.messaging.service.outbound;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

import gov.va.med.esr.service.trigger.CommonTriggerEvent;
import gov.va.med.esr.service.trigger.CommonTriggerIdentity;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.trigger.TriggerEvent;
import gov.va.med.fw.service.trigger.TriggerableService;
import gov.va.med.fw.util.InvalidConfigurationException;

/**
 * Handles CommonTriggerEvents that causes messages to be triggered.
 * 
 * @author DNS   BOHMEG
 */
public class OutboundMessageRouter implements TriggerableService,
        InitializingBean
{

    /**
     * Configuration injected as such: Map <CommonTriggerIdentity,
     * OutboundProcessService>
     */
    private Map outboundProcessServices;

    /**
     * Derived from configuration: Map <CommonTriggerIdentity,
     * CommonTriggerIdentity.getName()>
     */
    private Map outboundMessages;

    protected Log logger = LogFactory.getLog(getClass());

    public void trigger(TriggerEvent triggerEvent) throws ServiceException
    {
        if (triggerEvent != null)
        {
            if (!(triggerEvent instanceof CommonTriggerEvent))
                throw new IllegalArgumentException(
                        "TriggerEvent must be of type CommonTriggerEvent");

            OutboundProcessService service = getOutboundProcessService((CommonTriggerIdentity) triggerEvent.getTriggerIdentity());
            if (service == null)
            {
                throw new InvalidConfigurationException(triggerEvent.getName()
                        + " not mapped to an OutboundProcessService");
            }

            // since this is not specific to a person, just pass the message
            // info to the OutboundProcessService
            invokeOutboundProcessService(service,
                    (CommonTriggerEvent) triggerEvent, null);
        }
    }
    
    
	/** Overrides default implementation */
	protected OutboundProcessService getOutboundProcessService(
			CommonTriggerIdentity triggerIdentity) {
		return (OutboundProcessService) findMatch(triggerIdentity, getOutboundProcessServices());
	}
	
	private Object findMatch(CommonTriggerIdentity triggerIdentity, Map targetMap) {

		Object match = null;
		CommonTriggerIdentity keyFromConfiguration = null;
		Iterator itr = targetMap.keySet().iterator();
		while (itr.hasNext()) {
			keyFromConfiguration = (CommonTriggerIdentity) itr.next();
			if (keyFromConfiguration
					.matchTriggerCriteria(triggerIdentity)) {
				match = targetMap.get(keyFromConfiguration);
				break;
			}
		}
		return match;		
	}    

	
	protected String getOutboundMessage(CommonTriggerIdentity triggerIdentity) {
		return (String) findMatch(triggerIdentity, getOutboundMessages());		
	}   
    
    protected void invokeOutboundProcessService(OutboundProcessService service,
            CommonTriggerEvent triggerEvent, Object payload)
            throws ServiceException
    {
        if (payload == null)
            payload = triggerEvent; // default payload
        
        //Modified RP 09/06 to add TriggerEvent as param
        Object[] args = new Object[] { payload, getOutboundMessage((CommonTriggerIdentity) triggerEvent.getTriggerIdentity()),
                triggerEvent };
        service.processMessage(args);
    }

    /**
     * @return Returns the outboundProcessServices.
     */
    public Map getOutboundProcessServices()
    {
        return outboundProcessServices;
    }

    /**
     * @param outboundProcessServices
     *            The outboundProcessServices to set.
     */
    public void setOutboundProcessServices(Map outboundProcessServices)
    {
        this.outboundProcessServices = outboundProcessServices;
    }

    public Map getOutboundMessages() {
    	return outboundMessages;
    }
    
    public void afterPropertiesSet()
    {
        if (outboundProcessServices == null)
            throw new InvalidConfigurationException(
                    "Map of OutboundProcessService's must be set on "
                            + getClass().getName());

        outboundMessages = new HashMap();
        Iterator itr = outboundProcessServices.keySet().iterator();
        CommonTriggerIdentity keyFromConfig;
        while (itr.hasNext())
        {
            keyFromConfig = (CommonTriggerIdentity) itr.next();
            outboundMessages
                    .put(keyFromConfig, keyFromConfig.getName() /*
                                                                 * should be HL7
                                                                 * message name
                                                                 */);
        }
    }
}