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

import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.utils.EnumMapModifyMode;
import cdac.medinfo.sdk.hl7282.utils.IAttributeItem;
import cdac.medinfo.sdk.hl7282.utils.IPairedCollection;
import cdac.medinfo.sdk.hl7282.utils.ISegmentMap;
import cdac.medinfo.sdk.hl7282.utils.PairedCollection;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;

/**
 * SegmentMap class is the implementation of ISegmentMap.
 * SegmentMap represents structure of a segment as per defined in HL7 standard.
 * It includes index for attribute item sequence defined in segment structure.
 * Index for Attribute Item starts with 1.
 */
public final class SegmentMap implements ISegmentMap
{
	

	private IPairedCollection<Integer,IAttributeItem> objAttributeItemList = null;
	private int attrIndex = 1;
	private boolean isLocked = false;

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

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

	/**
	 * Retrieves IAttributeItem for defined index.
	 * Map index starts with 1.
	 * @return IAttributeItem instance of AttributeItem
	 */
	public IAttributeItem getAttributeItem(int index)
	{
		if(objAttributeItemList.contains(index))
			return objAttributeItemList.get(index);

		return null;
	}

	/**
	 * Adds AttributeItem to ISegmentMap at current available index.
	 * Adds AttributeItem only if map is not in lock state.
	 * In Lock state map can be modified only if LocalExtension feature is supported.
	 * @param objAttributeItem instance of Attribute Item
	 */
	public void addAttributeItem(IAttributeItem objAttributeItem)
	{
		if(this.isLocked)
		{
			setLock(false);
		}
		objAttributeItemList.put(attrIndex,objAttributeItem);
		attrIndex++;
	}

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

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

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

	/**
	 * 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> getItemIDList()
	{
		ISingleCollection<Integer> objItemIDList = null;

		int index = 1;
		objItemIDList = new SingleCollection<Integer>();
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			objItemIDList.add(objAttributeItem.getItemID());
			index++;
		}

		return objItemIDList;
	}

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

		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				intValueTableArray = objAttributeItem.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 Item ID
	 * @return int - return Minimum Length value for specified Item ID
	 */
	public int getItemMinimumLength(int iItemID)
	{
		int iItemMinLength = 0;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				iItemMinLength = objAttributeItem.getMinimumLength();
				break;
			}
			index++;
		}
		return iItemMinLength;
	}
	
	/**
	 * Retrieves the Maximum Length of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Item ID
	 * @return int - return Maximum Length value for specified Item ID
	 */
	public int getItemMaximumLength(int iItemID)
	{
		int iItemMaxLength = 0;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				iItemMaxLength = objAttributeItem.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 Item ID
	 * @return String - return Conformance Length value for specified Item ID
	 */
	public String getItemConformanceLength(int iItemID)
	{
		String iItemCLength = null;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				iItemCLength = objAttributeItem.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 ID
	 * @return String - return Data type name for specified Item ID
	 */
	public String getDataTypeName(int iItemID)
	{
		String strDTName = null;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				strDTName = objAttributeItem.getDataType();
				break;
			}
			index++;
		}
		return strDTName;
	}

	/**
	 * Retrieves the status indicating whether the specified Item ID is repeatable or not. 
	 * @param iItemID Integer value of Item ID
	 * @return boolean - the status indicating whether the specified Item ID is repeatable or not
	 */
	public boolean isRepeatable(int iItemID)
	{
		boolean isRepeat = false;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				isRepeat = objAttributeItem.isRepeatable();
				break;
			}
			index++;
		}
		return isRepeat;
	}
	
	 /**
	 * Retrieves Occurrence for attribute defined by HL7 standard in segment.
	 * @param iItemID Integer value of Item ID
	 * @return int - Number of Occurrence of the attribute
	 */
	public int getOccurrence(int iItemID)
	{
		int intOccurrence = 1;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				intOccurrence = objAttributeItem.getOccurrence();
				break;
			}
			index++;
		}
		
		return intOccurrence;
	}

	/**
	 * Retrieves the status indicating whether the specified Item ID is optional or not.
	 * @param iItemID Integer value of Item ID
	 * @return boolean - the status indicating whether the specified Item ID is optional or not
	 */
	public	boolean isOptional(int iItemID)
	{
		boolean isOptional = false;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				isOptional = objAttributeItem.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 Item ID
	 * @return String - return Field name for specified Item ID
	 */
	public String getFieldName(int iItemID)
	{
		String strFieldName = null;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				strFieldName = objAttributeItem.getFieldName();
				break;
			}
			index++;
		}
		return strFieldName;
	}
	
	/**
	 * Retrieves the Sequence number of an Item specified by HL7 Standard for the specified Item.
	 * @param iItemID Integer value of Item ID.
	 * @return int - return Sequence number for specified Item ID.
	 */
	@Override
	public int getSequenceNo(int iItemID) {
		int sequenceNo = 0;
		int index = 1;
		IAttributeItem objAttributeItem = null;
		while(index <= size())
		{
			objAttributeItem = getAttributeItem(index);
			if(objAttributeItem.getItemID() == iItemID)
			{
				sequenceNo = objAttributeItem.getSequenceNo();
				break;
			}
			index++;
		}
		return sequenceNo;
	}
	
	/**
	 * Retrieves a clone of ISegmentMap.
	 * @return ISegmentMap - instance of ISegmentMap
	 */
	public ISegmentMap clone()
	{
		ISegmentMap objNewSegmentMap = new SegmentMap();
		int i = 1;
		while(i <= size())
		{
			objNewSegmentMap.addAttributeItem(objAttributeItemList.get(i));
			i++;
		}
		objNewSegmentMap.setLock(true);
		return objNewSegmentMap;
	}
}
