/*******************************************************************************
 *  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.basicapplevelconfyprof.testcases;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;


import cdac.medinfo.sdk.dcm30_04.baselibs.SQ;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.dicomparserserializers.DicomParser;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.services.basicapplicationlevelconfidentialityprofile.BasicAppLevelConfidentialityProfile;
import cdac.medinfo.sdk.dcm30_04.services.basicapplicationlevelconfidentialityprofile.EnumProfileAlgorithm;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.ICollectionIterator;

/**
 * This class is to Test Basic Application Level Confidentiality Profile Attribute.
 * This Basic Application Level Confidentiality Profile addresses the following aspects of security:
 * Data Confidentiality at the application level.
 * This Profile is targeted toward creating a special purpose, de-identified version of an already-existing Data Set.
 * This test code encrypts the Confidential Attributes in the data set and then decrypts it.
 */
public class ConfidentialProfUsing_DES
{
	public static void main(String[] args)
	{
		try
		{
			DicomConfig objDicomConfig = DicomConfig.createInstance();

			//enable logging,specify the path of the directory where log files are created.
			//User can specify any directory in place of 'c:\DCM_Logs'.
			//If no directory is defined by user to create logs then it is created in User Temp DIR.
			objDicomConfig.enableLogging(EnumLoggingLevel.INFO, "C:\\DCM_Logs");

			
			
			/*
			 * Generate Secret Key using for DES algo.
			 */
			KeyGenerator  keyGen = KeyGenerator .getInstance("DES");
			SecretKey objSecretKey = keyGen.generateKey();

			ConfidentialProfUsing_DES objTestConfidentialityProfUsingDES = new ConfidentialProfUsing_DES();

			/*
			 * Get the data set to be encrypted
			 */
			IDataSet objOriginalDataSet = objTestConfidentialityProfUsingDES.getDataSet();
			System.out.println("***************************************************************************************");
			System.out.println("**************** Displaying Original Data Set *****************************************");
			System.out.println("***************************************************************************************");
			objTestConfidentialityProfUsingDES.display(objOriginalDataSet);

			/*
			 * Encrypt the DataSet.
			 */
			IDataSet objEncryptedDataSet = objTestConfidentialityProfUsingDES.encrypt(objOriginalDataSet, EnumProfileAlgorithm.DES, objSecretKey.getEncoded());
			System.out.println("***************************************************************************************");
			System.out.println("**************** Displaying Encrypted Data Set *****************************************");
			System.out.println("***************************************************************************************");
			objTestConfidentialityProfUsingDES.display(objEncryptedDataSet);

			/*
			 * Decrypt the DataSet.
			 */
			IDataSet objDecryptedDataSet = objTestConfidentialityProfUsingDES.decrypt(objEncryptedDataSet, EnumProfileAlgorithm.DES, objSecretKey.getEncoded());
			System.out.println("***************************************************************************************");
			System.out.println("**************** Displaying Decrypted Data Set *****************************************");
			System.out.println("***************************************************************************************");
			objTestConfidentialityProfUsingDES.display(objDecryptedDataSet);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private IDataSet  getDataSet() throws IOException
	{
		DicomParser objDicomParser = new DicomParser();
		/*
		 * Accept the DICOM file from User to parse
		 */
		System.out.println("Enter the Dicom File name with complete path");
		BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
		String strFilePath = b_reader.readLine();
		IDataSet objRSPDataSet = objDicomParser.parseAsPart10File(strFilePath, true);
		return objRSPDataSet;
	}

	/*
	 * Displays the DataElements of Dataset
	 */
	private void display(IDataSet objIDataSet)
	{
		if(objIDataSet != null)
		{
			ICollectionIterator<IDataElement> objIDataSetIterator = objIDataSet.iterator();

			System.out.println("Tag     Value");
			while(objIDataSetIterator.hasNext())
			{
				IDataElement objDataElement = objIDataSetIterator.next();				

				if(!(objDataElement.getDicomValue() instanceof SQ))
				{

					System.out.println(objDataElement.getTag().getGroupNumber()+"    "+
							objDataElement.getTag().getElementNumber()+"    "+
							objDataElement.getDicomValue().toString());
				}
				else  
				{
					displaySequence((SQ)objDataElement.getDicomValue(),"> ");					
				}
			}
		}
		else
		{
			System.out.println("Data Set cannot be displayed. Data Set is null.");
		}
	}

	/*
	 * This method Display the SQ data type.
	 */
	private void displaySequence(SQ objSQDataElement,String ss)
	{
		if( objSQDataElement != null)
		{
			ICollectionIterator<IItem> objSQItemIterator = objSQDataElement.iterator();
			int i = 1;
			while(objSQItemIterator.hasNext())
			{
				System.out.println("ITEM :"+ i++ );
				IItem objItem = objSQItemIterator.next();
				ICollectionIterator<IDataElement> objDataElementIterator = objItem.iterator();
				while(objDataElementIterator.hasNext())
				{
					IDataElement objDataElement = objDataElementIterator.next();

					if(!(objDataElement.getDicomValue() instanceof SQ))
					{
						System.out.println(ss +objDataElement.getTag().getGroupNumber()+"    "+
								objDataElement.getTag().getElementNumber());						 

					}
					else
					{
						displaySequence((SQ)objDataElement.getDicomValue(),ss+ss);
					}	 
				}
			}
		}
		else
		{
			System.out.println("Data Element is null");
		}
	}

	/*
	 * get the Encrypted Data Set.
	 */
	public IDataSet encrypt(IDataSet objIDataSet, EnumProfileAlgorithm enumProfileAlgorithm, byte[] objKey) throws Exception
	{
		BasicAppLevelConfidentialityProfile objBasicAppLevelConfidentialityProfile = new BasicAppLevelConfidentialityProfile();
		IDataSet objRSPDataSet = objBasicAppLevelConfidentialityProfile.encryptDataSet(objIDataSet, enumProfileAlgorithm, objKey,null);
		return objRSPDataSet;
	}

	/*
	 * get the Decrypted Data Set.
	 */
	public IDataSet decrypt(IDataSet objIDataSet, EnumProfileAlgorithm enumProfileAlgorithm, byte[] objKey) throws Exception
	{
		BasicAppLevelConfidentialityProfile objBasicAppLevelConfidentialityProfile = new BasicAppLevelConfidentialityProfile();
		IDataSet objRSPDataSet = objBasicAppLevelConfidentialityProfile.decryptDataSet(objIDataSet, enumProfileAlgorithm, objKey,null);
		return objRSPDataSet;
	}
}
