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


import java.util.Vector;

import cdac.medinfo.sdk.dcm30_04.baselibs.DicomFileHeader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;




// TODO: Auto-generated Javadoc
/**
 * This class retrieves image information from the DataSet and fills the DicomImageInfo.
 */
public class DicomDecoder 
{

	
	/**
	 * The obj i data element.
	 */
	IDataElement objIDataElement;
	
	/**
	 * The obj i data set.
	 */
	IDataSet objIDataSet;
	
	/**
	 * The obj dicom image info.
	 */
	DicomImageInfo objDicomImageInfo;
	
	/**
	 * The obj i dicom data.
	 */
	IDicomValue objIDicomValue;
	
	/**
	 * The str image type.
	 */
	String strImageType;
	
	/**
	 * The obj dicom file header.
	 */
	DicomFileHeader objDicomFileHeader;
	
	/**
	 * The Constant DCM_TS_NORMAL_RAWIMAGE.
	 */
	public static final int DCM_TS_NORMAL_RAWIMAGE = 2;
	
	/**
	 * The Constant DCM_TS_RLE_IMAGE.
	 */
	public static final int DCM_TS_RLE_IMAGE = 3;
	
	/**
	 * The Constant DCM_TS_JPEG_IMAGE.
	 */
	public static final int DCM_TS_JPEG_IMAGE = 4;
	
	/**
	 * The Constant DCM_TS_TRANSFERSYNTAX_NOTSUPPORTED.
	 */
	public static final int DCM_TS_TRANSFERSYNTAX_NOTSUPPORTED = 5;
	
	/**
	 * This constructor initializes DicomDecoder.
	 */
	public DicomDecoder()
	{
		objDicomImageInfo = new DicomImageInfo();
	}
	
	/**
	 * This function according to major and minor type , get the DicomValueelement object and fill the image
	 * information into DicomImageInfoObject, Image information like width, height etc, Image information
	 * in Dicom starts when major type is 28.
	 * @param objDicomFileHeader the obj dicom file header
	 * @throws ImageViewerException 	 * 
	 */
	
	public void setDicomFileHeader(DicomFileHeader objDicomFileHeader)
	{
		this.objDicomFileHeader = objDicomFileHeader;
	}
	
	/**
	 * Fill image info.
	 * 
	 * @return the dicom image info
	 */
	@SuppressWarnings("unchecked")
	public DicomImageInfo fillImageInfo()
	{
	
		    //This logic sets image type according to the TransferSyntax 
			//objIDataElement = objIDataSet.getDataForTag(0x02, 0x10);
			objIDataElement = objDicomFileHeader.getDataFromTag(0x2, 0x10);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.strTransferSyntax = (String)objIDicomValue.getValue();
				objIDataElement = null;
				
				if((objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2")) || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.")))
						objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_NORMAL_RAWIMAGE;

