/*******************************************************************************
 *  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.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Locale;

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicomstreams.DicomBufferStream;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataElementException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataTypeException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidTransferSyntaxException;
import cdac.medinfo.sdk.dcm30_04.exceptions.OutOfMemoryException;
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.GlobalConstants;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;
/**
 * This class represents Implicit Data Element of Dicom which reads the datatype of its value 
 * from the DataDictionary provided to it.
 */
public class ImplicitDE extends DataElement  
{
	


	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	IDictionaryReader objIDictionaryReader = null;
	private final String DCM_DT_OB_OR_OW = "OB/OW";
	private final String DCM_DT_OW_OR_OB = "OW/OB";
	private final String DCM_DT_SS_OR_US = "SS/US";
	private final String DCM_DT_US_OR_SS = "US/SS";
	private final String DCM_DT_OB = "OB";
	private final String DCM_DT_OW = "OW";
	private final String DCM_DT_US = "US";

	/*
	 * When ImplicitDE is created only with DictionaryReader, then the
	 * TS is taken as default TS
	 * This constructor should throw exception if dictionaryreader
	 * is tried to be set as null
	 */
	/**
	 * This constructor is used to provide user defined dictionary reader to the Implicit DataElement
	 * @param objIDictReader DictionaryReader to read from the Dictionary 
	 */
	public ImplicitDE(IDictionaryReader objIDictReader)
	{
		objIDictionaryReader = objIDictReader;
		objITransferSyntax = new TransferSyntax();
	}

