/*******************************************************************************
 *  Copyright 2017-2018 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.dcm30_04.services.association;

import java.util.Locale;

import cdac.medinfo.sdk.dcm30_04.services.pdu.AbstractSyntaxItem;
import cdac.medinfo.sdk.dcm30_04.services.pdu.RQPresContextItem;
import cdac.medinfo.sdk.dcm30_04.services.pdu.TransferSyntaxItem;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;
import cdac.medinfo.sdk.dcm30_04.utils.ICollectionIterator;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * This Class implements setters and getters for all attributes of RQ Presentation Context.
 * It contains Abstract syntax and collection of supported transfer syntax.
 */
public class RQPresContext  
{
	/** The abstract syntax name. */
	String strAbstractSyntaxName;

	/** The Transfer syntax collection supported for abstract syntax name. */
	ISingleCollection<String> TSCollection;

	/**
	 * Instantiates request presentation context.
	 */
	public RQPresContext() 
	{
		TSCollection = new SingleCollection<String>();
	}

	/**
	 * Instantiates RQ Presentation context according to parameters given.
	 * @param bPresContextId byte value of The Presentation context ID for Request Presentation Context.
	 * @param strAbstractSyntaxName string value of abstract syntax name.
	 * @param strTransferSyntax Transfer syntax collection supported for abstract syntax name.
	 */
	public RQPresContext(String strAbstractSyntaxName, ISingleCollection<String> strTransferSyntax)
	{
		this.strAbstractSyntaxName = strAbstractSyntaxName;
		this.TSCollection = strTransferSyntax;
	}

	/**
	 * Retrieves the Abstract Syntax Name.
	 * @return String - value of Abstract Syntax Name.
	 */
	public String getAbstractSyntaxName() 
	{
		return strAbstractSyntaxName;
	}

	/**
	 * Sets the Abstract Syntax Name.
	 * @param strAbstractSyntaxName value of Abstract Syntax Name.
	 */
	public void setAbstractSyntaxName(String strAbstractSyntaxName) 
	{
		this.strAbstractSyntaxName = strAbstractSyntaxName;
	}

	/**
	 * Retrieves the collection of Transfer Syntax Name.
	 * @return ISingleCollection<String> - collection of Transfer Syntax Name.
	 */
	public ISingleCollection<String> getTSCollection() 
	{
		return TSCollection;
	}

	/**
	 * Sets the collection of Transfer Syntax Name.
	 * @param collection - collection of Transfer Syntax Name.
	 */
	public void setTSCollection(ISingleCollection<String> collection) 
	{
		TSCollection = collection;
	}

	public void addTransferSyntax(String strTransferSyntax)
	{
		if( TSCollection== null)
		{
			TSCollection = new SingleCollection<String>();
		}
		TSCollection.add(strTransferSyntax);
	}

	/**
	 * Initializes the RQPresContext according to given RQPresContext Item.
	 * @param objRQPresContextItem instance of RQPresContext Item.
	 */
	public void populate(RQPresContextItem objRQPresContextItem)
	{
		AbstractSyntaxItem objAbstractSyntaxItem = objRQPresContextItem.getAbstractSyntaxItem();
		if(objAbstractSyntaxItem != null)
			this.strAbstractSyntaxName = objAbstractSyntaxItem.getAbstractSyntaxName();

		this.TSCollection = new SingleCollection<String>();
		ICollectionIterator<TransferSyntaxItem> objTSIterator = objRQPresContextItem.getTransferSyntaxItemCollection().iterator();
		while(objTSIterator.hasNext())
			TSCollection.add(objTSIterator.next().getTSName());
	}

	/**
	 * Initializes the RQPresContext Item.
	 * @return RQPresContextItem instance of RQ PresContext Item.
	 */
	public RQPresContextItem getItem()
	{
		RQPresContextItem objRQPresContextItem = new RQPresContextItem();
		AbstractSyntaxItem objAbstractSyntaxItem = new AbstractSyntaxItem();
		objAbstractSyntaxItem.setAbstractSyntaxName(this.getAbstractSyntaxName());
		objRQPresContextItem.setAbstractSyntaxItem(objAbstractSyntaxItem);

		ISingleCollection<TransferSyntaxItem> objTSItemCollection = new SingleCollection<TransferSyntaxItem>();
		ICollectionIterator<String> TSIterator = this.getTSCollection().iterator();
		TransferSyntaxItem objTransferSyntaxItem = null;
		while(TSIterator.hasNext())
		{
			objTransferSyntaxItem = new TransferSyntaxItem();
			objTransferSyntaxItem.setTSName(TSIterator.next());
			objTSItemCollection.add(objTransferSyntaxItem);
		}
		objRQPresContextItem.setTransferSyntaxItemCollection(objTSItemCollection);

		return objRQPresContextItem;
	}

