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

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.imageio.ImageIO;


import cdac.medinfo.sdk.dcm30_04.baselibs.DataSet;
import cdac.medinfo.sdk.dcm30_04.baselibs.TransferSyntax;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicommodel.ct.CTIOD;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralEquipmentModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralImageModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralSeriesModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralStudyModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.ImagePixelModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.PatientModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.SOPCommonModule;
import cdac.medinfo.sdk.dcm30_04.dicomparserserializers.DicomSerializer;
import cdac.medinfo.sdk.dcm30_04.dictionaryreaderwriters.DictionaryReader;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBitsAllocated;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBitsStored;
import cdac.medinfo.sdk.dcm30_04.enums.EnumHighBit;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.enums.EnumModality;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPhotometricInterpretation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPixelDataVRType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPixelRepresentation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSamplesPerPixel;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * This SampleTest code shows conversion of JPEG Image to DICOM.
 */
public class JPEGToDICOMConvertor 
{
	/**
	 * This function sets the data set of CTIOD through setter methods of the module.
	 * Manually populated the IOD.
	 */
	public void populateCTIOD() throws IOException
	{
		CTIOD objCTIOD = null;
		IDataSet objIDataSet = null;
		IDictionaryReader objIDictionaryReader=null;

		/*
		 * Creates instance of DictionaryReader and Populates it.
		 */
		objIDictionaryReader = DictionaryReader.createInstance();
		if(!objIDictionaryReader.isDictionaryPopulated())
		{
			objIDictionaryReader.populate();
		}

		/*
		 * Creates TransferSyntax. To Create object of particular transfer syntax , 
		 * transfer syntax UID can be passed in constructor.
		 */
		ITransferSyntax objITransferSyntax = new TransferSyntax("1.2.840.10008.1.2.4.50");

		/*
		 * Creats DataSet with above transfer syntax and dictionary reader.
		 */
		objIDataSet = new DataSet(objITransferSyntax,objIDictionaryReader); 

		/*
		 * Creates CTIOD.
		 */
		objCTIOD = new CTIOD(objIDataSet);

		//get GeneralImageModule from CTIOD and populate its attributes.
		GeneralImageModule objGeneralImageModule = objCTIOD.getGeneralImageModule();
		objGeneralImageModule.setInstanceNumber("1");

		//Populating SOPCommonModule
		SOPCommonModule objSOPCommonModule = objCTIOD.getSOPCommonModule();
		objSOPCommonModule.setSOPClassUID("1.2.840.10008.5.1.4.1.1.20");
		objSOPCommonModule.setSOPInstanceUID("1.2.40.0.13.1.192.168.8.94.27737404.20090202122755531.3");
		objSOPCommonModule.setInstanceCreationDate("20090202");
		objSOPCommonModule.setInstanceCreationTime("122755.531");
		String[] str = new String[1];
		str[0] = "ISO_IR 100";
		objSOPCommonModule.setSpecificCharacterSet(str);

		//Populating GeneralStudyModule
		GeneralStudyModule objGeneralStudyModule = objCTIOD.getGeneralStudyModule();
		objGeneralStudyModule.setStudyDate("20090202");
		objGeneralStudyModule.setStudyTime("122755.531");
		objGeneralStudyModule.setReferringPhysicianName("Dr XYZ");
		objGeneralStudyModule.setStudyInstanceUID("1.2.40.0.13.1.192.168.8.94.27737404.20090202122755531.1");
		objGeneralStudyModule.setStudyID("1");
		objGeneralStudyModule.setAccessionNumber("1");

		//Populating GeneralSeriesModule
		GeneralSeriesModule objGeneralSeriesModule = objCTIOD.getGeneralSeriesModule();
		objGeneralSeriesModule.setModality(EnumModality.NUCLEAR_MEDICINE);
		objGeneralSeriesModule.setSeriesInstanceUID("1.2.40.0.13.1.192.168.8.94.27737404.20090202122755531.2");
		objGeneralSeriesModule.setSeriesNumber("1");

		//Populating GeneralEquipmentModule
		GeneralEquipmentModule objGeneralEquipmentModule = objCTIOD.getGeneralEquipmentModule();
		objGeneralEquipmentModule.setManufacturer("XYZ");

		//Populating PatientModule
		PatientModule objPatientModule = objCTIOD.getPatientModule();
		objPatientModule.setPatientName("ABC");
		objPatientModule.setPatientID("1");
		objPatientModule.setPatientBirthDate("19940910");
		objPatientModule.setPatientSex("F");

		//Populating ImagePixelModule
		ImagePixelModule objImagePixelModule = objCTIOD.getImagePixelModule();

		//Get the image data from jpeg file and sets it to Image Pixel Module.
		getImageData(objImagePixelModule);

		/*
		 * Serialize the DataSet created.
		 */
		serialize(objIDataSet);
		System.out.println("File Serialized Successfully");
	}

	/**
	 * This method serializes the data set .
	 * @param objIDataSet - The data set to be serialized.
	 */
	private void serialize(IDataSet objIDataSet)
	{
		try
		{
			/*
			 * path where to serialize the Dicom File.
			 */
			BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
			System.out.println("Enter the Dicom File name with complete path where to save the Serialzed File");
			String strFilePath = b_reader.readLine();

			/*
			 * Instance of DicomSerializer
			 */
			DicomSerializer objDicomSerializer = new DicomSerializer();

			/*
			 * Here DicomSerializer is being called to serialize the file.
			 * Parsing process takes two parameters.
			 * strFilePath - path of file to parse.
			 * objIDataSet - DataSet to be serialized.
			 * objDicomFileHeader - If null then dedfault will be used.
			 * boolean - This boolean value decides whether to convert the TransferSyntax 
			 * 							or default TransferSyntax (same as given in file)will be taken.  
			 */
			objDicomSerializer.serializeAsPart10File(strFilePath, objIDataSet, null,true);
		}
		catch(Exception ioe)
		{
			ioe.printStackTrace();
		}
	}