	/*
	 * For description, see javadoc comments of this constructor
	 */
	/**
	 * This constructor is used to provide user defined dictionary reader and TS to the Implicit DataElement
	 * @param objTransferSyntax TransferSyntax specified by DICOM Standard
	 * @param objIDictReader DictionaryReader to read from the Dictionary
	 * @throws InvalidTransferSyntaxException Signals Transfer Syntax fails to satisfy Validation Criteria. 
	 */
	public ImplicitDE(ITransferSyntax objTransferSyntax, IDictionaryReader objIDictReader) throws InvalidTransferSyntaxException
	{
		try
		{
			if((objTransferSyntax.getVRTransferSyntax())== DicomConstants.DCM_VR_EXPLICIT)
				throw new InvalidTransferSyntaxException("Invalid Transfer Sysntax");
			objITransferSyntax = objTransferSyntax;
			objIDictionaryReader = objIDictReader;
		}
		catch( InvalidTransferSyntaxException dex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			throw new InvalidDataElementException(Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber()), dex);
		}
	}

	/*
	 * see javadoc comment for modification description
	 */
	/**
	 * This constructor accepts dictionary reader reading from the dictionary populated using
	 * the DictioanryReader and sets the transfersyntax in the dataelement as a default transfersyntax
	 * @param iGroupNumber GroupNumber from the Tag identifying this DataElement
	 * @param iElementNumber ElementNumber from the Tah identifying this DataElement
	 * @param objValue value of the DataElement
	 * @param objIDictReader DictionaryReader to read from the Dictionary
	 * @throws InvalidDataElementException Signals Data Element fails to satisfy Validation Criteria. 
	 */
	public ImplicitDE(int iGroupNumber,int iElementNumber,Object objValue,IDictionaryReader objIDictReader) throws InvalidDataElementException
	{
		this(iGroupNumber, iElementNumber, objValue, new TransferSyntax(), objIDictReader);
	}

	/**
	 * Creates Implicit DataElement based on the GroupNumber, ElementNumber, VR Type , Dicom Data , Transfer Syntax and Dictionary Reader.
	 * The Dicom data should be populated.
	 * @param iGroupNumber GroupNumber from the Tag identifying this DataElement.
	 * @param iElementNumber ElementNumber from the Tag identifying this DataElement.
	 * @param iVRType Value Representation Type specified in @see DicomConstants.
	 * @param objIDicomValue Populated Dicom Data to be set in Implicit Data Element.
	 * @param objTransferSyntax value of Transfer Sytntax.
	 * @param objIDictReader Dictionary Reader instance.
	 * @throws InvalidDataElementException thrown when creation of Data Element fails.
	 * @throws InvalidTransferSyntaxException thrown when creation of Transfer Syntax fails.
	 */
	public ImplicitDE(int iGroupNumber,int iElementNumber,IDicomValue objIDicomValue, ITransferSyntax objTransferSyntax, IDictionaryReader objIDictReader) throws InvalidDataElementException , InvalidTransferSyntaxException
	{
		try
		{
			if((objTransferSyntax.getVRTransferSyntax())== DicomConstants.DCM_VR_EXPLICIT)
				throw new InvalidTransferSyntaxException();
			this.objIDicomValue =objIDicomValue;
			this.objIDictionaryReader = objIDictReader;
			this.objITransferSyntax =objTransferSyntax;

			//Initializing Tag 
			setTag(iGroupNumber, iElementNumber);

			if(objIDicomValue != null)
			{
				/*
				 * This If block is checking whether given DicomValue has valid VR type or not.
				 * If VR type is invalid and logging is on then log will be generated.
				 */
				String strDictVRType = objIDictReader.getVR(iGroupNumber, iElementNumber);
				if(strDictVRType != null)
				{
					/*
					 * Logs will be generated if DataElement is retired. 
					 */
					if(objIDictionaryReader.isRetired(iGroupNumber,iElementNumber))
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","RetiredDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
						}
					}
					/*
					 * If the transferSyntax is LittleIndianImplicit then for PixelData(7FE0,0010),OverlayData(60XX,3000) and WaveformData(5400,1010) VR type must be OW.
					 * For CurveData(50XX,3000) VR type must be OB.
					 * refer pdf 5,page no.59
					 */
					if (strDictVRType.equalsIgnoreCase(DCM_DT_OB_OR_OW) || strDictVRType.equalsIgnoreCase(DCM_DT_OW_OR_OB))
					{
						if((iGroupNumber == 0x7FE0 && iElementNumber == 0x0010) || ((iGroupNumber >= 0x6000 || iGroupNumber < 0x7000) && iElementNumber == 0x3000) || (iGroupNumber == 0x5400 && iElementNumber == 0x1010))
						{
							if(objIDicomValue.getIVRType() != DicomConstants.DCM_DT_OW)
							{
								if(DicomConfig.createInstance().isLoggingOn())
								{
									DicomLogger objDicomLogger = DicomLogger.getLogger();
									objDicomLogger.log(ResourceBundleWrapper.getValue("warning","VRTypeNotMatched",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
								}
							}
						}
						else if((iGroupNumber >= 0x5000 || iGroupNumber < 0x6000) && iElementNumber == 0x3000)
						{
							if(objIDicomValue.getIVRType() != DicomConstants.DCM_DT_OB)
							{
								if(DicomConfig.createInstance().isLoggingOn())
								{
									DicomLogger objDicomLogger = DicomLogger.getLogger();
									objDicomLogger.log(ResourceBundleWrapper.getValue("warning","VRTypeNotMatched",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
								}
							}
						}
					}
					else if(strDictVRType.equalsIgnoreCase(DCM_DT_US_OR_SS) || strDictVRType.equalsIgnoreCase(DCM_DT_SS_OR_US))
					{
						//If for a DataElement the VR type can be US or SS then it is only checking that it should be one of them. 
						if(objIDicomValue.getIVRType() != DicomConstants.DCM_DT_US && objIDicomValue.getIVRType() != DicomConstants.DCM_DT_SS)
						{
							{
								DicomLogger objDicomLogger = DicomLogger.getLogger();
								objDicomLogger.log(ResourceBundleWrapper.getValue("warning","VRTypeNotMatched",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
							}
						}
					}
					else if(StandardMethods.getiVRtype(strDictVRType) != objIDicomValue.getIVRType())
					{
						/*
						 * If VR type does not match then logging is generated and throwing exception if validation mode is STRICT or MEDIUM.
						 */
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","VRTypeNotMatched",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
						}
					}
				}
				else
				{
					/*
					 * If VR from dictionary is null it means element is not in dictionary.
					 * if, even group number and not present in dictionary then exception will be generated.
					 * else, VR provided from outside will be taken and log generated.
					 */
					if(iGroupNumber%2 == 0)
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","DataElementMissing",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
						}

					}
					else
					{
						objIDicomValue.setIVRType(DicomConstants.DCM_DT_UN);
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","PrivateDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
						}
					}
				}
			}
		}
		catch( InvalidDataTypeException dex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			String strMessage = Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber());
			throw new InvalidDataElementException(strMessage, dex);
		}
		catch( InvalidTransferSyntaxException dex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			String strMessage = Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber());
			throw new InvalidDataElementException(strMessage, dex);
		}
	}
	/**
	 * This constructor can be used to create a dataelement 
	 * containing sequence in which case the Transfersyntax needs to be specified from outside
	 * @param iGroupNumber GroupNumber from the Tag identifying this DataElement
	 * @param iElementNumber ElementNumber from the the identifying this DataElement
	 * @param objValue value of the DataElement
	 * @param objTransferSyntax TransferSyntax specified by DICOM Standard
	 * @param objIDictReader DictionaryReader to read from the Dictionary
	 * @throws InvalidDataElementException Signals Data Element fails to satisfy Validation Criteria. 
	 * @throws InvalidTransferSyntaxException Signals Transfer Syntax fails to satisfy Validation Criteria.
	 */
	public ImplicitDE(int iGroupNumber,int iElementNumber,Object objValue,ITransferSyntax objTransferSyntax, IDictionaryReader objIDictReader) throws InvalidDataElementException , InvalidTransferSyntaxException
	{
		try{
			if((objTransferSyntax.getVRTransferSyntax())== DicomConstants.DCM_VR_EXPLICIT)
				throw new InvalidTransferSyntaxException();
			objITransferSyntax = objTransferSyntax;
			objIDictionaryReader = objIDictReader;

			//Initializing Tag 
			setTag(iGroupNumber, iElementNumber);

			int iVRType = 0;
			String strVRType = objIDictionaryReader.getVR(iGroupNumber,iElementNumber);

			if(strVRType!= null)
			{
				/*
				 * If the transferSyntax is LittleIndianImplicit then for PixelData(7FE0,0010),OverlayData(60XX,3000) and WaveformData(5400,1010) VR type must be OW.
				 * For CurveData(50XX,3000) VR type must be OB.
				 * refer pdf 5,page no.59
				 */
				/*
				 * Logs will be generated if DataElement is retired. 
				 */
				if(objIDictionaryReader.isRetired(iGroupNumber,iElementNumber))
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","RetiredDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				if (strVRType.equalsIgnoreCase(DCM_DT_OB_OR_OW) || strVRType.equalsIgnoreCase(DCM_DT_OW_OR_OB))
				{
					if((iGroupNumber == 0x7FE0 && iElementNumber == 0x0010) || ((iGroupNumber >= 0x6000 || iGroupNumber < 0x7000) && iElementNumber == 0x3000) || (iGroupNumber == 0x5400 && iElementNumber == 0x1010))
						strVRType = DCM_DT_OW;
					else if((iGroupNumber >= 0x5000 || iGroupNumber < 0x6000) && iElementNumber == 0x3000)
						strVRType = DCM_DT_OB;
				}
				/*
				 * For DataElements (0028,1101),(0028,1102),(0028,1103) Red,Green,Blue Palette Lookup Table Descriptor can have VR type US/SS
				 * but first and third values are always by definition interpreted as unsigned.
				 * DataElement(0028,3006) can have US/SS/OW VR type.
				 * So for every element of this kind we are taking VR Type as US.
				 * refer pdf 5 page 61.
				 */
				else if (strVRType.equalsIgnoreCase(DCM_DT_US_OR_SS) || strVRType.equalsIgnoreCase(DCM_DT_SS_OR_US))
				{
					strVRType = DCM_DT_US;
				}
				iVRType = StandardMethods.getiVRtype(strVRType);
			}
			else
			{
				/*
				 * If VR from dictionary is null it means element is not in dictionary.
				 * if, even group number and not present in dictionary then exception will be generated.
				 * else, VR provided from outside will be taken and log generated.
				 */
				if(iGroupNumber%2 == 0)
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","DataElementMissing",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				else
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","PrivateDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				iVRType = DicomConstants.DCM_DT_UN;
			}

			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();

			/*
			 * Modified create sequence method call to pass TS and dictionaryreader
			 */
			/*
			 * This condition is added because if  the sequence object is to be created, then 
			 * we desire to create the actual sequence specified by the tag values
			 */
			if(iVRType == DicomConstants.DCM_DT_SQ)
				objIDicomValue = objDicomV3Factory.createSequence(iGroupNumber, iElementNumber, objITransferSyntax, objIDictionaryReader);
			else
				objIDicomValue = objDicomV3Factory.createDataType(iVRType);
			if(objIDicomValue != null)
			{
				/*
				 * setValue function throws DataTypeException. Hence catch it and add it as a cause
				 * of InvalidDataElementException which is thrown by ImplicitDE constructor
				 */
				if(objValue != null)
					objIDicomValue.setValue(objValue);
			}
		}
		catch(InvalidDataTypeException dex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			String strMessage = Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber());
			throw new InvalidDataElementException(strMessage, dex);
		}
		catch( InvalidTransferSyntaxException dex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dex.getMessage());
			}
			String strMessage = Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber());
			throw new InvalidDataElementException(strMessage, dex);
		}
	}

	/**
	 * Retrieves the DicomValue present in the Implicit DataElement
	 * @return DicomValue - object of Dicom Data
	 */
	public IDicomValue getDicomValue()
	{
		return objIDicomValue;
	}


	/**
	 * parse method reads the Tag,ValueLength,Data Value from the Stream.
	 * It gets the Value Representation(VR) for the Data Value from the 
	 * Dictionary. It compares for the Value Multiplicity returned after reading
	 * the Data Value with Value Multiplicity read from Dictionary and sets it to 
	 * the DataElement. 
	 * 
	 * Note : It could throw OutOfMemoryException if length exceeds from allowed Heap Space. 
	 * @param objIDicomStream  stream from which the DataType is to be written
	 * @return integer - returns status success/failure 
	 * @throws InvalidDataElementException Signals Data Element fails to satisfy Validation Criteria.
	 * @throws IOException Signals that an I/O exception of some sort has occurred
	 */
	public int parse(IDicomStream objIDicomStream) throws InvalidDataElementException, IOException
	{
		int iTempValueLength = 0;

		try
		{
			int iGroupNumber = 0;
			int iElementNumber = 0;
			int iVRType=0;
			//Read GroupNumber and ElementNumber 
			iGroupNumber=objIDicomStream.readShort();
			iElementNumber=objIDicomStream.readShort();

			//System.out.println("Parsing DE: " + iGroupNumber+ "  "+ iElementNumber);
			//getting changed even if it is greater than 0
			if(iGroupNumber < 0 )
			{
				iGroupNumber+= 2;
				iGroupNumber = (Short.MAX_VALUE * 2 + iGroupNumber);
			}
			if(iElementNumber < 0)
			{
				iElementNumber+= 2;
				iElementNumber = (Short.MAX_VALUE * 2 + iElementNumber);
			}
			if(iGroupNumber == DicomConstants.DCM_NESTED_ITEM_DELIMITATION_DATA_MAJOR_TAG 
					&& iElementNumber == DicomConstants.DCM_NESTED_ITEM_DELIMITATION_DATA_MINOR_TAG)
			{
				objIDicomStream.readInt();
				return GlobalConstants.DCM_ITEM_DELIMITATION;
			}
			//Set the GroupNumber and ElementNumber to the DataElement
			//Initializing Tag 
			setTag(iGroupNumber, iElementNumber);
			//Read the Value Representation Type from the Dictionary
			String strTempVR = readVRFromDictionary(iGroupNumber, iElementNumber);

			if(strTempVR != null)
			{
				/*
				 * Logs will be generated if DataElement is retired. 
				 */
				if(objIDictionaryReader.isRetired(iGroupNumber,iElementNumber))
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","RetiredDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				if(strTempVR.equalsIgnoreCase(DCM_DT_OW_OR_OB) || strTempVR.equalsIgnoreCase(DCM_DT_OB_OR_OW))
				{
					/*
					 * If the transferSyntax is LittleIndianImplicit then for PixelData(7FE0,0010),OverlayData(60XX,3000) and WaveformData(5400,1010) VR type must be OW.
					 * For CurveData(50XX,3000) VR type must be OB.
					 * refer pdf 5,page no.59
					 */
					if((iGroupNumber == 0x7FE0 && iElementNumber == 0x0010) || ((iGroupNumber >= 0x6000 || iGroupNumber < 0x7000) && iElementNumber == 0x3000) || (iGroupNumber == 0x5400 && iElementNumber == 0x1010))
						strTempVR = DCM_DT_OW;
					else if((iGroupNumber >= 0x5000 || iGroupNumber < 0x6000) && iElementNumber == 0x3000)
						strTempVR = DCM_DT_OB;
				}
				else if(strTempVR.equalsIgnoreCase(DCM_DT_US_OR_SS) || strTempVR.equalsIgnoreCase(DCM_DT_SS_OR_US))
				{
					/*
					 * For DataElements (0028,1101),(0028,1102),(0028,1103) Red,Green,Blue Palette Lookup Table Descriptor can have VR type US/SS
					 * but first and third values are always by definition interpreted as unsigned.
					 * DataElement(0028,3006) can have US/SS/OW VR type.
					 * So for every element of this kind we are taking VR Type as US.
					 * refer pdf 5 page 61.
					 */
					strTempVR = DCM_DT_US;
				}
				iVRType = StandardMethods.getiVRtype(strTempVR);
			}
			else 
			{
				/*
				 * If VR from dictionary is null it means element is not in dictionary.
				 * if, even group number and not present in dictionary then exception will be generated.
				 * else, VR provided from outside will be taken and log generated.
				 */
				if(iGroupNumber%2 == 0)
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","DataElementMissing",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				else
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("warning","PrivateDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ iGroupNumber + "," + iElementNumber);
					}
				}
				iVRType = DicomConstants.DCM_DT_UN;
			}

			/*
			 * This method will set the length read from the stream in the DataElement.
			 * But it should not be setting it in the IDicomValue. since lengths may be different.
			 * For detailed reason, see description in IDicomValue interface
			 */
			iTempValueLength = objIDicomStream.readInt();

			DicomV3Factory objDicomV3Factory=DicomV3Factory.createInstance();
			//Get Datatype Object from Factory and set it to DataElement
			/*
			 * This condition is added because if  the sequence object is to be created, then 
			 * we desire to create the actual sequence specified by the tag values
			 */
			if(iVRType == DicomConstants.DCM_DT_SQ)
			{
				/*
				 * Modified create sequence method call to pass TS and dictionaryreader
				 */
				objIDicomValue = objDicomV3Factory.createSequence(iGroupNumber, iElementNumber, objITransferSyntax, objIDictionaryReader);
			}
			else
			{
				objIDicomValue = objDicomV3Factory.createDataType(iVRType);
			}

			//Set the values for this DicomValue object
			objIDicomValue.setIVRType(iVRType);

			//Read the DataValue and Get the Value Multiplicity from the DataValue
			if(DicomConfig.createInstance().isTempStorageInUse())
			{
				if(iGroupNumber == 0x7FE0 && iElementNumber == 0x0010 && iVRType == DicomConstants.DCM_DT_OB)
				{
					objIDicomValue = objDicomV3Factory.getOBImageObject();
				}
				else if(iGroupNumber == 0x7FE0 && iElementNumber == 0x0010 && iVRType == DicomConstants.DCM_DT_OW)
				{
					objIDicomValue = objDicomV3Factory.getOWImageObject();
				}
			}

			if((objIDicomStream.available() >= iTempValueLength) && (iTempValueLength >= -1) && (iTempValueLength <= Integer.MAX_VALUE)) 
				objIDicomValue.read(objIDicomStream, iTempValueLength);
			setDicomValue(objIDicomValue);	
		}
		catch( InvalidDataTypeException dte)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(dte.getMessage());
			}
			if(DicomConfig.createInstance().isLoggingOn()&&(DicomConfig.createInstance().getLoggingLevel() == EnumLoggingLevel.INFO))
			{
				DicomBufferStream objDicomBufferStream = new DicomBufferStream();
				ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
				objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
				this.serialize(objDicomBufferStream);
				String strLogMessage = objDicomBufferStream.toString();
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(strLogMessage);
				objDicomLogger.log(dte.getMessage());
			}
			else if(DicomConfig.createInstance().isLoggingOn()&&(DicomConfig.createInstance().getLoggingLevel() == EnumLoggingLevel.SEVERE))
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();	
				objDicomLogger.log(dte.getMessage());
			}

		}
		catch( OutOfMemoryException ome)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ome.getMessage());
			}
			String strMessage = Integer.toHexString(objITag.getGroupNumber()) + "," + Integer.toHexString(objITag.getElementNumber());
			throw new OutOfMemoryException(strMessage, ome);
		}
		return 1;
	}

	/**
	 * This method is used to write the Data Element to the Stream
	 * @param objIDicomStream : Stream Object on which to write the Data Element
	 * @return Integer: 1 if Data Element is written successfully to the Stream.
	 * 					0 if Exception occurs during the Process. 
	 * @throws IOException Signals that an I/O exception of some sort has occurred
	 */
	public int serialize(IDicomStream objIDicomStream) throws IOException
	{
		IDicomValue objIDicomValue=null;
		short shGroupNumber=0,shElementNumber=0;

		//Get the GroupNumber and the Element Number
		shGroupNumber=(short)objITag.getGroupNumber();
		shElementNumber=(short)objITag.getElementNumber();

		//System.out.println("Serializing DE: " + shGroupNumber+ "  "+ shElementNumber);

		//Write the GroupNumber and the Element Number to the Stream
		objIDicomStream.writeShort(shGroupNumber);
		objIDicomStream.writeShort(shElementNumber);

		//If the odd length value is present, mkae it even by incrementing it
		//Value will be padded with a NULL character and written to stream
		//This will be taken care by the write method of datatype class

		/*
		 *The value length should be modified only if it is not UNDEFINED LENGTH
		 */

		// commented this code as getValueLength() itself returns even length.
		//	if((getValueLength() != DicomConstants.DCM_UNDEFINED_LENGTH) && ((getValueLength() % 2) != 0))
		//	objIDicomStream.writeInt(getValueLength() + 1);
		//	else
		//Write the Length to Stream
		objIDicomStream.writeInt(getValueLength());

		//Get the Value
		objIDicomValue=this.getDicomValue();

		if(objIDictionaryReader != null)
		{
			if(objIDictionaryReader.isRetired(shGroupNumber, shElementNumber) && DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ResourceBundleWrapper.getValue("warning","RetiredDataElement",new Locale(DicomConfig.createInstance().getLocale()))+ shGroupNumber + "," + shElementNumber);
			}
		}

		//Write the Value
		//check if DicomValue object is not NULL then only call write on it.s

		if(objIDicomValue != null)
		{
			return objIDicomValue.write(objIDicomStream);
		}
		else
			return 0;
	}

	private String readVRFromDictionary(int iGroupNumber,int iElementNumber)
	{
		return objIDictionaryReader.getVR(iGroupNumber,iElementNumber);
	}


	/**
	 * Retrieves the length of the DataElement
	 * @return integer - the length of the DataElement
	 */
	public int getDataElementLength()
	{
		return TAG_LENGTH + VALUE_INT_LENGTH + getValueLength();
	}

	/**
	 * sets the DicomValue into the DataElement. DicomValue represents the value of the DataElement
	 * @param objIDicomValue object of IDicomValue which represents the value of the DataElement
	 */
	public void setDicomValue(IDicomValue objIDicomValue)
	{
		int iMinVM=objIDictionaryReader.getMinVM(objITag.getGroupNumber(), objITag.getElementNumber());
		int iMaxVM=objIDictionaryReader.getMaxVM(objITag.getGroupNumber(), objITag.getElementNumber());

		//Compare this Value Multiplicity with the Value Multiplicity read from the
		//Dictionary.Both should be same since VR type read from Dictionary and 
		//type of Object returned from Factory should be same.
		//Modified the condition by Atreya on 21-05-07,maxVM should be equal to 
		//UNDEFINED LENGTH and not iVM
		if((iVM >= iMinVM && iMaxVM == DicomConstants.DCM_UNDEFINED_LENGTH) || (iVM >= iMinVM && iVM <= iMaxVM))
		{
			//Set VM to DataElement
			setValueMultiplicity(iVM);
		}
	}
}
