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


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.CTImageModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.FrameOfReferenceModule;
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.ImagePlaneModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.PatientModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.SOPCommonModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.VOILUTModule;
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.EnumPlanarConfiguration;
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 class demonstrates to populate CT IOD and its modules manually using DicomModel.
 * Dicom Model contains classes of IOD and Modules. IOD classes contains getter methods for module
 * and Module contains getter and setter methods of attributes of that particular module.
 * User can use this getter and setter methods to populate a module of IOD.
 * The image data to populate Image Pixel Module is parsed from BMP file in getImageData function.
 * These files are available in BMPImages Folder in SampleDCM-J.zip in Parser Serializer Test cases. This data set is then serialized at path specified.
 * This test code shows bmp to dicom conversion using SDK for DICOM.
 */
public class BMPToDICOMConvertor 
{
	/**
	 * 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();

		/*
		 * 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();
		String[] strImageType = new String[3];
		strImageType[0]="DERIVED";
		strImageType[1]="SECONDARY";
		strImageType[2]="3D";
		objGeneralImageModule.setImageType(strImageType);
		objGeneralImageModule.setContentDate("1993.04.30");
		objGeneralImageModule.setContentTime("112724");
		objGeneralImageModule.setInstanceNumber("1");

		//Populating SOPCommonModule
		SOPCommonModule objSOPCommonModule = objCTIOD.getSOPCommonModule();
		objSOPCommonModule.setSOPClassUID("1.2.840.10008.5.1.4.1.1.7");
		objSOPCommonModule.setSOPInstanceUID("1.2.840.113619.2.1.2411.1031152382.365.1.736169244");

		//Populating GeneralStudyModule
		GeneralStudyModule objGeneralStudyModule = objCTIOD.getGeneralStudyModule();
		objGeneralStudyModule.setStudyDate("1993.04.30");
		objGeneralStudyModule.setStudyTime("112724");
		objGeneralStudyModule.setReferringPhysicianName("Anonymized");
		objGeneralStudyModule.setStudyDescription("RT ANKLE");
		String[] strNameOfPhysicianReadingStudy = new String[1];
		strNameOfPhysicianReadingStudy[0] = "Anonymized";
		objGeneralStudyModule.setNameOfPhysicianReadingStudy(strNameOfPhysicianReadingStudy);
		objGeneralStudyModule.setStudyInstanceUID("1.2.840.113619.2.1.1.322987881.621.736170080.681");
		objGeneralStudyModule.setStudyID("H.I.A. BEGIN");
		objGeneralStudyModule.setAccessionNumber("H.I.A. BEGIN");

		//Populating GeneralSeriesModule
		GeneralSeriesModule objGeneralSeriesModule = objCTIOD.getGeneralSeriesModule();
		objGeneralSeriesModule.setSeriesDate("1993.04.30");
		objGeneralSeriesModule.setSeriesTime("112724");
		objGeneralSeriesModule.setModality(EnumModality.COMPUTED_TOMOGRAPHY);
		String[] strOperatorNames = new String[1];
		strOperatorNames[0] = "Anonymized";
		objGeneralSeriesModule.setOperatorNames(strOperatorNames);
		objGeneralSeriesModule.setSeriesInstanceUID("1.2.840.113619.2.1.2411.1031152382.365.736169244");
		objGeneralSeriesModule.setSeriesNumber("365");

		//Populating GeneralEquipmentModule
		GeneralEquipmentModule objGeneralEquipmentModule = objCTIOD.getGeneralEquipmentModule();
		objGeneralEquipmentModule.setManufacturer("GE MEDICAL SYSTEMS");
		objGeneralEquipmentModule.setInstitutionName("JFK IMAGING CENTER");
		objGeneralEquipmentModule.setStationName("CT01OC0");
		objGeneralEquipmentModule.setManufacturerModelName("GENESIS_ZEUS");
		String[] strSoftwareVersions = new String[1];
		strSoftwareVersions[0] = "03";
		objGeneralEquipmentModule.setSoftwareVersions(strSoftwareVersions);
		objGeneralEquipmentModule.setPixelPaddingValue((short)0);

		//Populating PatientModule
		PatientModule objPatientModule = objCTIOD.getPatientModule();
		objPatientModule.setPatientName("Anonymized");
		objPatientModule.setPatientID("VB20A");
		objPatientModule.setPatientBirthDate("19930822");
		objPatientModule.setPatientSex("F");

		//Populating ImagePixelModule
		ImagePixelModule objImagePixelModule = objCTIOD.getImagePixelModule();
		objImagePixelModule.getImagePixelMacro().setPhotometricInterpretation(EnumPhotometricInterpretation.RGB.toString());
		objImagePixelModule.getImagePixelMacro().setBitsAllocated(EnumBitsAllocated.EIGHT.getValue());
		objImagePixelModule.getImagePixelMacro().setBitsStored(EnumBitsStored.EIGHT.getValue());
		objImagePixelModule.getImagePixelMacro().setHighBit(EnumHighBit.SEVEN.getValue());
		objImagePixelModule.getImagePixelMacro().setPixelRepresentation(EnumPixelRepresentation.ZERO.getValue());
		getImageData(objImagePixelModule);

		//Populating VOILUTModule
		VOILUTModule objVOILUTModule = objCTIOD.getVOILUTModule();
		String[] strWindowCenter = new String[1];
		strWindowCenter[0] = "1024";
		objVOILUTModule.getVOILUTMacro().setWindowCenter(strWindowCenter);
		String[] strWindowWidth = new String[1];
		strWindowWidth[0] = "4095";
		objVOILUTModule.getVOILUTMacro().setWindowWidth(strWindowWidth);

		//Populating CTImageModule
		CTImageModule objCTImageModule = objCTIOD.getCTImageModule();
		objCTImageModule.setRescaleIntercept("-1024");
		objCTImageModule.setRescaleScope("1");

		//Populating FrameOfReferenceModule
		FrameOfReferenceModule objFrameOfReferenceModule =objCTIOD.getFrameOfReferenceModule();
		objFrameOfReferenceModule.setFrameOfReferenceUID("1.21.840.10008.1.2");
		objFrameOfReferenceModule.setPositionReferenceIndicator("VB20A");

		//Populating ImagePlaneModule
		ImagePlaneModule objImagePlaneModule = objCTIOD.getImagePlaneModule();
		String[] strPixelSpacing = new String[1];
		strPixelSpacing[0]= "1.1";
		objImagePlaneModule.setPixelSpacing(strPixelSpacing);
		String[] strImageOrientationPatient = new String[1];
		strImageOrientationPatient[0]= "1.1";
		objImagePlaneModule.setImageOrientationPatient(strImageOrientationPatient);
		String[] strImagePositionPatient = new String[1];
		strImagePositionPatient[0]= "1.1";
		objImagePlaneModule.setImagePositionPatient(strImagePositionPatient);
		objImagePlaneModule.setSliceThickness("1.1");
		objCTImageModule.setKVP("1.1");
		objCTImageModule.setAcquisitionNumber("309");

		/*
		 * 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();
		}
	}

	public int iWidth ;
	public int iHeight;

	/**
	 * This function populated the various attributes of Image Pixel Module from the bmp file provided.
	 * @param objImagePixelModule instance of Image Pixel Module to be populated.
	 * @throws IOException throws if IOException occurs.
	 */
	private void getImageData(ImagePixelModule objImagePixelModule) throws IOException
	{
		/*
		 * path of BMP File to get the image Data. 
		 * These images are provided in SampleDCM-J folder.
		 */
		BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
		System.out.println("Enter the BMP File from where to read the Image Data");
		String strFilePath = b_reader.readLine();
		FileInputStream fs=new FileInputStream(strFilePath);

		//14 byte header length of Bmp File.
		int iFileHeaderlen=14;  

		//read 14 byte BMP File Header.
		byte arrBMPFileHeader[]=new byte[iFileHeaderlen];
		fs.read(arrBMPFileHeader,0,iFileHeaderlen);

		//read 40-byte BMP Info Header.
		int iInfoLen=40; 
		byte arrBMPFileInfo[]=new byte[iInfoLen];
		fs.read(arrBMPFileInfo,0,iInfoLen);

		//Read the width of bmp file  file.
		iWidth = (((int)arrBMPFileInfo[7]&0xff)<<24)
		| (((int)arrBMPFileInfo[6]&0xff)<<16)
		| (((int)arrBMPFileInfo[5]&0xff)<<8)
		| (int)arrBMPFileInfo[4]&0xff;

		//Read the height of bitmap  file.
		iHeight = (((int)arrBMPFileInfo[11]&0xff)<<24)
		| (((int)arrBMPFileInfo[10]&0xff)<<16)
		| (((int)arrBMPFileInfo[9]&0xff)<<8)
		| (int)arrBMPFileInfo[8]&0xff;
		System.out.println("Height is :"+iHeight);

		objImagePixelModule.getImagePixelMacro().setPlanarConfiguration(EnumPlanarConfiguration.PLANAR_VALUE_ZERO.getValue());
		objImagePixelModule.getImagePixelMacro().setSamplesPerPixel(EnumSamplesPerPixel.THREE.getValue());

		//Specifies the number of bits per pixel.
		int iBitcount = (((int)arrBMPFileInfo[15]&0xff)<<8) | (int)arrBMPFileInfo[14]&0xff;
		System.out.println("BitCount is :"+iBitcount);

		//Image Size.
		int iSizeImage = (((int)arrBMPFileInfo[23]&0xff)<<24)
		| (((int)arrBMPFileInfo[22]&0xff)<<16)
		| (((int)arrBMPFileInfo[21]&0xff)<<8)
		| (int)arrBMPFileInfo[20]&0xff;
		System.out.println("SizeImage is :"+ iSizeImage);

		byte brgb[] = null;
		int iPad = 0;
		if (iBitcount==24)
		{
			/*
			 * Read Pixel data
			 */
			iPad = (iSizeImage / iHeight) - iWidth * 3;
			brgb = new byte [(iWidth + iPad) * 3 * (iHeight)];
			fs.read (brgb, 0, (iWidth + iPad) * 3 * iHeight);
		}

		objImagePixelModule.getImagePixelMacro().setColumns((short)(iWidth + iPad));
		objImagePixelModule.getImagePixelMacro().setRows((short)iHeight);

		fs.close();

		//reading image from backwards 
		iWidth = iWidth +iPad;
		byte[] arrfliped = new byte[brgb.length];
		int startPos=0;
		for(int i=0; i<iHeight;i++)
		{
			int startSrcPos = (iWidth*3)*((iHeight-1)-i);
			System.arraycopy(brgb,startSrcPos, arrfliped, startPos, iWidth*3);
			startPos = startPos + iWidth*3;
		}

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

	public static void main(String args[]) throws IOException
	{
		/*
		 * Create Instance of TestCaseCTIOD.
		 */
		BMPToDICOMConvertor objTestCaseCTIOD = new BMPToDICOMConvertor();

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

		//Set useTempStorage as false. If temp storage is not in use then
		//image data is in memory.
		objDicomConfig.useTempStorage(false);
		objTestCaseCTIOD.populateCTIOD();
	}
}
