/*******************************************************************************
 *  Copyright 2017-2018 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.dcm30_04.services.basicapplicationlevelconfidentialityprofile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

import cdac.medinfo.sdk.dcm30_04.baselibs.DataSet;
import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.EncryptedAttributesSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.EncryptedAttributesSequenceItem;
import cdac.medinfo.sdk.dcm30_04.baselibs.ExplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.TransferSyntax;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataTypeSQ;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.SOPCommonModule;
import cdac.medinfo.sdk.dcm30_04.dicomparserserializers.DicomParser;
import cdac.medinfo.sdk.dcm30_04.dicomstreams.DicomBufferStream;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;

/*
 * This class works as an agent for Basic Application Level Confidentiality Profile.
 * It has methods to tell whether the element is confidential or not, encrypt the confidential data elements
 * and add it to Encrypted Attribute Sequence and to decrypt these data elements.
 */
class BasicAppAgent 
{
	private EnumProfileAlgorithm enumProfileAlgorithm;
	private IDataSet objConfidentialityList = null;
	private byte[] objKey;
	private byte[] IV;

	/*
	 * This method tell whether the Tag is Confidential Data ELemtn or Not.
	 * returns true if the attribute is confidential.
	 * Otherwise false is returned.
	 */
	boolean isConfidential(ITag objITag)
	{
		if(objITag.equals(EnumConfidentialityProfileAttributes.ACCESSION_NUMBER.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.ADDITIONAL_PATIENT_HISTORY.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.ADMITTING_DIAGNOSES_DESCRIPTION.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.CONTENT_SEQUENCE.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.DERIVATION_DESCRIPTION.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.DEVICE_SERIAL_NUMBER.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.ETHNIC_GROUP.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.FRAME_OF_REFERENCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.IMAGE_COMMENTS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.INSTANCE_CREATOR_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.INSTITUTION_ADDRESS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.INSTITUTION_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.INSTITUTIONAL_DEPARTMENT_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.MEDICAL_RECORD_LOCATOR.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.NAME_OF_PHYSICIAN_READING_STUDY.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.OCCUPATION.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.OPERATOR_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.OTHER_PATIENT_IDS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.OTHER_PATIENT_NAMES.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_AGE.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_BIRTH_DATE.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_BIRTH_TIME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_COMMENTS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_ID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_SEX.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_SIZE.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PATIENT_WEIGHT.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PERFORMING_PHYSICIAN_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PHYSICIAN_OF_RECORD.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.PROTOCOL_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REFERENCED_FRAME_OF_REFERENCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REFERENCED_SOP_INSTANCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REFERRING_PHYSICIAN_ADDRESS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REFERRING_PHYSICIAN_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REFERRING_PHYSICIAN_TELEPHONE_NUMBERS.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.RELATED_FRAME_OF_REFERENCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.REQUEST_ATTRIBUTES_SEQUENCE.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.SERIES_DESCRIPTION.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.SERIES_INSTANCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.SOP_INSTANCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.STATION_NAME.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.STORAGE_MEDIA_FILESET_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.STUDY_DESCRIPTION.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.STUDY_ID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.STUDY_INSTANCE_UID.getValue()))
			return true;
		if(objITag.equals(EnumConfidentialityProfileAttributes.SYNCHRONIZATION_FRAME_OF_REFERENCE_UID.getValue()))
			return true;

		return false;
	}

	/*
	 * This function adds the Data Elements to Confidentiality List.
	 */
	void addDataElementToConfidentialList(IDataElement objIDataElement)
	{
		if(objConfidentialityList == null)
		{
			objConfidentialityList = new DataSet(objIDataElement.getTransferSyntax());
		}
		IDataElement objTempDE = getDataElement(objIDataElement);
		objConfidentialityList.addDataElement(objTempDE);
	}

	/*
	 * This method gets the Data Element of the Value Specified.
	 */
	IDataElement getDataElement(IDataElement objIOriginalDE)
	{
		IDataElement objDummyIDataElement = null;

		if(objIOriginalDE != null)
		{
			if(objIOriginalDE instanceof ImplicitDE)
			{
				ImplicitDE objImplicitDE = (ImplicitDE)objIOriginalDE;
				objDummyIDataElement = new ImplicitDE(objImplicitDE.getTag().getGroupNumber(),objImplicitDE.getTag().getElementNumber(),objIOriginalDE.getDicomValue(),objImplicitDE.getTransferSyntax(),objImplicitDE.getDictionaryReader());
			}
			else if(objIOriginalDE instanceof ExplicitDE)
			{
				ExplicitDE objExplicitDE = (ExplicitDE)objIOriginalDE;
				objDummyIDataElement = new ExplicitDE(objExplicitDE.getTag().getGroupNumber(),objExplicitDE.getTag().getElementNumber(),objExplicitDE.getIVRType(),objIOriginalDE.getDicomValue(),objExplicitDE.getTransferSyntax(),objExplicitDE.getDictionaryReader());
			}
			else 
				return objIOriginalDE;
		}
		return objDummyIDataElement;
	}
	
