/*******************************************************************************
 *  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.datatypefactory;

import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.utils.EnumMapModifyMode;
import cdac.medinfo.sdk.hl7282.utils.IComponentItem;
import cdac.medinfo.sdk.hl7282.utils.IDataTypeMap;
import cdac.medinfo.sdk.hl7282.utils.IPairedCollection;
import cdac.medinfo.sdk.hl7282.utils.PairedCollection;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;

/**
 * DataTypeMap class is the implementation of IDataTypeMap.
 * DataTypeMap represents structure of a DataType as defined in HL7 standard.
 * It includes index for Component item sequence defined in DataType structure.
 * Index for Component Item starts with 1.
 */
public final class DataTypeMap implements IDataTypeMap
{
	

	private IPairedCollection<Integer,IComponentItem> objComponentItemList = null;
	private int attrIndex = 1;
	private boolean isLocked = false;

	/**
	 * Instantiates DataTypeMap
	 */
	public DataTypeMap()
	{
		this.objComponentItemList = new PairedCollection<Integer, IComponentItem>();
	}
	
	/**
	 * Sets lock on IDataTypeMap.
	 * If lock is set then new ComponentItem can not be added in DataTypeMap
	 * @param bLock value of lock
	 */
	public void setLock(boolean bLock)
	{
		if(this.isLocked && !bLock)
		this.isLocked = bLock;
	}

	/**
	 * Retrieves current status of lock for IDataTypeMap
	 * @return boolean - status of lock
	 */
	public boolean getLock()
	{
		return this.isLocked;
	}

	/**
	 * Retrieves IComponentItem for defined index.
	 * Map index starts with 1.
	 * @return IComponentItem instance of ComponentItem
	 */
	public IComponentItem getComponentItem(int iSequenceNo)
	{
		if(objComponentItemList.contains(iSequenceNo))
			return objComponentItemList.get(iSequenceNo);

		return null;
	}

	/**
	 * Adds ComponentItem to IDataTypeMap at current available index.
	 * Adds ComponentItem only if map is not in lock state.
	 * In Lock state map can be modified only if LocalExtension feature is supported.
	 * @param objComponentItem instance of Component Item
	 */
	public void addComponentItem(IComponentItem objComponentItem)
	{
		if(this.isLocked)
		{
			setLock(false);
		}
		objComponentItemList.put(attrIndex,objComponentItem);
		attrIndex++;
	}

	/**
	 * Adds ComponentItem to IDataTypeMap at given index position according to the modification mode.
	 * Adds ComponentItem only if map is not in lock state.
	 * In Lock state map can be modified only if LocalExtension feature is supported.
	 * @param objComponentItem instance of Component Item
	 * @param index sequence position
	 * @param enumModifyMode enumerated value of modification mode
	 */
	public void addComponentItem(IComponentItem objComponentItem,int index,EnumMapModifyMode enumModifyMode)
	{
		if(this.isLocked)
		{
			setLock(false);
		}
		
		switch(enumModifyMode)
		{
		case CURRENT:
		{
			objComponentItemList.put(attrIndex,objComponentItem);
			attrIndex++;
		}
		break;
		case AFTER:
		{
			IPairedCollection<Integer,IComponentItem> objTempComponentList = new PairedCollection<Integer, IComponentItem>();
			int i = 1;
			while(i < attrIndex && i <= index)
			{
				objTempComponentList.put(i,objComponentItemList.get(i));
				i++;
			}

			objTempComponentList.put(i,objComponentItem);
			while(i < attrIndex)
			{
				objTempComponentList.put(i + 1, objComponentItemList.get(i));
				i++;
			}
			this.objComponentItemList = objTempComponentList;
			attrIndex++;
		}
		break;
		case REPLACE:
		{
			if(objComponentItemList.contains(index))
				objComponentItemList.put(index,objComponentItem);
		}
		break;
		}
	}

	public int size()
	{
		return objComponentItemList.size();
	}

