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



import java.io.IOException;

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPhotometricInterpretation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPixelDataVRType;
import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidMacroException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ValidationException;
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;


/**
 * This macro specifies the common attributes that describe the pixel data of the image.
 */
public class ImagePixelMacro extends Macro  
{

	private static final long serialVersionUID = 1L;

	/**
	 * This constructor constructs a Macro with specified DataSet.
	 * @param objDataSet Collection of DataElements 
	 */
	public ImagePixelMacro(IDataSet objDataSet)
	{
		super(objDataSet);
	}

	/**
	 * This constructor constructs a Macro with specified DataSet and DictionaryReader
	 * @param objDataSet specifies the DataSet
	 * @param objDictionaryReader specifies the DICOM Dictionary reader to be used 
	 */
	public ImagePixelMacro(IDataSet objDataSet,IDictionaryReader objDictionaryReader)
	{
		super(objDataSet,objDictionaryReader);
	}

	/**
	 * This constructor constructs a Macro with the specified Item
	 * @param objItem specifies instance of Item class
	 */
	public ImagePixelMacro(IItem objItem)
	{
		super(objItem);
	}

	/**
	 * This constructor constructs a Macro with the specified Item and DictionaryReader
	 * @param objItem specifies instance of Item class
	 * @param objDictionaryReader specifies the DICOM Dictionary reader to be used 
	 */
	public ImagePixelMacro(IItem objItem,IDictionaryReader objDictionaryReader)
	{
		super(objItem, objDictionaryReader);
	}