	/*
	 * This method gets the Data Element of the Value Specified.
	 */
	IDataElement getDataElement(IDataElement objIOriginalDE, Object objValue)
	{
		IDataElement objDummyIDataElement = null;

		if(objIOriginalDE != null)
		{
			if(objIOriginalDE instanceof ImplicitDE)
			{
				ImplicitDE objImplicitDE = (ImplicitDE)objIOriginalDE;
				objDummyIDataElement = new ImplicitDE(objImplicitDE.getTag().getGroupNumber(),objImplicitDE.getTag().getElementNumber(),objValue,objImplicitDE.getTransferSyntax(),objImplicitDE.getDictionaryReader());
			}
			else if(objIOriginalDE instanceof ExplicitDE)
			{
				ExplicitDE objExplicitDE = (ExplicitDE)objIOriginalDE;
				objDummyIDataElement = new ExplicitDE(objExplicitDE.getTag().getGroupNumber(),objExplicitDE.getTag().getElementNumber(),objExplicitDE.getIVRType(),objValue,objExplicitDE.getTransferSyntax(),objExplicitDE.getDictionaryReader());
			}
			else 
				return objIOriginalDE;
		}
		return objDummyIDataElement;
	}

	/*
	 * This method creates Encrypted Attribute Sequence from the Confidential Attributes, encrypt then and add it to the presnet data set.
	 */
	void addEncryptedAttributeSequence(IDataSet objIDataSet) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException, InvalidAlgorithmParameterException
	{
		Base64 objBEncoder = new Base64();
		EncryptAgent objEncryptAgent = new EncryptAgent();

		SOPCommonModule objSOPCommonModule = new SOPCommonModule(objIDataSet);

		/*
		 * Get EncryptedAttributesSequence from SOP Common Module.
		 */
		EncryptedAttributesSequence objEncryptedAttributesSequence = objSOPCommonModule.getEncryptedAttributesSequence();
		objEncryptedAttributesSequence.changeToUndefined();
		EncryptedAttributesSequenceItem objEncryptedAttributesSequenceItem = (EncryptedAttributesSequenceItem)objEncryptedAttributesSequence.getNewItem();

		/*
		 * Serialize The TS Used for encryption on to the Dicom Buffer Stream and encrypt it.
		 */
		DicomBufferStream objDicomBufferStream = new DicomBufferStream();
		ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
		objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
		objDicomBufferStream.setEndianNess(objConfidentialityList.getTransferSyntax().getEndianNess());
		objDicomBufferStream.writeBuffer(objConfidentialityList.getTransferSyntax().getTransferSyntaxUID().getBytes(), 0, objConfidentialityList.getTransferSyntax().getTransferSyntaxUID().getBytes().length);
		ByteArrayInputStream objByteArrayInputStream = new ByteArrayInputStream(objDicomBufferStream.toByteArray());
		objDicomBufferStream.setInputStream(objByteArrayInputStream);

		byte[] arrEncyptByte = objEncryptAgent.encrypt(objDicomBufferStream, enumProfileAlgorithm, objKey, IV);
		byte[] byteValue =objBEncoder.encode(arrEncyptByte);
		String strValue = new String(byteValue);
		objEncryptedAttributesSequenceItem.setEncryptedContentTransferSyntaxUID(strValue);

		/*
		 * Serialize all the data elements present in the Confidentiality List and 
		 * encrypt it.
		 */
		IDataTypeSQ objIDataTypeSQ = DicomV3Factory.createInstance().createSequence(0x0400,0x0550 ,objIDataSet.getTransferSyntax());;
		IItem objItem = objIDataTypeSQ.getNewItem();
		IDataElement objIDataElementForType = null;
		if(objConfidentialityList.iterator().hasNext())
		{
			for(IDataElement objITempDataElement : objConfidentialityList)
			{
				objIDataElementForType = objITempDataElement;
				objItem.addDataElement(objITempDataElement);
			}
			ISingleCollection<IItem> objSingleCollection = new SingleCollection<IItem>();
			objSingleCollection.add(objItem);
			IDataElement objModifiedAttDE = createDataElement(0x0400,0x0550 , objIDataElementForType,objSingleCollection );
			objDicomBufferStream = new DicomBufferStream();
			objByteArrayOutputStream = new ByteArrayOutputStream();
			objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
			objDicomBufferStream.setEndianNess(objConfidentialityList.getTransferSyntax().getEndianNess());
			objModifiedAttDE.serialize(objDicomBufferStream);
			objByteArrayInputStream = new ByteArrayInputStream(objDicomBufferStream.toByteArray());
			objDicomBufferStream.setInputStream(objByteArrayInputStream);

			arrEncyptByte = objEncryptAgent.encrypt(objDicomBufferStream, enumProfileAlgorithm, objKey, IV);

			/*
			 * Add this encrypted byte array to sindle collection add it to the item
			 * of EncryptedAttributesSequence.
			 */
			if(arrEncyptByte != null)
			{
				ISingleCollection<byte[]> objByteArrayColl = new SingleCollection<byte[]>();
				objByteArrayColl.add(arrEncyptByte);
				objEncryptedAttributesSequenceItem.setEncryptedContent(objByteArrayColl);
			}
		}
		objEncryptedAttributesSequence.addItem(objEncryptedAttributesSequenceItem);
	}