	/**
	 * This function checks whether the presentation context provided by user is subset of RQ presentation context.
	 * @param objTempRQPesContext object of RQ presentation context given by user.
	 * @return boolean - true if objTempRQPesContext is subset of RQ Presentation context.
	 * 					 false if objTempRQPesContext is not subset of RQ Presentation context.
	 */
	public boolean isSubSet(RQPresContext objTempRQPesContext)
	{
		if(this.strAbstractSyntaxName.equals(objTempRQPesContext.getAbstractSyntaxName()))
		{
			ICollectionIterator<String> objStrTransferSyntaxIterator = this.TSCollection.iterator();

			while(objStrTransferSyntaxIterator.hasNext())
			{
				boolean isSubSet = false;
				String strTransferSyntax = objStrTransferSyntaxIterator.next();
				ICollectionIterator<String> objStrTempTransferSyntaxIterator = objTempRQPesContext.getTSCollection().iterator();
				while(objStrTempTransferSyntaxIterator.hasNext())
				{
					String strTempTransferSyntax = objStrTempTransferSyntaxIterator.next();
					if(strTempTransferSyntax.equals(strTransferSyntax))
					{
						isSubSet = true;
						break;
					}
				}
				if(!isSubSet)
					return false;
			}
			return true;
		}
		return false;
	}

	/**
	 * Validates the RQPresContext for mandatory attributes and Default TS.
	 * @return integer 1 - if AbstractSyntaxName is null.
	 * 				   2 - if collection of TS or its size is null.
	 * 				   3 - if collection of TS contains null value.
	 * 				   4 - if collection of TS does not contain default value of TS for corresponding AS.
	 * 				   0 - if validation is successful.
	 */
	public int validate(ISingleCollection<String> objTSCollection)
	{
		int ival = this.validate();
		if(ival !=0)
			return ival;

		if(!validateTSCollForDef(TSCollection))
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","AssociationException.DefTSNotPresent",new Locale(DicomConfig.createInstance().getLocale())) 
						+ this.strAbstractSyntaxName);
			}
			return 4;
		}
		return 0;
	}

	/**
	 * Validates the RQPresContext for mandatory attributes.
	 * @return integer 1 - if AbstractSyntaxName is null.
	 * 				   2 - if collection of TS or its size is null.
	 * 				   3 - if collection of TS contains null value.
	 * 				   0 - if validation is successful.
	 */
	public int validate()
	{
		if(strAbstractSyntaxName == null)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ResourceBundleWrapper.getValue("exceptions", "AssociationException.NULLAbstractSyntax", new Locale(DicomConfig.createInstance().getLocale())));
			}
			return 1;
		}
		else if(TSCollection == null || TSCollection.size() == 0)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ResourceBundleWrapper.getValue("exceptions", "AssociationException.InvalidTSList", new Locale(DicomConfig.createInstance().getLocale())));
			}
			return 2;
		}
		else
		{
			for(String strTS : TSCollection)
			{
				if(null == strTS)
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger.getLogger().log(ResourceBundleWrapper.getValue("exceptions", "AssociationException.InvalidTSList", new Locale(DicomConfig.createInstance().getLocale())));
					}
					return 3;
				}
			}
		}
		return 0;
	}

	/**
	 * Validates the collection of Transfer syntax for presence of Default transfer syntax presence
	 * @param objTSCollection Single collection of Transfer Syntax
	 * @return true - if validation is successful.
	 * 		   false - if validation fails.
	 */
	private boolean validateTSCollForDef(ISingleCollection<String> objTSCollection)
	{
		if(objTSCollection.size() > 1)
		{
			if(objTSCollection.contains(DicomConstants.TS_RLE_LOSSLESS)
					|| objTSCollection.contains(DicomConstants.TS_EXPLICIT_VR_LITTLE_ENDIAN) 
					|| objTSCollection.contains(DicomConstants.TS_EXPLICIT_VR_BIG_ENDIAN)
					|| objTSCollection.contains(DicomConstants.TS_DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN))
			{
				if(!objTSCollection.contains(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN))
				{
					return false;
				}
			}
			else if(objTSCollection.contains(DicomConstants.TS_JPEG_LOSSLESS_NON_HIERARCHICAL_PROCESS_14))
			{
				if(!objTSCollection.contains(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN)
						&& !objTSCollection.contains(DicomConstants.TS_DEFAULT_LOSSLESS_JPEG))
				{
					return false;
				}
			}
			else if(objTSCollection.contains(DicomConstants.TS_DEFAULT_LOSSLESS_JPEG))
			{
				if(!objTSCollection.contains(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN))
				{
					return false;
				}

			}
			return true;
		}
		return true;
	}
}