package cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.querycancel;

import java.util.Locale;

import cdac.medinfo.sdk.hl7282.baselibs.CWE;
import cdac.medinfo.sdk.hl7282.baselibs.segmentfactory.DataElementFactory;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSA;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSH;
import cdac.medinfo.sdk.hl7282.baselibs.segments.QID;
import cdac.medinfo.sdk.hl7282.baselibs.segments.QPD;
import cdac.medinfo.sdk.hl7282.baselibs.segments.SegmentSet;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegment;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegmentSet;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidMessageException;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IClientQueryCancellation;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageCode;
import cdac.medinfo.sdk.hl7282.utils.EnumSegments;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.HL7Logger;
import cdac.medinfo.sdk.hl7282.utils.IMultiValuedPairedCollection;
import cdac.medinfo.sdk.hl7282.utils.IPairedCollection;
import cdac.medinfo.sdk.hl7282.utils.MultiValuedPairedCollection;
import cdac.medinfo.sdk.hl7282.utils.PairedCollection;
import cdac.medinfo.sdk.hl7282.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;

/**
 * This class provides the Cancellation Message against the Query Message, if user has set the Agent.
 */
public class ClientSideQCNAgent implements IClientQueryCancellation
{
	
	/**Collection of query id for all queries.*/
	ISingleCollection<String> objClientQueryIDCollection = null;

	/**Collection of query id for which cancellation query is triggered.*/
	ISingleCollection<String> objCancelledQueryIDCollection = null;

	/**Collection of Canceled Messages stored. */
	ISingleCollection<ISegmentSet> objStoredCancelledessages =null;

	/**Collection of QueryId and MessageControlID */
	IPairedCollection<String,String> objQueryMctrlIDCollection =null;

	/**This boolean value is set to store canceled messages.*/
	boolean bStoreCancelledMessage = true;

	/**Multivalued paired collection of Query id and Segments.*/ 
	IMultiValuedPairedCollection<String, ISegment> objQueryTagSegmentsCollection = null;

	public ClientSideQCNAgent()
	{
		objClientQueryIDCollection = new SingleCollection<String> ();
		objCancelledQueryIDCollection = new SingleCollection<String> ();
		objStoredCancelledessages = new SingleCollection<ISegmentSet> ();
		objQueryMctrlIDCollection = new PairedCollection<String, String>();
		objQueryTagSegmentsCollection = new MultiValuedPairedCollection<String, ISegment>(); 
	}
	
	/**
	 * This method will process the sending queries by client. 
	 * This will keeps track for Query Id and for Canceled query.
	 * @return boolean - This will return if received Segment Set is invalid.
	 */
	public boolean processSend(ISegmentSet objSegmentSet) 
	{
		MSH objMSHSegment = null;
		String strQueryID = null; 
		ISingleCollection<ISegment> objSegmentCollection = objSegmentSet.getList();
		if(objSegmentCollection!= null && objSegmentCollection.size()>0)
		{
			int iSegSetSize = objSegmentCollection.size();
			boolean isMessageHeaderSet = false;
			for(int iRead=0;iRead<iSegSetSize;iRead++)
			{
				ISegment objSegment = null;
				objSegment = objSegmentCollection.elementAt(iRead);
				if(objSegment == null)
					throw new InvalidMessageException(this.getClass().getSimpleName());
				EnumSegments enumSegments = (EnumSegments) objSegment.getName();
				switch(enumSegments)
				{
				case HL7_SEG_MSH:
					if(false == isMessageHeaderSet)
					{
						objMSHSegment = (MSH)objSegment;
						isMessageHeaderSet = true;
					}
					else
						throw new InvalidMessageException(this.getClass().getSimpleName());
					break;
				case HL7_SEG_QPD:
					QPD objQPDSegment= (QPD)objSegment;
					strQueryID =(String)objQPDSegment.getQueryTag().getValue();
					break;
				case HL7_SEG_QID:
					QID objQIDSegment = (QID)objSegment;
					strQueryID =(String)objQIDSegment.getQueryTag().getValue();
					break;
				}
			}
		}
		// If this method returns true then in MessageAgent exception will be thrown.
		// If while sending query from client if entry is not done then add.
		if(objMSHSegment!=null && objMSHSegment.getMessageType().getMessageCode().getValue().equals(EnumMessageCode.QCN.getValue()))
		{
			if(objClientQueryIDCollection.size() > 0)
			{
				if(objClientQueryIDCollection.contains(strQueryID))
				{
					//Add entry in collection of canceled query id's and remove it from the collection of Query id.
					//checking of repetitive query id will not be part of QCN agent. 
					objCancelledQueryIDCollection.add(strQueryID);
					objClientQueryIDCollection.remove(strQueryID);

					String strQueryCancelled = ResourceBundleWrapper.getValue("exceptions", "QC_QueryCancelled",new Locale(HL7Config.createInstance().getLocale()))+strQueryID;
					if(HL7Config.createInstance().isLoggingOn())
					{
						HL7Logger objhl7Logger = HL7Logger.getLogger();
						objhl7Logger.log(strQueryCancelled);
					}

					//Status logging
					if(HL7Config.createInstance().isLoggingOn())
					{
						String strSendingMessage = ResourceBundleWrapper.getValue("exceptions", "QCN_SendingMessage",new Locale(HL7Config.createInstance().getLocale())) + strQueryID;
						HL7Logger objHLogger = HL7Logger.getLogger();
						objHLogger.log(strSendingMessage);
					}
				}
				else
					throw new InvalidMessageException(ResourceBundleWrapper.getValue("exceptions", "QC_NOQuery",new Locale(HL7Config.createInstance().getLocale()))+strQueryID);
			}
			else
				throw new InvalidMessageException(ResourceBundleWrapper.getValue("exceptions", "QC_InvalidQueryCancel",new Locale(HL7Config.createInstance().getLocale()))+strQueryID);
		}//This will add query id for those query which are triggered no repetitive query id is inserted. 
		else 
		{
			if(!objClientQueryIDCollection.contains(strQueryID))
				objClientQueryIDCollection.add(strQueryID);
			objQueryTagSegmentsCollection.put(strQueryID, objSegmentCollection);
			objQueryMctrlIDCollection.put((String)objMSHSegment.getMessageControlID().getValue(),strQueryID);

			//Status logging
			if(HL7Config.createInstance().isLoggingOn())
			{
				String strSendingMessage = ResourceBundleWrapper.getValue("exceptions", "QCN_SendingMessage",new Locale(HL7Config.createInstance().getLocale())) + strQueryID;
				HL7Logger objHLogger = HL7Logger.getLogger();
				objHLogger.log(strSendingMessage);
			}
			return false;
		}
		return true;
	}
	
