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

import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import java.util.Iterator;
import java.io.Serializable;
import java.math.BigDecimal;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import gov.va.med.esr.common.model.lookup.MessageStatus;
import gov.va.med.esr.common.model.messaging.MessageLogEntry;

import gov.va.med.esr.common.model.messaging.MsdsMessageLogEntry;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.service.LogTransmissionService;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.service.impl.IdmWebServiceDelegate;
import gov.va.med.esr.service.trigger.PersonTriggerEvent;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.jms.QueueMessageProducerService;
import gov.va.med.esr.messaging.service.MessageProcessServiceUtil;
import gov.va.med.ps.model.PatientIdentifier;

import gov.va.med.esr.jms.vadir.inboundRequest.VadirServiceMilitaryHistoryRequest;
import gov.va.med.esr.common.infra.ImpreciseDateUtils;

public class QRYZ21ProcessService extends AbstractOutboundProcessService
        implements OutboundMessageService{

	private QueueMessageProducerService producerService;
	private LogTransmissionService logMessagingService;
	private IdmWebServiceDelegate idmServiceDelegate = null;
	private static String isEMISProviderInUse = "NO";

	public static final String IDM_QUERY_POSTFIX = "^NI^200ESR^USVHA";
	public static final String YES = "YES";
	public static final String NO = "NO";
	public static final String BOTH = "BOTH";

    /**
     * Default contructor.
     */
    public QRYZ21ProcessService()
    {
        super();
    }
    
	static {
		try{
		   isEMISProviderInUse = System.getProperty("emis.provider.inuse");
		   if (isEMISProviderInUse == null) {
			   isEMISProviderInUse = NO;
		   }
		   
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	public String getIsEMISProviderInUse() {
		return isEMISProviderInUse;
	}

	public void setIsEMISProviderInUse(String isEMISProviderInUse) {
		isEMISProviderInUse = isEMISProviderInUse;
	}
	
    public void processMessage(Person person, SiteIdentity siteIdentity)
            throws ServiceException
    {
        this.processMessage(person, siteIdentity, null, null);
    }

    /*
     * (non-Javadoc)
     *
     * @see gov.va.med.esr.messaging.service.outbound.OutboundMessageService#processMessage(gov.va.med.esr.common.model.person.Person,
     *      gov.va.med.esr.common.model.messaging.SiteIdentity,
     *      gov.va.med.fw.service.trigger.TriggerEvent)
     */
    public void processMessage(Person person, SiteIdentity siteIdentity,
            PersonTriggerEvent triggerEvent) throws ServiceException
    {
        this.processMessage(person, siteIdentity, triggerEvent, null);
    }

    /*
     * (non-Javadoc)
     *
     * @see gov.va.med.esr.messaging.service.outbound.OutboundMessageService#processMessage(gov.va.med.esr.common.model.person.Person,
     *      gov.va.med.esr.common.model.messaging.SiteIdentity,
     *      gov.va.med.fw.service.trigger.TriggerEvent)
     */
    public void processMessage(Person person, SiteIdentity siteIdentity,
            MessageLogEntry log) throws ServiceException
    {
        this.processMessage(person, siteIdentity, null, log);
    }


    public void processMessage(Person person, SiteIdentity siteIdentity,
            PersonTriggerEvent triggerEvent, MessageLogEntry log)
            throws ServiceException
    {
        this.processMessage(person, siteIdentity, triggerEvent, log, false);
    }

    /**
     * @param person
     * @param siteIdentity
     * @param triggerEvent
     * @param log
     * @param isRetransmitFromUI - if it is a retransmit for a single message from UI
     * @throws ServiceException
     */
    public void processMessage(Person person, SiteIdentity siteIdentity,
    		PersonTriggerEvent triggerEvent, MessageLogEntry log, boolean isRetransmitFromUI)
    throws ServiceException
    {
    	if (triggerEvent.getInitiater() == null) {
    		try {
    			triggerEvent.setInitiater(SecurityContextHelper
    					.getSecurityContext().getUserPrincipal()
    					.getUserCredentials());
    		} catch (Exception e) {
    			logger
    			.warn(
    					"At publish time, unable to set TriggerEvent.initiater, most likely because the user is no longer logged in.",
    					e);
    		}
    	}

    	String logId = this.logMessagingService.generateControlIdentifier();

    	VadirServiceMilitaryHistoryRequest queryPerson = buildQueryPersonInfo(person,logId);
    	if (queryPerson != null) {
	    	Properties props = new Properties();
	    	props.put("MESSAGEID", logId);
	    	props.put("Message_Type", "MSDS");
	
	    	logMessage(person,new BigDecimal(logId), ToStringBuilder.reflectionToString(queryPerson, ToStringStyle.MULTI_LINE_STYLE));
	    	producerService.send((Serializable)queryPerson, props);
	
	
	    	if (super.logger.isInfoEnabled())
	    	{
	    		super.logger.info("Built outbound QRYZ21 with message Id " );
	    	}
    	} else {
    		if (super.logger.isInfoEnabled())
	    	{
	    		super.logger.info("Query to MSDS is ignored." );
	    	}
    	}


    }

    private void logMessage(Person person, BigDecimal logId, String request)throws ServiceException {

    	MessageStatus status;
    	try {

    		status = (MessageStatus)super.getLookupService().getByCode(MessageStatus.class,MessageStatus.PENDING);
    		MsdsMessageLogEntry logEntry = MessageProcessServiceUtil.createMsdsMessageLog(logId, status, person, Calendar.getInstance().getTime(), 0, null);

    		logEntry = logMessagingService.logMessage(logEntry);
    		logMessagingService.logMessagePayload(logEntry, request, null);

    	} catch (UnknownLookupTypeException e) {
    		throw new ServiceException();
    	}

    }

	public QueueMessageProducerService getProducerService() {
		return producerService;
	}

	public void setProducerService(QueueMessageProducerService producerService) {
		this.producerService = producerService;
	}

	public LogTransmissionService getLogMessagingService() {
		return this.logMessagingService;
	}

	public void setLogMessagingService(
			LogTransmissionService logMessagingService) {
		this.logMessagingService = logMessagingService;
	}


	private VadirServiceMilitaryHistoryRequest buildQueryPersonInfo(Person person, String logEntryId) throws ServiceException {
		VadirServiceMilitaryHistoryRequest queryPerson = new VadirServiceMilitaryHistoryRequest();
		queryPerson.setPersonId(((BigDecimal)(person.getPersonEntityKey().getKeyValue())).longValue());
		queryPerson.setRequestId(Long.parseLong(logEntryId));
		queryPerson.setFirstName(person.getIdentityTraits().getLegalName().getGivenName());
		queryPerson.setLastName(person.getIdentityTraits().getLegalName().getFamilyName());
		queryPerson.setDateOfBirth(ImpreciseDateUtils.getDateWithDefault( person.getIdentityTraits().getBirthRecord().getBirthDate()));
		queryPerson.setIcn(person.getVPIDEntityKey().getShortVPID());
		queryPerson.setSsn(person.getIdentityTraits().getSsnText());
		//CCR 13500 - allow null gender in MSDS query
		if (person.getIdentityTraits().getGender() != null) {
			queryPerson.setGender(person.getIdentityTraits().getGender().getCode());
		} else {
			queryPerson.setGender(" ");
		}
		
		String edipi = null;
		String isEMISProviderInUse = getIsEMISProviderInUse();
		if (super.logger.isDebugEnabled())
    	{
    		super.logger.debug("isEMISProviderInUse="+isEMISProviderInUse);
    	}
		if (YES.equalsIgnoreCase(isEMISProviderInUse) 
				|| BOTH.equalsIgnoreCase(isEMISProviderInUse)) {
		
			//NNNNNNNNNNVNNNNNN^NI^200ESR^USVHA
			String queryId = person.getVPIDEntityKey().getVPID() + IDM_QUERY_POSTFIX;
			List<PatientIdentifier> correlations = null;
			try {
				if (super.logger.isDebugEnabled())
		    	{
		    		super.logger.debug("Invoking PSIM call");
		    	}				
				correlations = idmServiceDelegate.getCorrelationsByFullyQualifiedIdentifier(queryId);
				if (super.logger.isDebugEnabled())
		    	{
		    		super.logger.debug("Received PSIM response "+correlations);
		    	}				
			} catch(Exception e) {
				logger.error("Error occured in invoking PSIM "+e.getMessage());
			}
			if (correlations != null && correlations.size() > 0) {				
				edipi = getEDIPI(correlations);
				if (super.logger.isDebugEnabled())
		    	{
		    		super.logger.debug("EDIPI="+edipi);
		    	}				
				if (StringUtils.isNotEmpty(edipi)) {
					queryPerson.setIcn(queryPerson.getIcn()+"^"+edipi);
				} else {
					if (super.logger.isDebugEnabled()) {
				    	super.logger.debug("Call to MSDS is ignored.");
				    }					
					return null;
				}
			} else {
				if (super.logger.isDebugEnabled()) {
			    	super.logger.debug("Call to MSDS is ignored.");
			    }				
				return null;
			}
		}
		if (edipi != null) {
			if (super.logger.isDebugEnabled()) {
		    	super.logger.debug("Submitting request to MSDS using ICN and EDIPI");
		    }
		} else {
			if (super.logger.isDebugEnabled()) {
	    		super.logger.debug("Submitting request to MSDS using only ICN");
	    	}
		}
		return queryPerson;

	}

	private String getEDIPI(List correlations)
    {
    	if (correlations == null || correlations.size() == 0) {
    		return null;
    	}

    	PatientIdentifier pid = null;

		Iterator it = correlations.iterator();
		while (it.hasNext())
		{
			pid = (PatientIdentifier)it.next();
			if ("200DOD".equals(pid.getStationNumber()) && "A".equalsIgnoreCase(pid.getIdState())) {
				return pid.getIdentity();
			}
		}

		return null;
    }
	
	public IdmWebServiceDelegate getIdmServiceDelegate() {
		return idmServiceDelegate;
	}

	public void setIdmServiceDelegate(IdmWebServiceDelegate idmServiceDelegate) {
		this.idmServiceDelegate = idmServiceDelegate;
	}


}