				else if(objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.1") || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.1.")))
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_NORMAL_RAWIMAGE;

				else if(objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.2") || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.2.")))
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_NORMAL_RAWIMAGE;

				else if(objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.5") || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.5.")))
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_RLE_IMAGE;
				
				else if(objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.4.50") || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.5.")))
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_JPEG_IMAGE;
				
				else if(objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.4.70") || (objDicomImageInfo.strTransferSyntax.equalsIgnoreCase("1.2.840.10008.1.2.5.")))
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_JPEG_IMAGE;
				
				else if(objDicomImageInfo.strTransferSyntax.length() == 0)
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_NORMAL_RAWIMAGE;
				
				else
				{
					objDicomImageInfo.iTransferSyntaxImageType = DCM_TS_TRANSFERSYNTAX_NOTSUPPORTED;
				}
			}
			
			//This tag retrieves height of image from the DataSet  
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x10);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iHeight = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag  retrieves width of the image from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x11);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iWidth = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves bits allocated in the image from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x100);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iBitsAllocated = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves bits stored in the image from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x101);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iBitsStored = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves high bit information from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x102);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iHighBit = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves pixel representation information from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x103);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iPixelRepresentation = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves number of frames information from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x8);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				String strNumberOfFrames = ((String)objIDicomValue.getValue());
				objDicomImageInfo.iNumberOfFrames = Integer.parseInt(strNumberOfFrames);
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves pixel window center information from the DataSet 
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x1050);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				String strPixelWindowCenter = ((String)objIDicomValue.getValue());
				if(strPixelWindowCenter!=null)
				{
					if(strPixelWindowCenter.indexOf('\\')==-1)
					{
						objDicomImageInfo.iPixelWindowCenter = Integer.parseInt(strPixelWindowCenter);
					}
					else
					{
						objDicomImageInfo.iPixelWindowCenter = 0;
					}
				}
				else
				{
					objDicomImageInfo.iPixelWindowCenter = 0;
				}
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves pixel window width from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x1051);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				String strPixelWindowWidth = ((String)objIDicomValue.getValue());
				if(strPixelWindowWidth!=null)
				{
					if(strPixelWindowWidth.indexOf('\\')==-1)
					{
						objDicomImageInfo.iPixelWindowWidth = Integer.parseInt(strPixelWindowWidth);
					}
					else
					{
						objDicomImageInfo.iPixelWindowWidth = 0;
					}
				}
				else
				{
					objDicomImageInfo.iPixelWindowWidth = 0;
				}
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag retrieves image type from the DataSet
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x4);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.strImageType = (String)objIDicomValue.getValue();
				objIDataElement = null;
				
				strImageType = objDicomImageInfo.strImageType;
				strImageType = strImageType.trim();
				if(strImageType.equalsIgnoreCase("MONOCHROME2"))
				{
					objDicomImageInfo.iBitsPerPixel = 8;
					// need some code to write.
				//	objDicomImageInfo.
				}
				else if(strImageType.equalsIgnoreCase("MONOCHROME1"))
				{
					objDicomImageInfo.iBitsPerPixel = 8;
				}
				else if(strImageType.equalsIgnoreCase("RGB"))
				{
					objDicomImageInfo.iBitsPerPixel = 24;
				}
				else if(strImageType.equalsIgnoreCase("YBR_FULL_422"))
				{
					objDicomImageInfo.iBitsPerPixel = 24;
				}
				else if(strImageType.equalsIgnoreCase("PALETTE COLOR"))
				{
					objDicomImageInfo.iBitsPerPixel = 8;
					int redLUTsize, redLUToffset, greenLUTsize, greenLUToffset, blueLUTsize, blueLUToffset;
					//int redBits, greenBits, blueBits;
					byte[] redLUT = new byte[256];
					byte[] greenLUT = new byte[256];
					byte[] blueLUT = new byte[256];
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1101);
					redLUTsize = 256;
					redLUToffset = 0;
					//redBits = 	16;
					
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1102);
					greenLUTsize = 256;
					greenLUToffset = 0;
					//greenBits = 	16; 
					
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1103);
					blueLUTsize = 256;
					blueLUToffset = 0;
					//blueBits = 	16;
					
					int lutSize = redLUTsize;
					if(lutSize > greenLUTsize) lutSize = greenLUTsize;
					if(lutSize > blueLUTsize) lutSize = blueLUTsize;
					byte[] data;
					
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1201);
					{
						objDicomImageInfo.arrPlaetteRed = new byte[256];
						objIDicomValue = objIDataElement.getDicomValue();
						Vector<byte[]> vctImageData = (Vector<byte[]>)objIDicomValue.getValue();
						
						data = vctImageData.get(0);
						for(int i = redLUToffset; i < lutSize; i++)
							redLUT[i] = (byte)(data[(i-redLUToffset)*2+1]);
						
						for(int i = lutSize; i < 255; i++) redLUT[i] = (byte)0;
						for(int i = 0; i < redLUToffset; i++) redLUT[i] = redLUT[0];
					}
					
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1202);
					{
						objDicomImageInfo.arrPlaetteGreen = new byte[256];
						objIDicomValue = objIDataElement.getDicomValue();
						Vector<byte[]> vctImageData = (Vector<byte[]>)objIDicomValue.getValue();
						
						data = vctImageData.get(0);
						for(int i = greenLUToffset; i < lutSize; i++)
						  	greenLUT[i] = (byte)(data[(i-greenLUToffset)*2+1]);
						
						for(int i = lutSize; i < 255; i++) greenLUT[i] = (byte)0;
						for(int i = 0; i < greenLUToffset; i++) greenLUT[i] = greenLUT[0];
						
						objIDataElement = null;
						vctImageData = null;
						//arrPaletteData = null;
					}
					
					objIDataElement = objIDataSet.getDataForTag(0x28, 0x1203);
					if(null != objIDataElement)
					{
						objDicomImageInfo.arrPlaetteBlue = new byte[256];
						objIDicomValue = objIDataElement.getDicomValue();
						Vector<byte[]> vctImageData = (Vector<byte[]>)objIDicomValue.getValue();
						
						data = vctImageData.get(0);
						for(int i = blueLUToffset; i < lutSize; i++)
							blueLUT[i] = (byte)(data[(i-blueLUToffset)*2+1]);
						
						for(int i = lutSize; i < 255; i++) blueLUT[i] = (byte)0;
						for(int i = 0; i < blueLUToffset; i++) blueLUT[i] = blueLUT[0];
						
						objIDataElement = null;
						vctImageData = null;
					}
					byte[] alphaLUT = new byte[256];
					for (int i = 0; i < 256;i++) 
					{
						alphaLUT[i] = (byte) 127;
					}

					objDicomImageInfo.arrPlaetteRed = redLUT;
					objDicomImageInfo.arrPlaetteGreen = greenLUT;
					objDicomImageInfo.arrPlaetteBlue = blueLUT;
				}
			}
			else
			{
				objDicomImageInfo.strImageType = "MONOCHROME2";
			}
	{
		// System.out.println(objDicomImageInfo.strImageType);
	}
			//This tag retrieves planar configuration information from the image
			objIDataElement = objIDataSet.getDataForTag(0x28, 0x6);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue();
				objDicomImageInfo.iPlanerConfiguration = ((Short)objIDicomValue.getValue()).shortValue();
				objIDataElement = null;
				objIDicomValue = null;
			}
			
			//This tag Retrieves actual byte information of image from DataSet
			objIDataElement = objIDataSet.getDataForTag(0x7FE0, 0x0010);
			if(null != objIDataElement)
			{
				objIDicomValue = objIDataElement.getDicomValue(); 
				int iNumberofFrames = objDicomImageInfo.iNumberOfFrames;

				int iLengthofEachImage;
				Vector vctDicomImageInfo = null;
				Vector vctDicomCompleteImage = new Vector();
				byte[] bytEqualFramesImage=null;
				//short[] shortEqualFramesImage;
				vctDicomImageInfo = new Vector();
				vctDicomImageInfo = (Vector)objIDicomValue.getValue();
				int iCount = 0;
				int iImageLength = 0;
				if(1 == vctDicomImageInfo.size() && iNumberofFrames >=0)
				{
					if(iNumberofFrames == 0)
					{
						iNumberofFrames = objDicomImageInfo.iNumberOfFrames = 1;
					}
				//	if( DicomConstants.DCM_DT_OB == objIDicomValue.getIVRType() )
				//	{
						bytEqualFramesImage = (byte[])vctDicomImageInfo.get(0);
						iLengthofEachImage = bytEqualFramesImage.length/iNumberofFrames;
						
						while(iNumberofFrames!=0)
						{
							byte[] bytEqualNoofFrames = new byte[iLengthofEachImage];
							for(int i=0; i<iLengthofEachImage; i++, iImageLength++)
							{
								bytEqualNoofFrames[i] = bytEqualFramesImage[iImageLength];
							}
							vctDicomCompleteImage.add(iCount, bytEqualNoofFrames);
							iCount++;
							iNumberofFrames--;
							bytEqualNoofFrames = null;
						}
				/*	}
					else
					{
						shortEqualFramesImage = (short[])vctDicomImageInfo.get(0);
						
						ByteArrayBuffer objByteArrayBuffer = new ByteArrayBuffer();
						
						iLengthofEachImage = shortEqualFramesImage.length/iNumberofFrames;
						
						while(iNumberofFrames!=0)
						{
							short[] shortEqualNoofFrames = new short[iLengthofEachImage];
							for(int i=0; i<iLengthofEachImage; i++, iImageLength++)
							{
								shortEqualNoofFrames[i] = shortEqualFramesImage[iImageLength];
							}
							vctDicomCompleteImage.add(shortEqualNoofFrames);
							iCount++;
							iNumberofFrames--;
							shortEqualNoofFrames = null;
						}
					}*/

					objDicomImageInfo.vctImage = vctDicomCompleteImage;
				}
				else
				{
					objDicomImageInfo.vctImage = vctDicomImageInfo;
				}
				objIDataElement = null;
			}
		return objDicomImageInfo;
	}

	/**
	 * Sets the dicom data set.
	 * 
	 * @param objIDataSet the obj i data set
	 * 
	 * @return the int
	 */
	public int setDicomValueSet(IDataSet objIDataSet)
	{
		this.objIDataSet = objIDataSet;
		return 1;
	}
}