	/*
	 * Read the Image Data from JPEG File and populates Image Pixel Module Accordingly.
	 */
	private void getImageData(ImagePixelModule objImagePixelModule) throws IOException
	{
		/*
		 * path of JPEG File to get the image Data. 
		 */
		BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
		System.out.println("Enter the JPEG File from where to read the Image Data");
		String strFilePath = b_reader.readLine();
		File jpgSource=new File(strFilePath);

		BufferedImage jpegImage = ImageIO.read(jpgSource);
		if (jpegImage == null)
			System.out.println("in valid jpeg file");

		int colorComponents = jpegImage.getColorModel().getNumColorComponents();
		int bitsPerPixel = jpegImage.getColorModel().getPixelSize();
		int bitsAllocated = (bitsPerPixel / colorComponents);
		int samplesPerPixel = colorComponents;

		if(samplesPerPixel == 3)
			objImagePixelModule.getImagePixelMacro().setPhotometricInterpretation(EnumPhotometricInterpretation.YBR_FULL_422.toString());
			//setPhotometricInterpretation();
		else
			objImagePixelModule.getImagePixelMacro().setPhotometricInterpretation(EnumPhotometricInterpretation.MONOCHROME2.toString());

		objImagePixelModule.getImagePixelMacro().setSamplesPerPixel(getSamplesPerPixel(samplesPerPixel).getValue());

		objImagePixelModule.getImagePixelMacro().setBitsAllocated(getBitsAllocated(bitsAllocated).getValue());
		objImagePixelModule.getImagePixelMacro().setBitsStored(getBitsStored(bitsAllocated).getValue());
		objImagePixelModule.getImagePixelMacro().setHighBit(getHighBit(bitsAllocated-1).getValue());
		objImagePixelModule.getImagePixelMacro().setPixelRepresentation(EnumPixelRepresentation.ZERO.getValue());


		objImagePixelModule.getImagePixelMacro().setColumns((short)jpegImage.getWidth());
		objImagePixelModule.getImagePixelMacro().setRows(((short)jpegImage.getHeight()));

		FileInputStream objFileInputStream = new FileInputStream(jpgSource);
		byte[] objByte = new byte[objFileInputStream.available()];
		objFileInputStream.read(objByte);
		objFileInputStream.close();

		/*
		 * Set Pixel data in Image Pixel Module. 
		 */
		ISingleCollection<byte[]> objSingleCollection = new SingleCollection<byte[]>();
		objSingleCollection.add(objByte);
		objImagePixelModule.getImagePixelMacro().setPixelData(objSingleCollection, EnumPixelDataVRType.OB,true);
	}

	/*
	 * Gets the Enum value For Samples Per Pixel.
	 */
	private EnumSamplesPerPixel getSamplesPerPixel(int samplesPerPixel)
	{
		switch (samplesPerPixel ) 
		{
		case 4:
			return EnumSamplesPerPixel.FOUR;
		case 1:
			return EnumSamplesPerPixel.ONE;
		case 3:
			return EnumSamplesPerPixel.THREE;
		}
		return null;
	}

	/*
	 * Gets the Enum value for Bits Allocated.
	 */
	private EnumBitsAllocated getBitsAllocated(int bitsAllocated)
	{
		switch (bitsAllocated) 
		{
		case 8:
			return EnumBitsAllocated.EIGHT;
		case 1:
			return EnumBitsAllocated.ONE;
		case 16:
			return EnumBitsAllocated.SIXTEEN;
		}
		return null;
	}

	/*
	 * Gets the Enum Value for Bits Stored.
	 */
	private EnumBitsStored getBitsStored(int bitsStored)
	{
		switch (bitsStored) 
		{
		case 8:
			return EnumBitsStored.EIGHT;
		case 11:
			return EnumBitsStored.ELEVEN;
		case 15:
			return EnumBitsStored.FIFTEEN;
		case 14:
			return EnumBitsStored.FOURTEEN;
		case 9:
			return EnumBitsStored.NINE;
		case 1:
			return EnumBitsStored.ONE;
		case 7:
			return EnumBitsStored.SEVEN;
		case 6:
			return EnumBitsStored.SIX;
		case 16:
			return EnumBitsStored.SIXTEEN;
		case 10:
			return EnumBitsStored.TEN;
		case 13:
			return EnumBitsStored.THIRTEEN;
		case 12:
			return EnumBitsStored.TWELVE;
		}
		return null;
	}

	/*
	 * Get the Enum Value for High Bit.
	 */
	private EnumHighBit getHighBit(int highBit)
	{
		switch(highBit)
		{
		case 8:
			return EnumHighBit.EIGHT;
		case 11:
			return EnumHighBit.ELEVEN;
		case 15:
			return EnumHighBit.FIFTEEN;
		case 14:
			return EnumHighBit.FOURTEEN;
		case 0:
			return EnumHighBit.ZERO;
		case 5:
			return EnumHighBit.FIVE;
		case 7:
			return EnumHighBit.SEVEN;
		case 6:
			return EnumHighBit.SIX;
		case 12:
			return EnumHighBit.TWELVE;
		case 13:
			return EnumHighBit.THIRTEEN;
		}
		return null;
	}

	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");

			JPEGToDICOMConvertor objTestJPEGToDICOM = new JPEGToDICOMConvertor();

			objDicomConfig.useTempStorage(false);
			objTestJPEGToDICOM.populateCTIOD();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
