/*******************************************************************************
 *  Copyright 2017 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *    http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.hl7282.baselibs.messagedictionary;

import java.net.URL;

import cdac.medinfo.sdk.hl7282.exceptions.InvalidDictionaryException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidMessageDictionaryException;
import cdac.medinfo.sdk.hl7282.utils.EnumHL7System;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageCode;
import cdac.medinfo.sdk.hl7282.utils.EnumTriggerEvent;
import cdac.medinfo.sdk.hl7282.utils.IMap;
import cdac.medinfo.sdk.hl7282.utils.IMessageMapReader;

/**
 * MessageMapReader provides implementation to IMessageMapReader.
 * It uses IMap to represent Message structure.
 */
public final class MessageMapReader implements IMessageMapReader
{
	
	private final static String strMessageMapInfoPath = "MessageMapInfo.xml";
	private static MessageDictionary objMessageDictionary = null;

	private static IMessageMapReader objMessageMapReader = null;

	private static boolean bflag = false;

	/**
	 * Default Constructor for MessageMapReader. 
	 */
	private MessageMapReader()
	{

	}
	/**
	 * Creates instance of singleton class.
	 * @return IMessageMapReader - populated object of MessageMapReader.
	 */
	public static IMessageMapReader createInstance(EnumHL7System objEnumHL7System)throws InvalidDictionaryException
	{
		
		if(objMessageMapReader == null)
			objMessageMapReader = new MessageMapReader();
		objMessageDictionary = MessageDictionary.createInstance();

		populate(objEnumHL7System,strMessageMapInfoPath);
		populateACK();

		return objMessageMapReader;
	}

	/**
	 * Creates instance of singleton class.
	 * It internally populate acknowledgment.
	 * @return IMessageMapReader - populated object of MessageMapReader.
	 * @throws InvalidDictionaryException
	 */
	public static IMessageMapReader createInstance()throws InvalidDictionaryException
	{
		if(!bflag)
		{
			if(objMessageMapReader == null)
				objMessageMapReader = new MessageMapReader();
			objMessageDictionary = MessageDictionary.createInstance();
			populateACK();
		}
		return objMessageMapReader;
	}

	private static IMessageMapReader populateACK()
	{
		if(!bflag)
		{
			URL tempURL = MessageMapReader.class.getResource(strMessageMapInfoPath);
			populate(tempURL);
		}
		return objMessageMapReader;		
	}

	/**
	 * This method checks that for particular System DataDicionary is poulated or not.
	 * Checks that SYSTEM name from xml file retrieved from jar is same as that of Provided System name.
	 * if yes then populate it for that System.    
	 */
	private static void populate(EnumHL7System objEnumHL7System,String strResourceName) throws InvalidMessageDictionaryException
	{
		if(!objMessageDictionary.isSystemPopulated(objEnumHL7System))
		{
			MessageXMLHandler objMessageXMLHandler = new MessageXMLHandler();
			objMessageXMLHandler.populate(strResourceName,objEnumHL7System,objMessageDictionary);
		}
	}

//	/**
//	 * 
//	 * @param strResourceName
//	 * @throws InvalidMessageDictionaryException
//	 */
//	private static void populate(String strResourceName) throws InvalidMessageDictionaryException
//	{
//		MessageXMLHandler objMessageXMLHandler = new MessageXMLHandler();
//		objMessageXMLHandler.populateAcknowledgment(strResourceName, objMessageDictionary);
//		bflag = true;
//	}

	/**
	 * 
	 * @param strResourceName
	 * @throws InvalidMessageDictionaryException
	 */
	private static void populate(URL urlResource) throws InvalidMessageDictionaryException
	{
		MessageXMLHandler objMessageXMLHandler = new MessageXMLHandler();
		objMessageXMLHandler.populateAcknowledgment(urlResource, objMessageDictionary);
		bflag = true;
	}