	/**
	 * This method returns the Collection of Segment Set which are canceled by user.
	 * @return ISingleCollection<ISegmentSet> Collection of Segment Set. 
	 */
	public ISingleCollection<ISegmentSet> getCancelledMessages() 
	{
		if(bStoreCancelledMessage)
			return objStoredCancelledessages;
		return null;
	}
	
	/**
	 * This method will return all collection of query id for which cancellation query is triggered.
	 * @return ISingleCollection<String> collection of Query id.
	 */
	public ISingleCollection<String> getCancelledQueries()
	{
		ISingleCollection<String> objQueryIdCollection = new SingleCollection<String>();
		for(String objQueryId :objCancelledQueryIDCollection)
		{
			objQueryIdCollection.add(objQueryId);
		}
		return objQueryIdCollection;
	}
	
	/**
	 * This method keeps track for the Responses received.
	 * This also checks that received Segment set is canceled response.
	 * if it is store it in Collection.
	 * @return boolean - true if received Segment set is canceled else false. 
	 */
	public boolean processReceive(ISegmentSet objSegmentSet) 
	{
		try
		{
			String strMessageControlID = null; 
			ISingleCollection<ISegment> objSegmentCollection = objSegmentSet.getList();
			if(objSegmentCollection!= null && objSegmentCollection.size()>0)
			{
				int iSegSetSize = objSegmentCollection.size();
				boolean isMessageHeaderSet = false;
				for(int iRead=0;iRead<iSegSetSize;iRead++)
				{
					ISegment objSegment = null;
					objSegment = objSegmentCollection.elementAt(iRead);
					if(objSegment == null)
						throw new InvalidMessageException(this.getClass().getSimpleName());
					EnumSegments enumSegments = (EnumSegments) objSegment.getName();
					switch(enumSegments)
					{
					case HL7_SEG_MSH:
						if(false == isMessageHeaderSet)
							isMessageHeaderSet = true;
						else
							throw new InvalidMessageException(this.getClass().getSimpleName());
						break;
					case HL7_SEG_MSA:
						MSA objMSASegment = (MSA)objSegment;
						strMessageControlID =(String)objMSASegment.getMessageControlID().getValue();
						break;
					}
				}
				//Client Receives response and verify it is canceled then add that in collection 
				//if it is set by user else remove.
				String strQueryIdentifier = objQueryMctrlIDCollection.get(strMessageControlID);
				if(objCancelledQueryIDCollection.contains(strQueryIdentifier))
				{
					objClientQueryIDCollection.remove(strQueryIdentifier);
					if(bStoreCancelledMessage)
						objStoredCancelledessages.add(objSegmentSet);

					//Status logging
					if(HL7Config.createInstance().isLoggingOn())
					{
						String strSendingMessage = ResourceBundleWrapper.getValue("exceptions", "QCN_RecievedMessage",new Locale(HL7Config.createInstance().getLocale())) + strQueryIdentifier;
						HL7Logger objHLogger = HL7Logger.getLogger();
						objHLogger.log(strSendingMessage);
					}
					return true;
				}
				else
				{
					objClientQueryIDCollection.remove(strQueryIdentifier);

					//Status logging
					if(HL7Config.createInstance().isLoggingOn())
					{
						String strSendingMessage = ResourceBundleWrapper.getValue("exceptions", "QCN_RecievedMessage",new Locale(HL7Config.createInstance().getLocale())) + strQueryIdentifier;
						HL7Logger objHLogger = HL7Logger.getLogger();
						objHLogger.log(strSendingMessage);
					}
				}
			}
			return false;
		}
		catch(InvalidMessageException ime)
		{
			if(HL7Config.createInstance().isLoggingOn())
			{
				HL7Logger objHLogger = HL7Logger.getLogger();
				objHLogger.log(ime);
			}
			throw ime;	
		}
	}
	