	IDataElement createDataElement(int groupNo, int ElementNo, IDataElement objIDataElementForType , Object objValue)
	{
		if(objIDataElementForType instanceof ImplicitDE)
		{
			ImplicitDE objTempDE = (ImplicitDE)objIDataElementForType;
			IDataElement objIDataElementRSP = new ImplicitDE(groupNo,ElementNo,objValue,objIDataElementForType.getTransferSyntax(),objTempDE.getDictionaryReader());
			return objIDataElementRSP;
		}
		else
		{
			ExplicitDE objTempDE = (ExplicitDE)objIDataElementForType;
			IDictionaryReader objIDictionaryReader = objTempDE.getDictionaryReader();
			String strVR = objIDictionaryReader.getVR(groupNo, ElementNo);
			int iVR = StandardMethods.getiVRtype(strVR);
			IDataElement objIDataElementRSP = new ExplicitDE(groupNo,ElementNo,iVR,objValue,objIDataElementForType.getTransferSyntax(),objTempDE.getDictionaryReader());
			return objIDataElementRSP;
		}
	}
	/*
	 * This function sets the profile algorithm for encryption and decryption.
	 */
	void setProfileAlgorithm(EnumProfileAlgorithm enumProfileAlgorithm)
	{
		this.enumProfileAlgorithm = enumProfileAlgorithm;
	}

	/*
	 * This function sets the secret key used for encryption and decryption.
	 */
	public void setSecretKey(byte[] objSecretKey)
	{
		this.objKey = objSecretKey;
	}