	/*
	 * Retruns Message Structure according to enumMessageCode and EnumTriggerEvent
	 */
	private String getMessageCodeEvent(EnumMessageCode enumMessageCode,EnumTriggerEvent enumTriggerEvent)
	{
		/*
		 * Checks whether Event uses MessageStructure of another Event(Common Message Structure)
		 * If It is using Common Message Structure then change EnumTriggerEvent and EnumMessagecode according to required message structure. 
		 */
		switch(enumTriggerEvent)
		{
		case A01:
		case A04 :
		case A08 :
		case A13 :
			 enumTriggerEvent=EnumTriggerEvent.A01;
			break;
		case A05 : 
		case A14 :
		case A28 :
		case A31 :
			 enumTriggerEvent=EnumTriggerEvent.A05;
			break;
		case A06 :
		case A07 :
			enumTriggerEvent=EnumTriggerEvent.A06;
			break;
		case A09 : 
		case A10 :
		case A11 :
			enumTriggerEvent=EnumTriggerEvent.A09;
			break;
		case A21 :
		case A22 :
		case A23 :
		case A25 :
		case A26 :
		case A27 :
		case A29 :
		case A32 :
		case A33 :
			enumTriggerEvent=EnumTriggerEvent.A21;
			break;
		case A40:
		case A41:
		case A42:
			enumTriggerEvent=EnumTriggerEvent.A39;
			break;
		case A43 :
		case A49 :
			enumTriggerEvent=EnumTriggerEvent.A43;
			break;
		case A44 :
		case A47 :
			enumTriggerEvent=EnumTriggerEvent.A44;
			break;
		case A50 :
		case A51 :
			enumTriggerEvent=EnumTriggerEvent.A50;
			break;
		case A52 :
		case A53 :
		case A55 :
			enumTriggerEvent=EnumTriggerEvent.A52;
			break;
		case A61 :
		case A62 :
			enumTriggerEvent=EnumTriggerEvent.A61;
			break;
		case Q21 :
		case Q22 :
		case Q23 :
		case Q24 :
		case Q25 :
			enumTriggerEvent=EnumTriggerEvent.Q21;
			break;
		case K21 :
		case K22 :
			enumTriggerEvent=EnumTriggerEvent.K21;
			break;
		case K23 :
		case K24 :
			enumTriggerEvent=EnumTriggerEvent.K23;
			break;
		 case U10:
         case U11:
        	enumTriggerEvent=EnumTriggerEvent.U10;
				break;
         case U12:
         case U13:
        	enumTriggerEvent=EnumTriggerEvent.U12;
				break;
         case M02:
        	 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M02;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
        	 break;
		 case M04:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M04;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M05:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M05;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M06:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M06;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M07:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M07;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M08:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M08;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M09:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M09;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M10:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M10;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M11:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M11;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M12:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M12;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M13:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M13;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M14:
			 switch(enumMessageCode)
        	 {
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M15:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M15;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M16:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M16;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M17:
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M17;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
			 break;
		 case M18:	
			 switch(enumMessageCode)
        	 {
        	 case MFN:
    			 enumTriggerEvent=EnumTriggerEvent.M18;
    			 break;
        	 case MFK:
    			 enumTriggerEvent=EnumTriggerEvent.M01;
    			 break;
        	 }
  			break;
		case T01 : 
		case T03 :
		case T05 :
		case T07 :
		case T09 :
		case T11 :
			 enumTriggerEvent=EnumTriggerEvent.T01;
	  			break;
		case T02 : 
		case T04 : 
		case T06 : 
		case T08 : 
		case T10 : 
			enumTriggerEvent=EnumTriggerEvent.T02;
  			break;
		case C01:
		case C02: 
		case C03:
		case C04:
		case C05:
		case C06:
		case C07:
		case C08:
			enumTriggerEvent=EnumTriggerEvent.C01;
  			break;
		case R01:
		case R40:
			enumTriggerEvent=EnumTriggerEvent.R01;
  			break;
		case R30:	
		case R31:	
		case R32:
			enumTriggerEvent=EnumTriggerEvent.R30;
  			break;
		case R22: 
			enumTriggerEvent=EnumTriggerEvent.R22;
			break;
		case R23:
			enumTriggerEvent=EnumTriggerEvent.R23;
			break;
		case R24:
			enumTriggerEvent=EnumTriggerEvent.R24;
  			break;
		case C09:
		case C10: 
		case C11:
		case C12:
			enumTriggerEvent=EnumTriggerEvent.C09;
  			break;
		case P07:
		case P08:
			enumTriggerEvent=EnumTriggerEvent.P07;
  			break;
		case Q26 : 
		case Q27 : 
		case Q28 : 
		case Q29 : 
		case Q30 : 
			enumTriggerEvent=EnumTriggerEvent.Q26;
  			break;
		case PC1 : 
		case PC2 : 
		case PC3  :
			enumTriggerEvent=EnumTriggerEvent.PC1;
  			break;
		case PC6  : 
		case PC7  : 
		case PC8  : 
			enumTriggerEvent=EnumTriggerEvent.PC6;
  			break;
		case PCB  : 
		case PCC  : 
		case PCD  : 
			enumTriggerEvent=EnumTriggerEvent.PCB;
  			break;
		case PCG  : 
		case PCH  :
		case PCJ  : 
			enumTriggerEvent=EnumTriggerEvent.PCG;
  			break;
		case I08 : 
		case I09 : 
		case I10 : 
		case I11 :
			enumTriggerEvent=EnumTriggerEvent.I08;
  			break;
		case I12:
		case I13 : 
		case I14 : 
		case I15 : 
			enumTriggerEvent=EnumTriggerEvent.I12;
  			break;
		case I16:
		case I17 : 
		case I18 : 
			enumTriggerEvent=EnumTriggerEvent.I16;
  			break;
		case I07:
			enumMessageCode= EnumMessageCode.RQI;
			enumTriggerEvent=EnumTriggerEvent.I01;
  			break;
		case I04 : 
			switch(enumMessageCode)
			{
			case RPI:					
				enumTriggerEvent= EnumTriggerEvent.I01;
				break; 
			case RQP:					
				enumTriggerEvent= EnumTriggerEvent.I04;
				break; 
			}
			break;
		case I03 :
			switch (enumMessageCode)
			{

			case RPR:					
				enumTriggerEvent= EnumTriggerEvent.I03;
				break;

			case RQI:					
				enumTriggerEvent= EnumTriggerEvent.I01;
				break;
			}
			break;
		case I02 :
			switch (enumMessageCode)
			{
			case RPL:					
				enumTriggerEvent= EnumTriggerEvent.I02;
				break;

			case RQI:					
				enumTriggerEvent= EnumTriggerEvent.I01;
				break;
			}
			break;
		case B01:
		case B02 :
			enumTriggerEvent=EnumTriggerEvent.B01;
  			break;
		case B04:
		case B05:
		case B06:
			enumTriggerEvent=EnumTriggerEvent.B04;
  			break;
		case Q16:
		case Z83:
			enumTriggerEvent=EnumTriggerEvent.Q16;
  			break;
		case K13:
		case Z76:
		case Z78:
		case Z92:
		case Z94:
		case Z96:
			enumTriggerEvent=EnumTriggerEvent.K13;
  			break;
		case S01:
		case S02:
		case S03:
		case S04:
		case S05:
		case S06:
		case S07:
		case S08:
		case S09:
		case S10:
		case S11:
			enumTriggerEvent=EnumTriggerEvent.S01;
  			break;
		case S12 :
		case S13 :
		case S14 :
		case S15 :
		case S16 :
		case S17 :
		case S18 :
		case S19 :
		case S20 :
		case S21 :
		case S22 :
		case S23 :
		case S24 :
		case S26 :
		case S27 :
			enumTriggerEvent=EnumTriggerEvent.S12;
  			break;
  			
		case S28:
		case S29 :
			enumTriggerEvent = EnumTriggerEvent.S28;
			break;
		case S30:
			enumMessageCode = EnumMessageCode.SLR;
			enumTriggerEvent = EnumTriggerEvent.S28;
			break;
		case S32:
			enumMessageCode = EnumMessageCode.SDR;
			break;
		case S34:
		case S35:
			enumMessageCode = EnumMessageCode.SLR;
			enumTriggerEvent = EnumTriggerEvent.S28;
			break;
		case S36:
			enumMessageCode = EnumMessageCode.SDR;
			enumTriggerEvent = EnumTriggerEvent.S31;
			break;
		case S37:
			enumMessageCode = EnumMessageCode.SDR;
			enumTriggerEvent = EnumTriggerEvent.S32;
			break;
			
		}
		String strMessageCodeEvent = enumMessageCode.getValue()+"_" +enumTriggerEvent.getValue();
		return strMessageCodeEvent;
	}

	/**
	 * Retrieves Message Map for the specified code and Event(i.e Message)
	 * If trigger event is null then retrieves message map for acknowledgement
	 * @param enumMessageCode message code
	 * @param enumTriggerEvent trigger event
	 * @return ISingleCollection<ItemRowDescriptor> - Item list for the specified Segment.
	 */
	@Override
	public IMap getMessageMap(EnumMessageCode enumMessageCode,EnumTriggerEvent enumTriggerEvent)
	{
		if(enumMessageCode.equals(EnumMessageCode.ACK))
		{
			String strMessageCode = enumMessageCode.getValue();
			return objMessageDictionary.getMessageMap(strMessageCode);
		}
		else
		{
			String strMessageCodeEvent=getMessageCodeEvent(enumMessageCode, enumTriggerEvent);
			
			return objMessageDictionary.getMessageMap(strMessageCodeEvent);
		}
	}
		
}