	/**
	 * This will set the status whether to store canceled response messages or not.
	 */
	public void setStoreCancelledMessage(boolean bStoreCancelledMessage)
	{
		this.bStoreCancelledMessage = bStoreCancelledMessage;
	}
	
	/**
	 * This method will generate segment set for QCN^J01.
	 * @param strQueryId Query Id for which to generate Segment Set.
	 * @return ISegmentSet object of Segment set. 
	 */
	public ISegmentSet generateCancellationQuery(String strQueryId) 
	{
		if(strQueryId!=null && objQueryTagSegmentsCollection.contains(strQueryId))
		{
			QPD objQPDSegment =null;
			QID objQIDSegment =null;
			ISingleCollection<ISegment> objSegmentCollection = objQueryTagSegmentsCollection.get(strQueryId);
			if(objSegmentCollection!= null && objSegmentCollection.size()>0)
			{
				ISegmentSet objSegmentSetPopulated = new SegmentSet();
				int iSegSetSize = objSegmentCollection.size();
				boolean isMessageHeaderSet = false;
				for(int iRead=0;iRead<iSegSetSize;iRead++)
				{
					ISegment objSegment = null;
					objSegment = objSegmentCollection.elementAt(iRead);
					if(objSegment == null)
						throw new InvalidMessageException(this.getClass().getSimpleName());
					EnumSegments enumSegments = (EnumSegments) objSegment.getName();
					switch(enumSegments)
					{
					case HL7_SEG_MSH:
						if(false == isMessageHeaderSet)
						{
							MSH objMSHSegment = (MSH)objSegment;
							MSH objMSH = new MSH();
							objMSH.setFieldSeparator(objMSHSegment.getFieldSeparator());
							objMSH.setEncodingChars(objMSHSegment.getEncodingChar());
							objMSH.setDateTimeOfMessage(objMSHSegment.getDateTimeOfMessage());
							objMSH.setMessageType("QCN","J01","QCN_J01");
							objMSH.setMessageControlID(objMSHSegment.getMessageControlID());
							objMSH.setProcessingID(objMSHSegment.getProcessingID());
							objMSH.setVersionID(objMSHSegment.getVersionID());

							objSegmentSetPopulated.addSegment(objMSH);
							isMessageHeaderSet = true;
						}
						else
							throw new InvalidMessageException(this.getClass().getSimpleName());
						break;
					case HL7_SEG_QPD:
						objQPDSegment = (QPD)objSegment;
						objQIDSegment = new QID();
						objQIDSegment.setQueryTag(strQueryId);
						objQIDSegment.setMessageQueryName(objQPDSegment.getMessageQueryName());
						objSegmentSetPopulated.addSegment(objQIDSegment);
						break;
					}
				}//If any Segment like QPD is not present then for Message Query name field internally populated.
				if(objQIDSegment==null)
				{
					objQIDSegment = new QID();
					objQIDSegment.setQueryTag(strQueryId);
					DataElementFactory objDataElementFactory = DataElementFactory.createInstance();
					CWE objCE =(CWE)objDataElementFactory.getDataElement(EnumSegments.HL7_SEG_QID.getValue(),1375);
					objCE.setIdentifier("AB");
					objCE.setText("TEXT2");
					objCE.setNameOfCodingSystem("HL7");
					objCE.setAlternateIdentifier("AI3");
					objCE.setAlternateText("AT3");
					objCE.setNameOfAlternateCodingSystem("98");
					objQIDSegment.setMessageQueryName(objCE);
					objSegmentSetPopulated.addSegment(objQIDSegment);
				}
				return objSegmentSetPopulated;
			}
		}
		else if(HL7Config.createInstance().isLoggingOn())
		{
			HL7Logger objHL7Logger = HL7Logger.getLogger();
			String strLogMessage = ResourceBundleWrapper.getValue("exceptions","QIC_QueryIdNotPresent",new Locale(HL7Config.createInstance().getLocale()));
			objHL7Logger.log(strLogMessage);
		}
		return null;
	}
}
