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

package gov.va.med.esr.common.rule.service.impl;

import java.util.Iterator;

import org.apache.commons.lang.Validate;

import gov.va.med.esr.common.model.lookup.MessageType;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.rule.data.ConsistencyCheckInputData;
import gov.va.med.esr.common.rule.service.ConsistencyCheckException;
import gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.trigger.PersonTriggerEvent;
import gov.va.med.fw.hl7.Message;
import gov.va.med.fw.model.lookup.SeverityType;
import gov.va.med.fw.rule.AbstractRuleValidationService;
import gov.va.med.fw.rule.RuleDataAware;
import gov.va.med.fw.rule.RuleParameters;
import gov.va.med.fw.rule.SimpleValidatableRule;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.validation.ValidationFieldMessage;
import gov.va.med.fw.validation.ValidationMessages;

/**
 * Executes Consistency Checks for a Person, Message, and/or PersonTriggerEvent.
 * The data can come from any of the aforementioned objects depending
 * what makes the most sense to check against.
 * 
 * Created Jul 31, 2006 2:55:13 PM
 * 
 * @author DNS   BOHMEG
 */
public class ConsistencyCheckRuleServiceImpl extends
	AbstractRuleValidationService implements
		ConsistencyCheckRuleService {
	/**
    * An instance of serialVersionUID 
    */
   private static final long serialVersionUID = 4602943090051490156L;
   private LookupService lookupService;
	private String consistencyCheckRuleParameters;

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutbound(gov.va.med.esr.common.model.person.Person,
	 *      gov.va.med.esr.common.model.lookup.MessageType)
	 */
	public void processConsistencyChecksForMessage(Person person, PersonTriggerEvent triggerEvent, Message message,
			MessageType.Code type) throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, type);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutboundZ04(gov.va.med.esr.common.model.person.Person)
	 */
	public void processConsistencyChecksForOutboundZ04(Person person, PersonTriggerEvent triggerEvent, Message message)
			throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, MessageType.CODE_ORUZ04_TO_SITE);		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutboundZ05(gov.va.med.esr.common.model.person.Person)
	 */
	public void processConsistencyChecksForOutboundZ05(Person person, PersonTriggerEvent triggerEvent, Message message)
			throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, MessageType.CODE_ORUZ05_TO_SITE);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutboundZ06(gov.va.med.esr.common.model.person.Person)
	 */
	public void processConsistencyChecksForOutboundZ06(Person person, PersonTriggerEvent triggerEvent, Message message)
			throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, MessageType.CODE_ORUZ06_TO_SITE);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutboundZ10(gov.va.med.esr.common.model.person.Person)
	 */
	public void processConsistencyChecksForOutboundZ10(Person person, PersonTriggerEvent triggerEvent, Message message)
			throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, MessageType.CODE_ORUZ10_TO_SITE);
	}

	private MessageType getMessageType(MessageType.Code messageTypeCode) throws ServiceException {
		return getLookupService().getMessageTypeByCode(messageTypeCode.getCode());
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.esr.common.rule.service.ConsistencyCheckRuleService#processConsistencyChecksForOutboundZ11(gov.va.med.esr.common.model.person.Person)
	 */
	public void processConsistencyChecksForOutboundZ11(Person person, PersonTriggerEvent triggerEvent, Message message)
			throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, MessageType.CODE_ORUZ11_TO_SITE);
	}

	private void executeConsistencyChecks(Person person, PersonTriggerEvent triggerEvent, Message message, MessageType.Code messageTypeCode) throws ServiceException {
		executeConsistencyChecks(person, triggerEvent, message, getMessageType(messageTypeCode));
	}
	
	private void executeConsistencyChecks(Person person, PersonTriggerEvent triggerEvent, Message message,  MessageType messageType) throws ServiceException {
		/* since Consistency Checks can check against any of the Person, PersonTriggerEvent, or Message, there
		 * may be times when some of those inputs are null.  Therefore do not validate those inputs
		 */
		Validate.notNull(messageType, "MessageType can not be null");
		
		// data (note that the Person and the built message are passed to ILog - in some cases the BAL rule may check one or the other)
		RuleDataAware data = new ConsistencyCheckInputData(person, triggerEvent, message, messageType);
		// parameters (works on the data)
		RuleParameters params = getRuleParameters(consistencyCheckRuleParameters);
		
		// do the validation
		ValidationMessages msgs = validate(new SimpleValidatableRule(SimpleValidatableRule.EXHAUSTIVE, params, data));
		
		// must see if should throw ConsistencyCheckException	
		if(msgs != null && !msgs.isEmpty()) {			
			ConsistencyCheckException e = new ConsistencyCheckException(msgs);
			ValidationFieldMessage msg = null;
			Iterator itr = msgs.get();
			while(itr.hasNext()) {
				msg = (ValidationFieldMessage) itr.next();
				if(SeverityType.ERROR.equals(msg.getSeverity())) {					
					e.setBlocking(true);
					break;
				}
			}
			throw e;
		}
	}
	
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull(this.consistencyCheckRuleParameters, "consistencyCheckRuleParameters property is required");
		Validate.notNull(this.lookupService, "lookupService property is required");
	}

	/**
	 * @return Returns the lookupService.
	 */
	public LookupService getLookupService() {
		return lookupService;
	}

	/**
	 * @param lookupService The lookupService to set.
	 */
	public void setLookupService(LookupService lookupService) {
		this.lookupService = lookupService;
	}

	/**
	 * @return Returns the consistencyCheckRuleParameters.
	 */
	public String getConsistencyCheckRuleParameters() {
		return consistencyCheckRuleParameters;
	}

	/**
	 * @param consistencyCheckRuleParameters The consistencyCheckRuleParameters to set.
	 */
	public void setConsistencyCheckRuleParameters(
			String consistencyCheckRuleParameters) {
		this.consistencyCheckRuleParameters = consistencyCheckRuleParameters;
	}	
}