	/*
	 * This method sets the Samples per Pixel in the Image Pixel Macro
	 */
	/**
	 * Sets Number of samples (planes) in this image.
	 * @param shSamplesPerPixel short value of Samples per Pixel.
	 */
	public void setSamplesPerPixel(short shSamplesPerPixel)
	{
		/*Accept the Samples per Pixel 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0002, shSamplesPerPixel,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0002,DicomConstants.DCM_DT_US, shSamplesPerPixel);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Number of samples (planes) in this image.
	 * @return shSamplesperPixel - short value of Samples per Pixel.
	 */
	public short getSamplesPerPixel()
	{
		Object objValue = getValue(0x0028, 0x0002);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets value that specifies the intended interpretation of the pixel data.
	 * @param strPhotometricInterpretation String valeu of Photometric Interpretation.
	 */
	public void setPhotometricInterpretation(String strPhotometricInterpretation)
	{
		/* Accept the Photometric Interpretation 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0004, strPhotometricInterpretation,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0004,DicomConstants.DCM_DT_CS, strPhotometricInterpretation);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves value that specifies the intended interpretation of the pixel data.
	 * @return strPhotometricInterpretation - String valeu of Photometric Interpretation.
	 */
	public String getPhotometricInterpretation()
	{
		Object objValue = getValue(0x0028, 0x0004);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets Number of rows in the image.
	 * @param shRows short value of rows.
	 */
	public void setRows(short shRows)
	{
		/* Accept the Rows in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0010, shRows,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0010,DicomConstants.DCM_DT_US, shRows);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves number of rows in the image.
	 * @return short - short value of rows.
	 */
	public short getRows()
	{
		Object objValue = getValue(0x0028, 0x0010);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Number of columns in the image.
	 * @param shColumns short value of Columns.
	 */
	public void setColumns(short shColumns)
	{
		/* Accept the Columns in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0011, shColumns,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0011,DicomConstants.DCM_DT_US, shColumns);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Number of columns in the image.
	 * @return short - short value of Columns.
	 */
	public short getColumns()
	{
		Object objValue = getValue(0x0028, 0x0011);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 *	Sets Number of bits allocated for each pixel sample. Each sample shall have the same
	 *	number of bits allocated. 
	 *	@param shBitsAllocated short specifies the number of bits allocated
	 */
	public void setBitsAllocated(short shBitsAllocated)
	{
		/* Accept the Bits Allocated in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0100, shBitsAllocated,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0100,DicomConstants.DCM_DT_US, shBitsAllocated);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Number of bits allocated for each pixel sample. Each sample shall have the same
	 * number of bits allocated. 
	 * @return short - specifies the number of bits allocated
	 */
	public short getBitsAllocated()
	{
		Object objValue = getValue(0x0028, 0x0100);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Number of bits stored for each pixel sample. Each sample shall have the same
	 * number of bits stored.
	 * @param shBitsStored specifies the number of bits stored
	 */
	public void setBitsStored(short shBitsStored)
	{
		/*Accept the Bits Stored in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0101, shBitsStored,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0101,DicomConstants.DCM_DT_US, shBitsStored);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Number of bits stored for each pixel sample. Each sample shall have the same
	 * number of bits stored.
	 * @return short - specifies the number of bits stored
	 */
	public short getBitsStored()
	{
		Object objValue = getValue(0x0028, 0x0101);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Most significant bit for pixel sample data. Each sample shall have the same high bit.
	 * @param shHighBit specifies the high bit
	 */
	public void setHighBit(short shHighBit)
	{
		/*Accept the Bits Stored in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0028, 0x0102, shHighBit,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0102,DicomConstants.DCM_DT_US, shHighBit);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves most significant bit for pixel sample data. Each sample shall have the same high bit.
	 * @return short specifies the high bit
	 */
	public short getHighBit()
	{
		Object objValue = getValue(0x0028, 0x0102);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Data representation of the pixel samples. Each sample shall have the same pixel
	 * representation. Enumerated Values: 0000H = unsigned integer. 0001H = 2's complement
	 * @param shPixelRepresentation specifies the pixel representation
	 */
	public void setPixelRepresentation(short shPixelRepresentation)
	{
		/*Accept the Pixel Representation in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0103, shPixelRepresentation,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0103,DicomConstants.DCM_DT_US, shPixelRepresentation);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves data representation of the pixel samples. Each sample shall have the same pixel
	 * representation. Enumerated Values: 0000H = unsigned integer. 0001H = 2's complement
	 * @return short specifies the pixel representation
	 */
	public short getPixelRepresentation()
	{
		Object objValue = getValue(0x0028, 0x0103);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets a data stream of the pixel samples that comprise the Image.
	 * @param objCollectionOfPixelData the obj collection of pixel data
	 * @param enumPixelDataVRType VR type pf the pixel data . It can be OW/OB.
	 * @param isUndefined true then the Data Element created is of undefined length.
	 * false then the Data Element created is of defined length.
	 */ 
	public void setPixelData(ISingleCollection<byte[]> objCollectionOfPixelData, EnumPixelDataVRType enumPixelDataVRType, boolean isUndefined)
	{
		/*Accept Pixel Data in this image in short format of type OB/OW.
		 * 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
		 */
		int	iVRTransferSyntax = objITransferSyntax.getVRTransferSyntax();
		IDataElement objIDataElement=null;
		if(enumPixelDataVRType.getValue() == DicomConstants.DCM_DT_OB)
		{
			OB objOb = (OB)DicomV3Factory.createInstance().createDataType(DicomConstants.DCM_DT_OB);
			if(isUndefined == true)
				objOb.changeToUndefined();
			objOb.setValue(objCollectionOfPixelData);
			if(iVRTransferSyntax==DicomConstants.DCM_VR_IMPLICIT)
				objIDataElement = new ImplicitDE(0x7FE0, 0x0010,objOb,objITransferSyntax,objIDictionaryReader);
			else
				objIDataElement = new ExplicitDE(0x7FE0, 0x0010, DicomConstants.DCM_DT_OB,objOb,objITransferSyntax,objIDictionaryReader);
		}
		else
		{
			OW objOW = (OW)DicomV3Factory.createInstance().createDataType(DicomConstants.DCM_DT_OW);
			if(isUndefined == true)
				objOW.changeToUndefined();
			objOW.setValue(objCollectionOfPixelData);
			if(iVRTransferSyntax==DicomConstants.DCM_VR_IMPLICIT)
				objIDataElement = new ImplicitDE(0x7FE0, 0x0010,objOW,objITransferSyntax,objIDictionaryReader);
			else
				objIDataElement = new ExplicitDE(0x7FE0, 0x0010, DicomConstants.DCM_DT_OW,objOW,objITransferSyntax,objIDictionaryReader);
		}
		if(objIDataElement != null)
			objIDataSet.addDataElement(objIDataElement);
	}

	/**
	 * Sets a data stream of the pixel samples that comprise the Image.
	 * @param objIDicomStream the Dicom Stream Containing pixel data
	 * @param iFrameSizeArr int array containing size of each frame.
	 * @param enumPixelDataVRType VR type pf the pixel data . It can be OW/OB.
	 * @param isUndefined true then the Data Element created is of undefined length.
	 * false then the Data Element created is of defined length.
	 */ 
	public void setPixelData(IDicomStream objIDicomStream, int[] iFrameSizeArr, EnumPixelDataVRType enumPixelDataVRType, boolean isUndefined) throws IOException
	{
		/*Accept Pixel Data in this image in short format of type OB/OW.
		 * 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
		 */
		IDataElement objIDataElement=null;
		if(enumPixelDataVRType.getValue() == DicomConstants.DCM_DT_OB)
		{
			OBImageObject objObImageObject = new OBImageObject();
			if(isUndefined == true)
				objObImageObject.changeToUndefined();
			objObImageObject.addFrames(objIDicomStream, iFrameSizeArr);
			objIDataElement = new ImageElement(objIDataSet.getTransferSyntax(), objIDictionaryReader,objObImageObject);
		}
		else
		{
			OWImageObject objOWImageObject = new OWImageObject();
			if(isUndefined == true)
				objOWImageObject.changeToUndefined();
			objOWImageObject.addFrames(objIDicomStream, iFrameSizeArr);
			objIDataElement = new ImageElement(objIDataSet.getTransferSyntax(), objIDictionaryReader,objOWImageObject);
		}
		if(objIDataElement != null)
			objIDataSet.addDataElement(objIDataElement);
	}

	/**
	 * Retrieves data stream of the pixel samples that comprise the Image.
	 * @return ISingleCollection<byte[]> specifies the collection of pixel data
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getPixelData()
	{
		Object objValue = getValue(0x7FE0, 0x0010);
		if(objValue != null)
			return (ISingleCollection<byte[]>)objValue;
		return null;
	}

	/**
	 * Sets value that indicates whether the pixel data are sent color-by-plane or color-by-pixel.
	 * @param shPlanarConfiguration short value specifies planar configuration of the image.
	 */
	public void setPlanarConfiguration(short shPlanarConfiguration)
	{
		/*Accept the Planar Configuration in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0006, shPlanarConfiguration,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0006,DicomConstants.DCM_DT_US, shPlanarConfiguration);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves value that indicates whether the pixel data are sent color-by-plane or color-by-pixel.
	 * @return short specifies planar configuration of the image.
	 */
	public short getPlanarConfiguration()
	{
		Object objValue = getValue(0x0028, 0x0006);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Ratio of the vertical size and horizontal size of the pixels in the image specified by
	 * a pair of integer values where the first value is the vertical pixel size.
	 * @param sPixelAspectRatio specifies the pixel aspect ratio. 
	 */
	public void setPixelAspectRatio(String strPixelAspectRatio)
	{
		/*Accept Pixel Aspect Ratio in this image in short 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
		 */
		IDataElement objIDataElement=null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
		{	
			objIDataElement = new ImplicitDE(0x0028,0x0034,strPixelAspectRatio,objIDictionaryReader);
		}
		else
		{
			objIDataElement = new ExplicitDE(0x0028,0x0034, DicomConstants.DCM_DT_IS,strPixelAspectRatio);
		}
		if(objIDataElement != null)
			addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the pixel aspect ratio
	 * @return short - returns the pixel aspect ratio
	 */
	public String[] getPixelAspectRatio()
	{
		if(getDataElement(0x0028,0x0034)!=null)
			{
				if(getDataElement(0x0028,0x0034).getValue()!=null)
				{
					Object objValue = getDataElement(0x0028,0x0034).getValue();
					if(objValue!=null)
					{
						if(objValue instanceof String)
						{
							String strTemp = (String)objValue;
							String[] strArr = new String[1];
							strArr[0] = strTemp;
							return strArr;
						}
						else
							return (String[])objValue;
					}
				}
			}
			return null;	
	}

	/**
	 * Sets the minimum actual pixel value encountered in this image.
	 * @param shSmallestImagePixelValue short specifies the value of smallest image pixel
	 */
	public void setSmallestImagePixelValue(short shSmallestImagePixelValue)
	{
		/*Accept the Smallest Image Pixel Value in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0106, shSmallestImagePixelValue,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0106,DicomConstants.DCM_DT_US, shSmallestImagePixelValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the minimum actual pixel value encountered in this image.
	 * @return short specifies the value of smallest image pixel
	 */
	public short getSmallestImagePixelValue()
	{
		Object objValue = getValue(0x0028, 0x0106);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets the maximum actual pixel value encountered in this image.
	 * @param shLargestImagePixelValue specifies the value of largest image pixel.
	 */
	public void setLargestImagePixelValue(short shLargestImagePixelValue)
	{
		/*Accept the Largest Image Pixel Value in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x0107, shLargestImagePixelValue,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x0107,DicomConstants.DCM_DT_US, shLargestImagePixelValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the maximum actual pixel value encountered in this image.
	 * @return short specifies the value of largest image pixel.
	 */
	public short getLargestImagePixelValue()
	{
		Object objValue = getValue(0x0028, 0x0107);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * sets value that specifies the format of the Red Palette Color Lookup Table Data (0028,1201)
	 * @param shRedPaletteColorLookupTableDescriptor specifies the pallette color lookup table descriptor
	 */
	public void setRedPaletteColorLookupTableDescriptor(short[] shRedPaletteColorLookupTableDescriptor)
	{
		/*Accept the RedPaletteColorLookupTableDescriptor in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1101, shRedPaletteColorLookupTableDescriptor,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1101,DicomConstants.DCM_DT_US, shRedPaletteColorLookupTableDescriptor);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves value that specifies the format of the Red Palette Color Lookup Table Data (0028,1201)
	 * @return short specifies the pallette color lookup table descriptor
	 */
	public short[] getRedPaletteColorLookupTableDescriptor()
	{
		Object objValue = getValue(0x0028, 0x1101);
		if(objValue != null)
			return (short[])objValue;
		return null;
	}

	/**
	 *  Sets value that specifies the format of the Green Palette Color Lookup Table Data (0028,1202)
	 *  Required if Photometric Interpretation (0028,0004) has a value of PALETTE
	 *  COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or
	 *  MIXED.
	 * @param shGreenPaletteColorLookupTableDescriptor specifies the Green Pallette Color Lookup Table Descriptor
	 */
	public void setGreenPaletteColorLookupTableDescriptor(short[] shGreenPaletteColorLookupTableDescriptor)
	{
		/*Accept the GreenPaletteColorLookupTableDescriptor in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1102, shGreenPaletteColorLookupTableDescriptor,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1102,DicomConstants.DCM_DT_US, shGreenPaletteColorLookupTableDescriptor);

		addDataElement(objIDataElement);
	}

	/**
	 *  Retrieves value that specifies the format of the Green Palette Color Lookup Table Data (0028,1202)
	 *  Required if Photometric Interpretation (0028,0004) has a value of PALETTE
	 *  COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or
	 *  MIXED.
	 * @return short specifies the Green Pallette Color Lookup Table Descriptor
	 */
	public short[] getGreenPaletteColorLookupTableDescriptor()
	{
		Object objValue = getValue(0x0028, 0x1102);
		if(objValue != null)
			return (short[])objValue;
		return null;
	}

	/*
	 * This method sets the BluePaletteColorLookupTableDescriptor in the Image Pixel Macro
	 */
	/**
	 * Sets the Blue Pallette Color Lookup Table Descriptor.
	 * @param shBluePaletteColorLookupTableDescriptor specifies blue pallette color lookup table descriptor
	 */
	public void setBluePaletteColorLookupTableDescriptor(short[] shBluePaletteColorLookupTableDescriptor)
	{
		/*Accept the BluePaletteColorLookupTableDescriptor in short 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1103, shBluePaletteColorLookupTableDescriptor,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1103,DicomConstants.DCM_DT_US, shBluePaletteColorLookupTableDescriptor);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the Blue Pallette Color Lookup Table Descriptor.
	 * @return short specifies blue pallette color lookup table descriptor
	 */
	public short[] getBluePaletteColorLookupTableDescriptor()
	{
		Object objValue = getValue(0x0028, 0x1103);
		if(objValue != null)
			return (short[])objValue;
		return null;
	}

	/**
	 * This method sets the Red Palette Color Lookup Table Data in the Image Pixel Macro
	 * @param objSingleCollection SingleCollection of bytefor Red Palette Color Lookup Table Data.
	 */
	public void setRedPaletteColorLookupTableData(ISingleCollection<byte[]> objSingleCollection)
	{
		/*Accept the Red Palette Color Lookup Table Data in short format of type OW.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1201, objSingleCollection,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1201,DicomConstants.DCM_DT_OW, objSingleCollection);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the Red Palette Color Lookup Table Data in the Image Pixel Macro
	 * @return SISingleCollection<byte[]> of byte for Red Palette Color Lookup Table Data.
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getRedPaletteColorLookupTableData()
	{
		Object objValue = getValue(0x0028, 0x1201);
		if(objValue != null)
			return (ISingleCollection<byte[]>)objValue;
		return null;
	}

	/**
	 * Sets value of Green Palette Color Lookup Table Data
	 * @param objSingleCollection ISingleCollection of bytes
	 */
	public void setGreenPaletteColorLookupTableData(ISingleCollection<byte[]> objSingleCollection)
	{
		/*Accept the Green Palette Color Lookup Table Data in short format of type OW.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1202, objSingleCollection,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1202,DicomConstants.DCM_DT_OW, objSingleCollection);

		addDataElement(objIDataElement);
	}

	/**
	 * This method returns the value of the field Green Palette Color Lookup Table Data
	 * @return objSingleCollection ISingleCollection of bytes
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getGreenPaletteColorLookupTableData()
	{
		Object objValue = getValue(0x0028, 0x1202);
		if(objValue != null)
			return (ISingleCollection<byte[]>)objValue;
		return null;
	}

	/**
	 * This method sets the Blue Palette Color Lookup Table Data in the Image Pixel Macro
	 * @param objSingleCollection of bytes
	 */
	public void setBluePaletteColorLookupTableData(ISingleCollection<byte[]> objSingleCollection)
	{
		/*Accept the Blue Palette Color Lookup Table Data in short format of type OW.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0028, 0x1203, objSingleCollection,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1203,DicomConstants.DCM_DT_OW, objSingleCollection);

		addDataElement(objIDataElement);
	}

	/**
	 * This method returns the value of the field Blue Palette Color Lookup Table Data
	 * @return ISingleCollection of byte
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getBluePaletteColorLookupTableData()
	{
		Object objValue = getValue(0x0028, 0x1203);
		if(objValue != null)
			return (ISingleCollection<byte[]>)objValue;
		return null;
	}

	/*
	 * Added exception handling code
	 */
	/**
	 * Validates all the attributes in CodeSequenceMacro
	 * @return int - Success -true, Failure -false.
	 * @throws ValidationException throws ValidationException If Mandatory or Conditional element fails.
	 */
	public boolean validate() throws ValidationException
	{
		if(iMacroLevel == DicomConstants.DCM_MODULE_LEVEL_MACRO)
			return validate(objIDataSet);
		else if(iMacroLevel == DicomConstants.DCM_ITEM_LEVEL_MACRO)
			return validate(objIItem);
		return false;
	}

	/*
	 * Added exception handling code
	 */
	/**
	 * Validates all the attributes in CodeSequenceMacro that are present in the DataSet
	 * @param objIDataSet collection of DataElements
	 * @return int - Success -true, Failure - false
	 * @throws ValidationException throws ValidationException If Mandatory or Conditional element fails.
	 * @throws InvalidMacroException Signals Macro Validation is failed.
	 */

	public static boolean validate(IDataSet objIDataSet) throws InvalidMacroException
	{
		try
		{
			IDataElement objIDataElement = null;
			IDicomValue objIDicomValue = null;
			String[] arrPixelAspectRatio = null;
			/*
			 * Validation Rules for Mandatory Elements
			 */
			if(!objIDataSet.isPresent(0x0028,0x0002))
				throw new MandatoryMissingException("0028,0002");
			else if(!objIDataSet.isPresent(0x0028,0x0004))
				throw new MandatoryMissingException("0028,0004");
			else if	(!objIDataSet.isPresent(0x0028,0x0010))
				throw new MandatoryMissingException("0028,0010");
			else if(!objIDataSet.isPresent(0x0028,0x0011))
				throw new MandatoryMissingException("0028,0011");
			else if(!objIDataSet.isPresent(0x0028,0x0100))
				throw new MandatoryMissingException("0028,0100");
			else if(!objIDataSet.isPresent(0x0028,0x0101))
				throw new MandatoryMissingException("0028,0101");
			else if(!objIDataSet.isPresent(0x0028,0x0102))
				throw new MandatoryMissingException("0028,0102");
			else if(!objIDataSet.isPresent(0x0028,0x0103))
				throw new MandatoryMissingException("0028,0103");
			else if(!objIDataSet.isPresent(0x7fe0,0x0010))
				throw new MandatoryMissingException("7fe0,0010");

			/*
			 * Validation Rules for Conditional Elements
			 */
			else if(objIDataSet.isPresent(0x0028,0x0006))
			{
				objIDataElement = objIDataSet.getDataForTag(0x0028,0x0002);
				objIDicomValue = objIDataElement.getDicomValue();
				int iNumberOfSamples = ((Short)objIDicomValue.getValue()).shortValue();

				if(iNumberOfSamples <= 1)
					throw new ConditionFailedException("value of conditional Element 0028,0002 required to be greater than 1 for Tag 0028,0006") ;
			}
			else if(objIDataSet.isPresent(0x0028,0x0034))
			{
				objIDataElement = objIDataSet.getDataForTag(0x0028,0x0034);
				objIDicomValue = objIDataElement.getDicomValue();
				arrPixelAspectRatio=(String[]) objIDicomValue.getValue();	
				if(arrPixelAspectRatio != null)	
				{
					int iVerticalSize=Integer.parseInt(arrPixelAspectRatio[0]);
					int iHorizontalSize=Integer.parseInt(arrPixelAspectRatio[1]);
					if((iVerticalSize/iHorizontalSize)==1)
						throw new ConditionFailedException("value of ratio of first value and second value of conditional Element 0028,0034 is required to be not equal to 1 for Tag 0028,0034");
				}
			}
			else 
			{
				objIDataElement = objIDataSet.getDataForTag(0x0028,0x0004);
				objIDicomValue = objIDataElement.getDicomValue();

				if(objIDicomValue!=null)
				{
					String strPhotoMetricInterpretation=(String)objIDicomValue.getValue();
					if(objIDataSet.isPresent(0x0028,0x1101)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1101");
					if(objIDataSet.isPresent(0x0028,0x1102)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1102");
					if(objIDataSet.isPresent(0x0028,0x1103)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1103");
					if(objIDataSet.isPresent(0x0028,0x1201)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1201");
					if(objIDataSet.isPresent(0x0028,0x1202)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1202");
					if(objIDataSet.isPresent(0x0028,0x1203) && !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1203");
				}
			}
		}
		catch( ConditionFailedException ce)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			throw new InvalidMacroException(ImagePixelMacro.class.getSimpleName(),ce); 
		}
		catch( MandatoryMissingException me)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(me.getMessage());
			}
			throw new InvalidMacroException(ImagePixelMacro.class.getSimpleName(),me);
		}
		return true;
	}

	/**
	 * Validates all the attributes in CodeSequenceMacro that are present in the DataSet
	 * @param objIItem collection of DataElements in a sequence
	 * @return int - Success -true, Failure - false
	 * @throws ValidationException throws ValidationException If Mandatory or Conditional element fails.
	 * @throws InvalidMacroException Signals Macro Validation is failed.
	 */
	public static boolean validate(IItem objIItem) throws InvalidMacroException
	{
		try
		{
			IDataElement objIDataElement = null;
			IDicomValue objIDicomValue = null;
			String[] arrPixelAspectRatio = null;
			/*
			 * Validation Rules for Mandatory Elements
			 */
			if(!objIItem.contains(0x0028,0x0002))
				throw new MandatoryMissingException("0028,0002");
			else if(!objIItem.contains(0x0028,0x0004))
				throw new MandatoryMissingException("0028,0004");
			else if	(!objIItem.contains(0x0028,0x0010))
				throw new MandatoryMissingException("0028,0010");
			else if(!objIItem.contains(0x0028,0x0011))
				throw new MandatoryMissingException("0028,0011");
			else if(!objIItem.contains(0x0028,0x0100))
				throw new MandatoryMissingException("0028,0100");
			else if(!objIItem.contains(0x0028,0x0101))
				throw new MandatoryMissingException("0028,0101");
			else if(!objIItem.contains(0x0028,0x0102))
				throw new MandatoryMissingException("0028,0102");
			else if(!objIItem.contains(0x0028,0x0103))
				throw new MandatoryMissingException("0028,0103");
			else if(!objIItem.contains(0x7fe0,0x0010))
				throw new MandatoryMissingException("7fe0,0010");

			/*
			 * Validation Rules for Conditional Elements
			 */
			else if(objIItem.contains(0x0028,0x0006))
			{
				objIDataElement = objIItem.getDataForTag(0x0028,0x0002);
				objIDicomValue = objIDataElement.getDicomValue();
				int iNumberOfSamples = ((Short)objIDicomValue.getValue()).shortValue();

				if(iNumberOfSamples <= 1)
					throw new ConditionFailedException("value of conditional Element 0028,0002 required to be greater than 1 for Tag 0028,0006") ;
			}
			else if(objIItem.contains(0x0028,0x0034))
			{
				objIDataElement = objIItem.getDataForTag(0x0028,0x0034);
				objIDicomValue = objIDataElement.getDicomValue();
				arrPixelAspectRatio=(String[])objIDicomValue.getValue();
				if(arrPixelAspectRatio != null)	
				{
					int iVerticalSize=Integer.parseInt(arrPixelAspectRatio[0]);
					int iHorizontalSize=Integer.parseInt(arrPixelAspectRatio[1]);
					if((iVerticalSize/iHorizontalSize)==1)
						throw new ConditionFailedException("value of ratio of first value and second value of conditional Element 0028,0034 is required to be not equal to 1 for Tag 0028,0034");
				}
			}
			else 
			{
				objIDataElement = objIItem.getDataForTag(0x0028,0x0004);
				objIDicomValue = objIDataElement.getDicomValue();

				if(objIDicomValue!=null)
				{
					String strPhotoMetricInterpretation=(String)objIDicomValue.getValue();
					if(objIItem.contains(0x0028,0x1101)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1101");
					if(objIItem.contains(0x0028,0x1102)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1102");
					if(objIItem.contains(0x0028,0x1103)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1103");
					if(objIItem.contains(0x0028,0x1201)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1201");
					if(objIItem.contains(0x0028,0x1202)&& !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1202");
					if(objIItem.contains(0x0028,0x1203) && !EnumPhotometricInterpretation.PALETTE_COLOR.getValue().equals((strPhotoMetricInterpretation)))
						throw new ConditionFailedException("value of conditional Element 0028,0004 is required to be equal to "+EnumPhotometricInterpretation.PALETTE_COLOR.getValue()+" for Tag 0028,1203");
				}
			}
		}
		catch( ConditionFailedException ce)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			throw new InvalidMacroException(ImagePixelMacro.class.getSimpleName(),ce); 
		}
		catch( MandatoryMissingException me)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(me.getMessage());
			}
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(me.getMessage());
			}
			throw new InvalidMacroException(ImagePixelMacro.class.getSimpleName(),me);
		}
		return true;
	}
}