	/*
	 * This function decrypts the data set.
	 */
	@SuppressWarnings("unchecked")
	IDataSet decryptDataSet(IDataSet objIDataSet) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException
	{
		Base64 objBDecoder = new Base64();
		DecryptAgent objDecryptAgent = new DecryptAgent();

		/*
		 * Create the resultant data set.
		 */
		IDataSet objRSPDataSet = new DataSet(objIDataSet.getTransferSyntax(),objIDataSet.getDictionaryReader());

		/*
		 * First add all the Data Elements to the Resultant Data Set.
		 */
		for(IDataElement objDE : objIDataSet)
		{
			objRSPDataSet.addDataElement(objDE);
		}

		/*
		 * if the encrypted attribute sequence is present then only it need to be decrypted. Otherwise no need to decrypt it.
		 */
		if(objIDataSet.isPresent(0x0400, 0x0500))
		{
			IDataElement objIDataElement = objIDataSet.getDataForTag(0x0400, 0x0500);

			if(objIDataElement.getValue() != null)
			{
				ISingleCollection<IItem> objModifiedAttrSeqItemCol = (ISingleCollection<IItem> )objIDataElement.getValue();

				for(IItem encryptedAttributesSequenceItem : objModifiedAttrSeqItemCol)
				{
					EncryptedAttributesSequenceItem encryptedTempAttributesSequenceItem = (EncryptedAttributesSequenceItem)encryptedAttributesSequenceItem;

					/*
					 * Get the Transfer Syntax UID from this sequence.
					 */
					String strValue = encryptedTempAttributesSequenceItem.getEncryptedContentTransferSyntaxUID();
					byte[] encryptedDataStringBytes = objBDecoder.decode(strValue.getBytes());


					/*
					 * Serialize TS to Dicom buffer stream and decrypt it.
					 */
					DicomBufferStream objDicomBufferStream = new DicomBufferStream();
					ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
					objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
					objDicomBufferStream.setEndianNess(objIDataElement.getTransferSyntax().getEndianNess());
					objDicomBufferStream.writeBuffer(encryptedDataStringBytes, 0, encryptedDataStringBytes.length);
					ByteArrayInputStream objByteArrayInputStream = new ByteArrayInputStream(objDicomBufferStream.toByteArray());
					objDicomBufferStream.setInputStream(objByteArrayInputStream);
					IDicomStream objIDicomStream = objDecryptAgent.decrypt(objDicomBufferStream, enumProfileAlgorithm, objKey, IV);
					objByteArrayInputStream = new ByteArrayInputStream(((DicomBufferStream)objIDicomStream).toByteArray());
					((DicomBufferStream)objIDicomStream).setInputStream(objByteArrayInputStream);
					strValue = ((DicomBufferStream)objIDicomStream).readString(objIDicomStream.available());

					ITransferSyntax objITransferSyntax = null;
					if(strValue != null)
					{
						objITransferSyntax = new TransferSyntax(strValue);
					}

					/*
					 * Serialize Encrypted attribute content on Dicom Buffer Stream and decrypt it.
					 */
					objDicomBufferStream = new DicomBufferStream();
					objByteArrayOutputStream = new ByteArrayOutputStream();
					objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
					objDicomBufferStream.setEndianNess(objRSPDataSet.getTransferSyntax().getEndianNess());
					ISingleCollection<byte[]> objByteArrayColl = encryptedTempAttributesSequenceItem.getEncryptedContent();
					if(objByteArrayColl != null)
					{
						for(byte[] arrByteTemp : objByteArrayColl)
						{
							objDicomBufferStream.writeBuffer(arrByteTemp, 0, arrByteTemp.length);
							objByteArrayInputStream = new ByteArrayInputStream(objDicomBufferStream.toByteArray());
							objDicomBufferStream.setInputStream(objByteArrayInputStream);
							objIDicomStream = objDecryptAgent.decrypt(objDicomBufferStream,enumProfileAlgorithm,objKey,IV);
							if(objIDicomStream != null)
							{
								objByteArrayInputStream = new ByteArrayInputStream(((DicomBufferStream)objIDicomStream).toByteArray());
								((DicomBufferStream)objIDicomStream).setInputStream(objByteArrayInputStream);
								DicomParser objDicomParser = new DicomParser();
								if(objITransferSyntax != null)
									objDicomParser.setTransferSyntax(objITransferSyntax);
								else
									objDicomParser.setTransferSyntax(objRSPDataSet.getTransferSyntax());

								IDataSet objIDataSetTemp = objDicomParser.parseDataContents(objIDicomStream, true);

								/*
								 * Add original data elements to the resultant Data Set.
								 */
								for(IDataElement objITempDataElement : objIDataSetTemp)
								{
									ISingleCollection<IItem> objITemCol = (ISingleCollection<IItem> )objITempDataElement.getValue();
									for(IItem objItem : objITemCol)
									{
										for(IDataElement objTempDE : objItem)
										{
											if(objRSPDataSet.getTransferSyntax().equals(objTempDE.getTransferSyntax()))
											{
												objRSPDataSet.addDataElement(objTempDE);
											}
											else
											{
												IDataElement objIDE = createDataElement(objTempDE, objIDataElement);
												objRSPDataSet.addDataElement(objIDE);
											}
										}
									}
								}
							}
						}
					}
				}
			}
			objRSPDataSet.removeDataElement(objIDataElement);
		}
		return objRSPDataSet;
	}

	/*
	 * This method created the objIdataElement of objIDataElementForDEType
	 */
	IDataElement createDataElement(IDataElement objIDataElement,IDataElement objIDataElementForDEType)
	{
		if(objIDataElementForDEType instanceof ImplicitDE)
		{
			ImplicitDE objTempDE = (ImplicitDE)objIDataElementForDEType;
			IDataElement objIDataElementRSP = new ImplicitDE(objIDataElement.getTag().getGroupNumber(),objIDataElement.getTag().getElementNumber(),objIDataElement.getValue(),objIDataElementForDEType.getTransferSyntax(),objTempDE.getDictionaryReader());
			return objIDataElementRSP;
		}
		else
		{
			ExplicitDE objTempDE = (ExplicitDE)objIDataElementForDEType;
			IDictionaryReader objIDictionaryReader = objTempDE.getDictionaryReader();
			String strVR = objIDictionaryReader.getVR(objIDataElement.getTag().getGroupNumber(), objIDataElement.getTag().getGroupNumber());
			int iVR = StandardMethods.getiVRtype(strVR);
			IDataElement objIDataElementRSP = new ExplicitDE(objIDataElement.getTag().getGroupNumber(),objIDataElement.getTag().getElementNumber(),iVR,objIDataElement.getValue(),objIDataElementForDEType.getTransferSyntax(),objTempDE.getDictionaryReader());
			return objIDataElementRSP;
		}
	}

	void setSaltParameter(byte[] objSaltParameter)
	{
		this.IV = objSaltParameter;
	}
}
