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



import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumOverlayType;
import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
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.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

// TODO: Auto-generated Javadoc
/**
 * This Class represents Overlay Plane.
 * An Overlay Plane describes graphics or bit-mapped text
 * that is associated with an Image or has its own existence within a Series.
 * In this The Group Number allowed are in the series 60xx, i.e allows the repeating Group.
 * 
 * 
 */
public class OverlayPlaneModule extends Module  
{


	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;
	// 

	/**
	 * Creates an Overlay Plane Module with default initialization.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public OverlayPlaneModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		//Note that Here the group number 60xx is replaced by 6000.	 
		objSingleCollection.add(new Tag(0x6000,0x0010));
		objSingleCollection.add(new Tag(0x6000,0x0011));
		objSingleCollection.add(new Tag(0x6000,0x0022));
		objSingleCollection.add(new Tag(0x6000,0x0040));
		objSingleCollection.add(new Tag(0x6000,0x0045));
		objSingleCollection.add(new Tag(0x6000,0x0050));
		objSingleCollection.add(new Tag(0x6000,0x0100));
		objSingleCollection.add(new Tag(0x6000,0x0102));
		objSingleCollection.add(new Tag(0x6000,0x1301));
		objSingleCollection.add(new Tag(0x6000,0x1302));
		objSingleCollection.add(new Tag(0x6000,0x1303));
		objSingleCollection.add(new Tag(0x6000,0x1500));
		objSingleCollection.add(new Tag(0x6000,0x3000));//Type 1C
	}

	/**
	 * This method checks the DataSet according the rules of the Overlay Plane Module.
	 * 
	 * @return boolean - status of validation as success or failure
	 * 
	 * @throws InvalidModuleException the invalid module exception
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{		
			if(!(isPresent(0x6000,0x0010)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0010");
			else if(!(isPresent(0x6000,0x0011)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0011");
			else if(!(isPresent(0x6000,0x0040)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0040");
			else if(!(isPresent(0x6000,0x0050)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0050");
			else if(!(isPresent(0x6000,0x0100)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0100");
			else if(!(isPresent(0x6000,0x0102)))
				throw new MandatoryMissingException("Missing Mandatory Element 6000,0102");
			//Checking for type 1C 
			// DE (6000,3000) should be present if
			/*  
			 * For the Data Element (6000,3000)----1C type
			 * The Condition is not understood :
			 * Overlay pixel data. The order of pixels sent for each overlay
			 * is left to right, top to bottom, i.e., the 
			 * upper left pixel is sent first followed by 
			 * the remainder of the first row , followed
			 * by the first pixel of the 2nd row, then the
			 * remainder of the 2nd row and so on.
			 * Overlay data shall be contained in this
			 * Attribute or imbedded with the image pixel data in Group 7FE0.
			 * Required if overlay data are in this Group.
			 * See C.9.2.1.1 for further explanation.
			 */
		}catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

			throw new InvalidModuleException("Overlay Plane",mme);
		}
		catch(ConditionFailedException cfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(cfe.getMessage());

			throw new InvalidModuleException("Overlay Plane",cfe);
		}	

		return true;
	}

	/**
	 * The method is used to set Number of Rows in Overlay.
	 * The function accepts a String Value as strOverlayRows  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module HashMap
	 * 
	 * @param shOverlayRows : Number of Rows in Overlay.
	 */
	public void setOverlayRows(short shOverlayRows)
	{
		/* Accept Number of Rows in Overlay in String format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set.
		 */
		addDataElement(0x6000,0x0010, DicomConstants.DCM_DT_US, shOverlayRows);
	}

	/**
	 * The method is used to set Number of Columns in Overlay.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module Data Set
	 * 
	 * @param shOverlayColumns : Number of Columns in Overlay.
	 */
	public void setOverlayColumns(short shOverlayColumns)
	{
		/*Accept Number of Columns in Overlay in String format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x0011, DicomConstants.DCM_DT_US, shOverlayColumns);
	}

	/**
	 * The method is used to set Indicates whether this overlay represents
	 * a region of interest or other graphics. Enumerated Values:G = Graphics R = ROI.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param enumOverlayType : indicates a region of interest or other graphics
	 */
	public void setOverlayType(EnumOverlayType enumOverlayType)
	{
		/*Accept a region of interest or other graphics in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set.
		 */
		addDataElement(0x6000,0x0040, DicomConstants.DCM_DT_CS, enumOverlayType.getValue());
	}

	/**
	 * The method is used to set Location of first overlay point with respect to pixels in the image,
	 * a region of interest or other graphics. Enumerated Values:G = Graphics R = ROI.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param arrShOverlayOrigin :Location of first overlay point with respect to pixels in the image.
	 */
	public void setOverlayOrigin(short[] arrShOverlayOrigin)
	{
		/*
		 * Accept  Location of first overlay point with respect to pixels in the image, 
		 * in String Array format of type SS.
		 * Read the Transfer Syntax and check to create ImplicitDE or ExplicitDE .
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set.
		 */
			addDataElement(0x6000, 0x0050, DicomConstants.DCM_DT_SS, arrShOverlayOrigin);
	}

	/**
	 * The method is used to set Number of Bits Allocated in the Overlay.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module Data Set
	 * 
	 * @param shOverlayBitsAllocated :Number of Bits Allocated in the Overlay.
	 */
	public void setOverlayBitsAllocated(short shOverlayBitsAllocated)
	{
		/*Accept Number of Bits Allocated in the Overlay. in String format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x0100, DicomConstants.DCM_DT_US, shOverlayBitsAllocated);
	}

	/**
	 * The method is used to set Bit in which Overlay is stored.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param shOverlayBitPosition :Bit in which Overlay is stored.
	 */
	public void setOverlayBitPosition(short shOverlayBitPosition)
	{
		/*Accept Bit in which Overlay is stored in String format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set.
		 */
		addDataElement(0x6000,0x0102, DicomConstants.DCM_DT_US, shOverlayBitPosition);
	}

	/**
	 * The method is used to set the order of pixels sent for each overlay is left to right, top to bottom,
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param objCollectionOfOverlayData : ISingle Collection of bytes.
	 */

	//The element has OB or OW as data type as per Data Dictionary.
	//Implementing OB data type.
	public void setOverlayData(ISingleCollection<byte[]> objCollectionOfOverlayData)
	{
		/* Accept Overlay pixel data.in IDicomValue  type OB.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000, 0x3000, DicomConstants.DCM_DT_OB, objCollectionOfOverlayData);
	}

	/**
	 * The method is used to User-defined comments about the overlay.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strOverlayDescription :User-defined comments about the overlay.
	 */
	public void setOverlayDescription(String strOverlayDescription)
	{
		/*Accept User-defined comments about the overlay in String format of type LO.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x0022, DicomConstants.DCM_DT_LO, strOverlayDescription);
	}

	/**
	 * The method is used to set term which identifies the intended purpose of the Overlay Type.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strOverlaySubtype :term which identifies the intended purpose of the Overlay Type.
	 */
	public void setOverlaySubtype(String strOverlaySubtype)
	{
		/*Accept term which identifies the intended purpose of the Overlay Type in String format of type LO.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x0045, DicomConstants.DCM_DT_LO, strOverlaySubtype);
	}

	/**
	 * The method is used to set a user defined text string which may be used to label or name this overlay.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strOverlayLabel : a user defined text string which may be used to label or name this overlay.
	 */
	public void setOverlayLabel(String strOverlayLabel)
	{
		/*Accept a user defined text string which may be used to label or name this overlay
		 * in String format of type LO.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x1500, DicomConstants.DCM_DT_LO, strOverlayLabel);
	}

	/**
	 * The method is used to set Number of pixels in ROI area.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strROIArea : Number of pixels in ROI area.
	 */
	public void setROIArea(String strROIArea)
	{
		/*Accept Number of pixels in ROI area in String format of type IS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x1301, DicomConstants.DCM_DT_IS, strROIArea);
	}

	/**
	 * The method is used to set ROI Mean.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module Data Set
	 * 
	 * @param strROIMean : ROI Mean.
	 */
	public void setROIMean(String strROIMean)
	{
		/*Accept ROI Mean in String format of type DS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x1302, DicomConstants.DCM_DT_DS, strROIMean);
	}

	/**
	 * The method is used to set ROI standard deviation.
	 * The function accepts a String Value as User generated Study identifie the  and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module HashMap
	 * 
	 * @param strROIStandardDeviation : ROI standard deviation.
	 */
	public void setROIStandardDeviation(String strROIStandardDeviation)
	{
		/*Accept ROI standard deviation in String format of type DS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x6000,0x1303, DicomConstants.DCM_DT_DS, strROIStandardDeviation);
	}

	/**
	 * Return the short value of the attribute  Overlay Rows.
	 * 
	 * @return short - returns the Rows of Overlay
	 */
	public short getOverlayRows()
	{
		Object objectValue = getValue(0x6000,0x0010);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Return the short value of the attribute  Overlay Columns.
	 * 
	 * @return short - returns the Columns of Overlay
	 */
	public short getOverlayColumns()
	{
		Object objectValue = getValue(0x6000,0x0011);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Return the String value of the attribute Overlay Type.
	 * 
	 * @return String - returns the Type of Overlay
	 */
	public String getOverlayType()
	{
		Object objectValue = getValue(0x6000,0x0040);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the attribute Overlay Origin.
	 * 
	 * @return String[] - returns the array of Overlay Origin
	 */
	public short[] getOverlayOrigin()
	{
		Object objectValue = getValue(0x6000, 0x0050);
		if(objectValue!=null)
			return (short[])objectValue;
		return null;
	}

	/**
	 * Return the short value of the attribute Overlay Bits Allocated.
	 * 
	 * @return short - returns the Bits Allocated for Overlay
	 */
	public short getOverlayBitsAllocated()
	{
		Object objectValue = getValue(0x6000,0x0100);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Return the short value of the attribute Overlay Bit Position.
	 * 
	 * @return short - returns the Position of Overlay Bit
	 */
	public short getOverlayBitPosition()
	{
		Object objectValue = getValue(0x6000,0x0102);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Return the String value of the attribute Overlay Data.
	 * 
	 * @return Collection of byte[] - returns the collection of Overlay Data
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getOverlayData()
	{
		Object objValue = objIDataSet.getValue(0x6000, 0x3000);
		if(objValue != null)
			return ((ISingleCollection<byte[]>)objValue);
		return null;
	}

	/**
	 * Return the String value of the attribute Overlay Description.
	 * 
	 * @return String - return the Description of Overlay
	 */
	public String getOverlayDescription()
	{
		Object objectValue = getValue(0x6000,0x0022);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the attribute OverlaySubtype.
	 * 
	 * @return String - return the Overlay Subtype
	 */
	public String getOverlaySubtype()
	{
		Object objectValue = getValue(0x6000,0x0045);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the attribute OverlayLabel.
	 * 
	 * @return String - returns the Overlay Label
	 */
	public String getOverlayLabel()
	{
		Object objectValue = getValue(0x6000,0x1500);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the attribute ROI Area.
	 * 
	 * @return String - returns the ROI Area
	 */
	public String getROIArea()
	{
		Object objectValue = getValue(0x6000,0x1301);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the  attribute ROI Mean.
	 * 
	 * @return String - returns the ROI Mean
	 */
	public String getROIMean()
	{
		Object objectValue = getValue(0x6000,0x1302);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Return the String value of the ROI attribute  Standard Deviation.
	 * 
	 * @return String - returns the ROI Standard Deviation
	 */
	public String getROIStandardDeviation()
	{
		Object objectValue = getValue(0x6000,0x1303);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/* 
	 * I have modified the collection type from vector to custom class
	 * This method is used by the Module Iterator to iterate through the DataSet and return only
	 * those elements that belong to the respective Module class whose getVectorOfKeys is called.
	 */
	/**
	 * This method returns the custom collection containing the list of DataElements belonging to the CT
	 * Image Module specified by DICOM Standard.
	 * 
	 * @return collection - custom collection containing the list of DataElements belonging to the CT Image Module
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}


}