	/**
	 * Retrieves the Table value specified by HL7 Standard for the specified Item ID.
	 * @param iItemID Integer value of Sequence number.
	 * @return int[] - return array of Table value for specified Item ID.
	 */
	public int[] getValueTable(int iSequenceNo)
	{
		int[] intValueTableArray = null;

		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				intValueTableArray = objComponentItem.getTableNo();
				break;
			}
			index++;
		}

		return intValueTableArray;
	}

	/**
	 * Retrieves the Minimum Length of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Sequence number.
	 * @return int - return Minimum Length value for specified Item ID.
	 */
	public int getItemMinimumLength(int iSequenceNo)
	{
		int iItemMinLength = 0;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				iItemMinLength = objComponentItem.getMinimunLength();
				break;
			}
			index++;
		}
		return iItemMinLength;
	}
	
	/**
	 * Retrieves the Maximum Length of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Sequence number.
	 * @return int - return Maximum Length value for specified Item ID.
	 */
	public int getItemMaximumLength(int iSequenceNo)
	{
		int iItemMaxLength = 0;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				iItemMaxLength = objComponentItem.getMaximumLength();
				break;
			}
			index++;
		}
		return iItemMaxLength;
	}
	
	/**
	 * Retrieves the Conformance Length of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Sequence number.
	 * @return String - return Conformance Length value for specified Item ID.
	 */
	public String getItemConformanceLength(int iSequenceNo)
	{
		String iItemCLength = null;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				iItemCLength = objComponentItem.getConformanceLength();
				break;
			}
			index++;
		}
		return iItemCLength;
	}
	
	/**
	 * Retrieves the Data Type name of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Item number.
	 * @return String - return Data type name for specified Item ID.
	 */
	public String getDataTypeName(int iSequenceNo)
	{
		String strDTName = null;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				strDTName = objComponentItem.getDataType();
				break;
			}
			index++;
		}
		return strDTName;
	}

	/**
	 * Retrieves the status indicating whether the specified Item ID is optional or not.
	 * @param iItemID Integer value of Sequence number.
	 * @return boolean - the status indicating whether the specified Item ID is optional or not.
	 */
	public	boolean isOptional(int iSequenceNo)
	{
		boolean isOptional = false;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				isOptional = objComponentItem.isOptional();
				break;
			}
			index++;
		}
		return isOptional;
	}

	/**
	 * Retrieves the Field name of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Sequence number.
	 * @return String - return Field name for specified Item ID.
	 */
	public String getFieldName(int iSequenceNo)
	{
		String strFieldName = null;
		int index = 1;
		IComponentItem objComponentItem = null;
		while(index <= size())
		{
			objComponentItem = getComponentItem(index);
			if(objComponentItem.getSequenceNo() == iSequenceNo)
			{
				strFieldName = objComponentItem.getFieldName();
				break;
			}
			index++;
		}
		return strFieldName;
	}
	
	/**
	 * Retrieves a clone of IDataTypeMap
	 * @return IDataTypeMap - instance of IDataTypeMap
	 */
	public IDataTypeMap clone()
	{
		IDataTypeMap objNewDataTypeMap = new DataTypeMap();
		int i = 1;
		while(i <= size())
		{
			objNewDataTypeMap.addComponentItem(objComponentItemList.get(i));
			i++;
		}
		objNewDataTypeMap.setLock(true);
		return objNewDataTypeMap;
	}
	/**
	 * Retrieves the list of Item ID of all AttributeItems which are member of ISEgmentMap.
	 * @return ISingleCollection<Integer> - return collection of Item ID.
	 */
	public ISingleCollection<Integer> getSequenceNumberList()
	{
		ISingleCollection<Integer> objItemIDList = null;

		int iSequenceNo = 1;
		objItemIDList = new SingleCollection<Integer>();
		IComponentItem objComponentItem = null;
		while(iSequenceNo <= size())
		{
			objComponentItem = getComponentItem(iSequenceNo);
			objItemIDList.add(objComponentItem.getSequenceNo());
			iSequenceNo++;
		}

		return objItemIDList;
	}
}
