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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Pattern;


import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.ExplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.Item;
import cdac.medinfo.sdk.dcm30_04.baselibs.PurposeOfReferenceCodeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomFileHeader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicomparserserializers.DicomParser;
import cdac.medinfo.sdk.dcm30_04.dicomparserserializers.DicomSerializer;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataElementException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ParseException;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumImplOpsStatus;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.SourceException;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IDataSource;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IQueryModel;
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.ICollectionIterator;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * This class provides functionality to query the data base and find the resultant matches.
 */
public class IFLRDataSourceImpl  extends Item implements IDataSource
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/** The obj db agent. */
	IFLR_DBAgent objDBAgent = null;

	/**
	 * Instantiates a new data source implementation.
	 * @param strConnectionString the string connection string.
	 * @param strDriverName the string driver name.
	 * @throws SQLException the SQL exception.
	 * @throws IllegalAccessException the illegal access exception.
	 * @throws InstantiationException the instantiation exception.
	 * @throws ClassNotFoundException the class not found exception.
	 */
	public IFLRDataSourceImpl(String strConnectionString, String strDriverName) throws SQLException, IllegalAccessException,InstantiationException,ClassNotFoundException
	{
		objDBAgent = IFLR_DBAgent.createInstance(strConnectionString,strDriverName);
	}

	/**
	 * Depending on the keys in the IDataSet it finds the matching DataSets and returns status.
	 * According to the matched DataSets populate the collection taken as out parameter.
	 * @param objIDataSet The data set contain identifiers.
	 * @param objRstDataCollection the matched data set collection.
	 * @return short - shows status value which will be used in generation of response.
	 * 					Refer EnumImplOpsStatus for supported response status values.
	 */
	public short find(DicomMessage objDicomMessage, ISingleCollection<IDataSet> objRstDataCollection) 
	{
		try
		{
			IFLR_QueryModel objDCMQuery = new IFLR_QueryModel(); 
			IFLR_QueryModel objRstQueryModel = new IFLR_QueryModel();
			IDataSet objIDataSet = objDicomMessage.getDataSet();
			objDCMQuery.decode(objIDataSet);

			if(objDBAgent.find(objDCMQuery, objRstQueryModel))
			{
				if(objRstQueryModel.encode(objIDataSet.getTransferSyntax(), objRstDataCollection))
					return EnumImplOpsStatus.SUCCESS.getValue();
			}
		}
		catch(SQLException sqle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sqle.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "SQLException", new Locale(DicomConfig.createInstance().getLocale())), sqle);
		}
		catch(IOException sqle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sqle.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "IOException", new Locale(DicomConfig.createInstance().getLocale())), sqle);
		}
		catch (InvalidDataElementException ide)
		{
			if (DicomConfig.createInstance().isLoggingOn())
			{
			    DicomLogger objDicomLogger = DicomLogger.getLogger();
			    objDicomLogger.log(ide.getMessage());
			}
		}
		return EnumImplOpsStatus.FAILURE.getValue();
	}

	
	/**
	 * Depending on the keys in the IDataSet it finds the matching DataSets and returns status.
	 * According to the matched DataSets populate the collection taken as out parameter.
	 * @param objIDataSet The data set contains identifiers.
	 * @param objRstDataSetCollection the obj rst data set collection.
	 * @return short - shows status value which will be used in generation of response.
	 * 					Refer EnumImplOpsStatus for supported response status values.
	 */
	public short retrieve(DicomMessage objDicomMessage, ISingleCollection<IDataSet> objRstDataSetCollection) 

	{

		IDataSet objIDataSetMatch =null;
		IDataSet objIDataSetMatchforExtract =null;
		try
		{
			IDataSet objIDataSet = objDicomMessage.getDataSet();
			IFLR_QueryModel objDCMQuery = new IFLR_QueryModel(); 
			objDCMQuery.decode(objIDataSet);

			ISingleCollection<String> filePathCollection = objDBAgent.retrive(objDCMQuery);
			ICollectionIterator<String> objFileIterator = filePathCollection.iterator();
			ICollectionIterator<String> objFileIterator2 = filePathCollection.iterator();

			DicomParser objDicomParser = null ;
			DicomParser objDicomParserforExtract = null ;
			
			while(objFileIterator.hasNext())
			{		
				objDicomParser = new DicomParser();
				String strFilePath = objFileIterator.next();
				objIDataSetMatch = objDicomParser.parseAsPart10File(strFilePath, true);				
				objRstDataSetCollection.add(objIDataSetMatch);
			}
			
			while(objFileIterator2.hasNext())
			{		
				objDicomParserforExtract = new DicomParser();
				String strFilePath = objFileIterator2.next();
				objIDataSetMatchforExtract = objDicomParserforExtract.parseAsPart10File(strFilePath, true);
				String strRetrieveLevel=objDicomMessage.getDataSet().getDataForTag(0x0008,0x0052).getValue().toString();
				if(strRetrieveLevel.equalsIgnoreCase("Image"))			
					extractforIMAGE(objIDataSetMatchforExtract,objDicomParserforExtract);
				else if(strRetrieveLevel.equalsIgnoreCase("Frame"))
				{
					
					if(objDicomMessage.getDataSet().getDataForTag(0x0008,0x1161)!=null)
					{
						int[] str=(int[]) objDicomMessage.getDataSet().getDataForTag(0x0008,0x1161).getDicomValue().getValue();
						for(int i=0;i<str.length;i++)
						System.out.println("Type of SFL:"+str[i]);
						System.out.println("Type of Retrievel:"+objDicomMessage.getDataSet().getDataForTag(0x0008,0x0052).getDicomValue().toString()+" with Simple Frame List.");
						extractforSFL(objIDataSetMatchforExtract,objDicomParserforExtract,str);
					}
					else if(objDicomMessage.getDataSet().getDataForTag(0x0008,0x1162)!=null)
					{
						int[] str=(int[]) objDicomMessage.getDataSet().getDataForTag(0x0008,0x1162).getDicomValue().getValue();
						for(int i=0;i<str.length;i++)
						System.out.println("Type of CFL:"+str[i]);
						System.out.println("Type of Retrievel:"+objDicomMessage.getDataSet().getDataForTag(0x0008,0x0052).getDicomValue().toString()+" with Calculated Frame List.");
						extractforCFL(objIDataSetMatchforExtract,objDicomParserforExtract,str);
					}
					else if(objDicomMessage.getDataSet().getDataForTag(0x0008,0x1163)!=null)
					{
						double[] time= (double[]) objDicomMessage.getDataSet().getDataForTag(0x0008,0x1163).getDicomValue().getValue();
						System.out.println("Type of Retrievel :"+objDicomMessage.getDataSet().getDataForTag(0x0008,0x0052).getDicomValue().toString()+" with Time Range.");
						extractforTIME(objIDataSetMatchforExtract,objDicomParserforExtract,time);
					}
					else
						extractforIMAGE(objIDataSetMatchforExtract,objDicomParserforExtract);
					
				}
			}
			
			
			if(filePathCollection.size() != 0)
				return EnumImplOpsStatus.SUCCESS.getValue();
		}
		catch(ParseException pe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();	
				objDicomLogger.log(pe.getMessage());
			}
			return EnumImplOpsStatus.FAILURE_INVALID_ATTRIBUTE_VALUE.getValue();
		}
		catch(SQLException sqle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sqle.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "SQLException", new Locale(DicomConfig.createInstance().getLocale())), sqle);
		}
		catch(IOException sqle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sqle.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "IOException", new Locale(DicomConfig.createInstance().getLocale())), sqle);
		}
		catch (InvalidDataElementException ide)
		{
			if (DicomConfig.createInstance().isLoggingOn())
			{
			    DicomLogger objDicomLogger = DicomLogger.getLogger();
			    objDicomLogger.log(ide.getMessage());
			}
		}
		return EnumImplOpsStatus.FAILURE.getValue();
	}

	

	/**
	 * Depending on the keys in the DCMQuery model it finds the matching DataSets and returns status.
	 * According to the matched sets populates the collection of DCMResultSet taken as out parameter.
	 * @param objRstQueryModel the resultant query model containing the matched attributes.
	 * @param objQueryModel the obj query model.
	 * @return short - shows status value which will be used in generation of response.
	 * 					Refer EnumImplOpsStatus for supported response status values.
	 */
	public short find(IQueryModel objQueryModel, IQueryModel objRstQueryModel)
	{
		try
		{
			if(objDBAgent.find(objQueryModel, objRstQueryModel))
				return EnumImplOpsStatus.SUCCESS.getValue();
		}
		catch(SQLException sqle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sqle);
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "SQLException", new Locale(DicomConfig.createInstance().getLocale())), sqle);
		}
		return EnumImplOpsStatus.FAILURE.getValue();
	}

	@Override
	public short retrieve(IQueryModel arg0, IQueryModel arg1) 
	{
		// TODO Auto-generated method stub
		return EnumImplOpsStatus.FAILURE.getValue();
	}
	
	private String createSOPInstanceUID(String strAffectedSOPClassUID)
	{
		String[] parts = strAffectedSOPClassUID.split("\\.");
		String strSOPInstanceUID=parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]+"."+((new Date()).getTime());

		return strSOPInstanceUID;
	}

	/**
	 * Serializes the given DataSet with file Header if given, else appends default file header.
	 * @param objIDataSet object of DataSet to be serialized.
	 * @param objDicomFileHeader object of Dicom File header. 
	 */
	public void serialize(IDataSet objIDataSet, IDicomFileHeader objDicomFileHeader,String newSOPInstanceUID,String strFilePath) throws IOException
	{
		/*
		 * Creates instance of Dicom Serializer.
		 */
		DicomSerializer objDicomSerializer = new DicomSerializer();
		String filepath=strFilePath+"/"+newSOPInstanceUID+".dcm";

		/*
		 * 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 default 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(filepath, objIDataSet, objDicomFileHeader,true);
	}
	/**
	 * This function gets the sequence belonging to group no and element number specified.
	 */
	private IDataSet getSQ(int GroupNo,int ElementNo , ITransferSyntax objTS,IDictionaryReader objDictionaryReader, IDataSet objnewIDataSet)
	{
		PurposeOfReferenceCodeSequence objPurposeOfReferenceCodeSequence = null;
		IDataElement objIDataElement =  getDataForTag(0x0040, 0xA170);
		DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
		int iVRTransferSyntax = objTS.getVRTransferSyntax();
		objIDataElement = null;
		objPurposeOfReferenceCodeSequence = (PurposeOfReferenceCodeSequence)objDicomV3Factory.createSequence(0x0040, 0xA170, objTS, objDictionaryReader);

		if(iVRTransferSyntax == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA170, objPurposeOfReferenceCodeSequence.getValue(),objDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA170, DicomConstants.DCM_DT_SQ, objPurposeOfReferenceCodeSequence.getValue());
		
		objIDataElement.setTransferSyntax(objTS);
		objnewIDataSet.addDataElement(objIDataElement);

		
		IItem objPurposeOfReferenceCodeSequenceItem=objPurposeOfReferenceCodeSequence.getNewItem();
		
		//Set the Code Value
		IDataElement objCodeValueIDataElement = null;
		if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objCodeValueIDataElement = new ImplicitDE(0x0008, 0x0100, "109105" ,objDictionaryReader);
		else
			objCodeValueIDataElement = new ExplicitDE(0x0008, 0x0100,DicomConstants.DCM_DT_SH, "109105" );
		objPurposeOfReferenceCodeSequenceItem.addDataElement(objCodeValueIDataElement);
		
		
		//Set the Coding SchemeDesignator
		IDataElement objCodingSchemeDesignatorIDataElement = null;
		if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objCodingSchemeDesignatorIDataElement = new ImplicitDE(0x0008, 0x0102, "DCM" ,objDictionaryReader);
		else			objCodingSchemeDesignatorIDataElement = new ExplicitDE(0x0008, 0x0102,DicomConstants.DCM_DT_SH, "DCM" );

		objPurposeOfReferenceCodeSequenceItem.addDataElement(objCodingSchemeDesignatorIDataElement);
		
		
		//Set the Code Meaning
		IDataElement objCodeMeaningIDataElement = null;
		if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objCodeMeaningIDataElement = new ImplicitDE(0x0008, 0x0104, "Frame Extracting Equipment" ,objDictionaryReader);
		else
			objCodeMeaningIDataElement = new ExplicitDE(0x0008, 0x0104,DicomConstants.DCM_DT_LO, "Frame Extracting Equipment" );
		objPurposeOfReferenceCodeSequenceItem.addDataElement(objCodeMeaningIDataElement);
		
		objPurposeOfReferenceCodeSequence.addItem(objPurposeOfReferenceCodeSequenceItem);		
		return objnewIDataSet;
	}
	
	/**
	 * Displays the DataElements of given Collection Iterator.
	 */
	private void display(ICollectionIterator<IDataElement> objIterator)
	{
		int iGroupNumber = 0;
		int iElementNumber = 0;
		String value;
		System.out.println("Group Number"+"\t\t"+"Element Number"+"\t\t"+"Value");
		while(objIterator.hasNext())
		{
			IDataElement objIDataElement = objIterator.next();
			iGroupNumber = objIDataElement.getTag().getGroupNumber();
			iElementNumber = objIDataElement.getTag().getElementNumber();
			value= objIDataElement.getDicomValue().toString();
			System.out.println( Integer.toHexString(iGroupNumber) +"\t\t"+ Integer.toHexString(iElementNumber)+"\t\t"+value);
		}
	}
	
	
	/**
	 * Extracts every Frame from multi-frame image for Retrieval level-IMAGE
	 */
	@SuppressWarnings("unchecked")
	private void extractforIMAGE(IDataSet objIDataSetMatch,DicomParser objDicomParser)
	{
		IDictionaryReader objDictionaryReader = objIDataSetMatch.getDictionaryReader();
		IDicomFileHeader objDicomFileHeader = null;
		ITransferSyntax objTS = objIDataSetMatch.getTransferSyntax();
		String strFilePath = null;
		
		/*
		 * path where to serialize the Dicom File.
		 */
		strFilePath="C:/temp";
		
		//User can  provide the storage location as well, just un-comment the below code.
		/*	BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
		System.out.println("Enter the complete path where to save the Serialized File");
		try 
		{
			strFilePath = b_reader.readLine();
			
		}
		catch (IOException e1) 
		{
			e1.printStackTrace();
		}*/
		try 
		{
			objDicomFileHeader = objDicomParser.getFileHeader();
		}
		catch (IOException e1)
		{
			e1.printStackTrace();
		}
		System.out.println("DIcom Header: ");
		display(objDicomFileHeader.iterator());
		System.out.println("DIcom Dataset: ");
		display(objIDataSetMatch.iterator());
		
		
		//Get the pixel data value from the main image
		Object objValue = objIDataSetMatch.getValue(0x7FE0,0x0010);
		if((objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getValueLength())==-1)
		{
			ISingleCollection<byte[]> objPixelData=(ISingleCollection<byte[]>)objValue;
			int length=objPixelData.size();
			System.out.println(length);
			for(int i=0;i<length;i++)
			{
				byte[] a=objPixelData.elementAt(i);						
				String oldSOPInstanceValue = objIDataSetMatch.getValue(0x0008, 0x0018).toString();
				int VRtype=objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getDicomValue().getIVRType();
				
				//remove Pixel Data Tag				
				ITag objITag = new Tag(0x7FE0, 0x0010);	
				objIDataSetMatch.removeDataElement(objITag);
				//remove Number of Frames tag		
				objITag=new Tag(0x0028, 0x0008);
				objIDataSetMatch.removeDataElement(objITag);
				//remove SOP Instance Tag tag		
				objITag=new Tag(0x0008, 0x0018);
				objIDataSetMatch.removeDataElement(objITag);	
				
				
				IDataSet objnewIDataSet = null;
				objnewIDataSet=objIDataSetMatch;
				 byte[] image = a;
					 objPixelData.add(image);
					 ISingleCollection<byte[]> objSingleCollection = new SingleCollection<byte[]>();
					 objSingleCollection.add(image); 
					 
					if(VRtype==20290)
					{		 
					 //Set the pixel data value from the main image
					 IDataElement objIPixelDataElement = null;
					 if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						 objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
					 else
						 objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OB, objSingleCollection);
					 objnewIDataSet.addDataElement(objIPixelDataElement);
					}
					if(VRtype==20311)
					{
						//Set the pixel data value from the main image
						IDataElement objIPixelDataElement = null;
						if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
							objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
						else
							objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OW, objSingleCollection);
						objnewIDataSet.addDataElement(objIPixelDataElement);
					}
		
				
				//Set the Number of Frames value
				IDataElement objNumberofFramesIDataElement = null;
				if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
					objNumberofFramesIDataElement = new ImplicitDE(0x0028, 0x0008, "1" ,objDictionaryReader);
				else
					objNumberofFramesIDataElement = new ExplicitDE(0x0028, 0x0008,DicomConstants.DCM_DT_IS, "1" );
		
				objnewIDataSet.addDataElement(objNumberofFramesIDataElement);
				
				//set the SOP Instance UID
				String newSOPInstanceUID=createSOPInstanceUID(oldSOPInstanceValue);
				IDataElement objSOPInstanceUIDIDataElement = null;
				if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
					objSOPInstanceUIDIDataElement = new ImplicitDE(0x0008, 0x0018, newSOPInstanceUID,objDictionaryReader);
				else
					objSOPInstanceUIDIDataElement = new ExplicitDE(0x0008, 0x0018,DicomConstants.DCM_DT_UI, newSOPInstanceUID);
		
				objnewIDataSet.addDataElement(objSOPInstanceUIDIDataElement);
				
				//add sequence (0040,A170)
				IDataSet objfinalIDataSet = getSQ(0x0040,0xA170, objTS,objDictionaryReader,objnewIDataSet);
				try 
				{
					serialize(objfinalIDataSet,objDicomFileHeader,newSOPInstanceUID,strFilePath);
				} 
				catch (IOException e) 
				{
					e.printStackTrace();
				}
			}
		}
		else
		{		
			ISingleCollection<byte[]> objPixelData=(ISingleCollection<byte[]>)objValue;
			String oldSOPInstanceValue = objIDataSetMatch.getValue(0x0008, 0x0018).toString();
			
			//remove Pixel Data Tag
			ITag objITag = new Tag(0x7FE0, 0x0010);
			int VRtype=objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getDicomValue().getIVRType();
			objIDataSetMatch.removeDataElement(objITag);

			//remove Number of Frames tag		
			objITag=new Tag(0x0028, 0x0008);
			objIDataSetMatch.removeDataElement(objITag);
			
			//remove SOP Instance Tag tag		
			objITag=new Tag(0x0008, 0x0018);
			objIDataSetMatch.removeDataElement(objITag);

			IDataSet objnewIDataSet = null;
			objnewIDataSet=objIDataSetMatch;	

			short rows = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0010).getValue();
			short columns = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0011).getValue();
			short samplePerPixel =(short) objIDataSetMatch.getDataForTag(0x0028, 0x0002).getValue();
			short bitsAllocated = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0100).getValue();
			int frameSize = (rows * columns * samplePerPixel * bitsAllocated) / 8;
			int from = 0;
			int to = frameSize;
			byte[] yourBytes=objPixelData.get(0);		
			int framearray;
				framearray=(yourBytes.length/frameSize);

			for (int frame = 0; frame < framearray; frame++) 
			{
				System.out.println("****Frame : "+frame+"******");
				 byte[] image = Arrays.copyOfRange(yourBytes, from, to);
				 objPixelData.add(image);
				 ISingleCollection<byte[]> objSingleCollection = new SingleCollection<byte[]>();
				 objSingleCollection.add(image);
				if(VRtype==20290)
				{		 
				 //Set the pixel data value from the main image
				IDataElement objIPixelDataElement = null;
				 if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
					 objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
				 else
					 objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OB, objSingleCollection);
				 objnewIDataSet.addDataElement(objIPixelDataElement);
				}

				if(VRtype==20311)
				{
				//Set the pixel data value from the main image
					IDataElement objIPixelDataElement = null;
					if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
					else
						objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OW, objSingleCollection);
					objnewIDataSet.addDataElement(objIPixelDataElement);
				}			

			//Set the Number of Frames value
			IDataElement objNumberofFramesIDataElement = null;
			if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
				objNumberofFramesIDataElement = new ImplicitDE(0x0028, 0x0008, "1" ,objDictionaryReader);
			else
				objNumberofFramesIDataElement = new ExplicitDE(0x0028, 0x0008,DicomConstants.DCM_DT_IS, "1" );
			objnewIDataSet.addDataElement(objNumberofFramesIDataElement);

			//set the SOP Instance UID
			String newSOPInstanceUID=createSOPInstanceUID(oldSOPInstanceValue);
			IDataElement objSOPInstanceUIDIDataElement = null;
			if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
				objSOPInstanceUIDIDataElement = new ImplicitDE(0x0008, 0x0018, newSOPInstanceUID,objDictionaryReader);
			else
				objSOPInstanceUIDIDataElement = new ExplicitDE(0x0008, 0x0018,DicomConstants.DCM_DT_UI, newSOPInstanceUID);
			objnewIDataSet.addDataElement(objSOPInstanceUIDIDataElement);	


			//add sequence (0040,A170)
			IDataSet objfinalIDataSet = getSQ(0x0040,0xA170, objTS,objDictionaryReader,objnewIDataSet);

			//serialize the files
			try 
			{
				serialize(objfinalIDataSet,objDicomFileHeader,newSOPInstanceUID,strFilePath);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		      from += frameSize;
		      to += frameSize;

			}
		}	
	}
	
	
	/**
	 * Extracts every Frame from multi-frame image for Retrieval level-FRAME and Simple Frame List
	 */
	@SuppressWarnings("unchecked")
	private void extractforSFL(IDataSet objIDataSetMatch,DicomParser objDicomParser,int SFL[])
	{
		IDictionaryReader objDictionaryReader = objIDataSetMatch.getDictionaryReader();
		IDicomFileHeader objDicomFileHeader = null;
		ITransferSyntax objTS = objIDataSetMatch.getTransferSyntax();
		String strFilePath = null;
		/*
		 * path where to serialize the Dicom File.
		 */
		BufferedReader b_reader =new BufferedReader( new InputStreamReader( System.in ) );
		System.out.println("Enter the complete path where to save the Frames");
		try 
		{
			strFilePath = b_reader.readLine();
			objDicomFileHeader = objDicomParser.getFileHeader();
		}
		catch (IOException e1) 
		{
			e1.printStackTrace();
		}
		System.out.println("DIcom Header: ");
		display(objDicomFileHeader.iterator());
		System.out.println("DIcom Dataset: ");
		display(objIDataSetMatch.iterator());
		
		
		//Get the pixel data value from the main image
		Object objValue = objIDataSetMatch.getValue(0x7FE0,0x0010);
		if((objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getValueLength())==-1)
		{
			ISingleCollection<byte[]> objPixelData=(ISingleCollection<byte[]>)objValue;
			int SFLlength=SFL.length;
			int length=objPixelData.size();
			for(int i=0;i<SFLlength;i++)
			{
				if(SFL[i]<=length&&SFL[i]>=1)
				{
					int SFLvalue=SFL[i];
					byte[] a=objPixelData.elementAt(SFLvalue-1);						
					String oldSOPInstanceValue = objIDataSetMatch.getValue(0x0008, 0x0018).toString();
					int VRtype=objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getDicomValue().getIVRType();
					
					//remove Pixel Data Tag				
					ITag objITag = new Tag(0x7FE0, 0x0010);	
					objIDataSetMatch.removeDataElement(objITag);
					//remove Number of Frames tag		
					objITag=new Tag(0x0028, 0x0008);
					objIDataSetMatch.removeDataElement(objITag);
					//remove SOP Instance Tag tag		
					objITag=new Tag(0x0008, 0x0018);
					objIDataSetMatch.removeDataElement(objITag);	
					
					
					IDataSet objnewIDataSet = null;
					objnewIDataSet=objIDataSetMatch;
					byte[] image = a;
					objPixelData.add(image);
					ISingleCollection<byte[]> objSingleCollection = new SingleCollection<byte[]>();
					 objSingleCollection.add(image); 
						 
					if(VRtype==20290)
					{		 
					 //Set the pixel data value from the main image
					 IDataElement objIPixelDataElement = null;
					 if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						 objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
					 else
						 objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OB, objSingleCollection);
					 objnewIDataSet.addDataElement(objIPixelDataElement);
					}
					if(VRtype==20311)
					{
						//Set the pixel data value from the main image
						IDataElement objIPixelDataElement = null;
						if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
							objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
						else
							objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OW, objSingleCollection);
						objnewIDataSet.addDataElement(objIPixelDataElement);
					}
						
					//Set the Number of Frames value
					IDataElement objNumberofFramesIDataElement = null;
					if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						objNumberofFramesIDataElement = new ImplicitDE(0x0028, 0x0008, "1" ,objDictionaryReader);
					else
						objNumberofFramesIDataElement = new ExplicitDE(0x0028, 0x0008,DicomConstants.DCM_DT_IS, "1" );
			
					objnewIDataSet.addDataElement(objNumberofFramesIDataElement);
					
					//set the SOP Instance UID
					String newSOPInstanceUID=createSOPInstanceUID(oldSOPInstanceValue);
					IDataElement objSOPInstanceUIDIDataElement = null;
					if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						objSOPInstanceUIDIDataElement = new ImplicitDE(0x0008, 0x0018, newSOPInstanceUID,objDictionaryReader);
					else
						objSOPInstanceUIDIDataElement = new ExplicitDE(0x0008, 0x0018,DicomConstants.DCM_DT_UI, newSOPInstanceUID);
			
					objnewIDataSet.addDataElement(objSOPInstanceUIDIDataElement);
					
					//add sequence (0040,A170)
					IDataSet objfinalIDataSet = getSQ(0x0040,0xA170, objTS,objDictionaryReader,objnewIDataSet);
					try 
					{
						serialize(objfinalIDataSet,objDicomFileHeader,newSOPInstanceUID,strFilePath);
					} 
					catch (IOException e) 
					{
						e.printStackTrace();
					}
				}
				else
				{
					System.out.println("Please enter the valid frame number");
				}

			}
		}
		else
		{		
			ISingleCollection<byte[]> objPixelData=(ISingleCollection<byte[]>)objValue;
			String oldSOPInstanceValue = objIDataSetMatch.getValue(0x0008, 0x0018).toString();
			
			//remove Pixel Data Tag
			ITag objITag = new Tag(0x7FE0, 0x0010);
			int VRtype=objIDataSetMatch.getDataForTag(0x7FE0, 0x0010).getDicomValue().getIVRType();
			objIDataSetMatch.removeDataElement(objITag);

			//remove Number of Frames tag		
			objITag=new Tag(0x0028, 0x0008);
			objIDataSetMatch.removeDataElement(objITag);
			
			//remove SOP Instance Tag tag		
			objITag=new Tag(0x0008, 0x0018);
			objIDataSetMatch.removeDataElement(objITag);

			IDataSet objnewIDataSet = null;
			objnewIDataSet=objIDataSetMatch;	

			short rows = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0010).getValue();
			short columns = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0011).getValue();
			short samplePerPixel =(short) objIDataSetMatch.getDataForTag(0x0028, 0x0002).getValue();
			short bitsAllocated = (short) objIDataSetMatch.getDataForTag(0x0028, 0x0100).getValue();
			int frameSize = (rows * columns * samplePerPixel * bitsAllocated) / 8;

			byte[] yourBytes=objPixelData.get(0);		
			int SFLlength=SFL.length;

			for (int frame = 0; frame < SFLlength; frame++) 
			{
				int SFLValue=SFL[frame];
				int from = frameSize*(SFLValue-1);
				int to = from+frameSize;
				
				System.out.println("****Frame : "+SFLValue+"******");
				 byte[] image = Arrays.copyOfRange(yourBytes, from, to);
				 objPixelData.add(image);
				 ISingleCollection<byte[]> objSingleCollection = new SingleCollection<byte[]>();
				 objSingleCollection.add(image);
				if(VRtype==20290)
				{		 
				 //Set the pixel data value from the main image
				IDataElement objIPixelDataElement = null;
				 if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
					 objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
				 else
					 objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OB, objSingleCollection);
				 objnewIDataSet.addDataElement(objIPixelDataElement);
				}

				if(VRtype==20311)
				{
				//Set the pixel data value from the main image
					IDataElement objIPixelDataElement = null;
					if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
						objIPixelDataElement = new ImplicitDE(0x7FE0,0x0010, objSingleCollection,objDictionaryReader);
					else
						objIPixelDataElement = new ExplicitDE(0x7FE0,0x0010,DicomConstants.DCM_DT_OW, objSingleCollection);
					objnewIDataSet.addDataElement(objIPixelDataElement);
				}			

			//Set the Number of Frames value
			IDataElement objNumberofFramesIDataElement = null;
			if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
				objNumberofFramesIDataElement = new ImplicitDE(0x0028, 0x0008, "1" ,objDictionaryReader);
			else
				objNumberofFramesIDataElement = new ExplicitDE(0x0028, 0x0008,DicomConstants.DCM_DT_IS, "1" );
			objnewIDataSet.addDataElement(objNumberofFramesIDataElement);

			//set the SOP Instance UID
			String newSOPInstanceUID=createSOPInstanceUID(oldSOPInstanceValue);
			IDataElement objSOPInstanceUIDIDataElement = null;
			if(objTS.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
				objSOPInstanceUIDIDataElement = new ImplicitDE(0x0008, 0x0018, newSOPInstanceUID,objDictionaryReader);
			else
				objSOPInstanceUIDIDataElement = new ExplicitDE(0x0008, 0x0018,DicomConstants.DCM_DT_UI, newSOPInstanceUID);
			objnewIDataSet.addDataElement(objSOPInstanceUIDIDataElement);	


			//add sequence (0040,A170)
			IDataSet objfinalIDataSet = getSQ(0x0040,0xA170, objTS,objDictionaryReader,objnewIDataSet);

			//serialize the files
			try 
			{
				serialize(objfinalIDataSet,objDicomFileHeader,newSOPInstanceUID,strFilePath);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
			}
		}
	}
	
	
	/**
	 * Extracts every Frame from multi-frame image for Retrieval level-FRAME and Calculated Frame List
	 */
	private void extractforCFL(IDataSet objIDataSetMatch,DicomParser objDicomParser,int CFL[])
	{		

		int CFLLength=CFL.length;
		String strnumberofframes= objIDataSetMatch.getDataForTag(0x0028, 0x0008).getDicomValue().getValue().toString();
		int numberofframes=Integer.parseInt(strnumberofframes);
		if(CFLLength%3!=0)
		{
			System.out.println("Please enter the proper values of Calculated Frame List");
		}
		else
		{
			ArrayList<Integer> StartCFL=new ArrayList<Integer>(); 
			ArrayList<Integer> LastCFL=new ArrayList<Integer>(); 
			ArrayList<Integer> MiddleCFL=new ArrayList<Integer>(); 
			int l=0;
			for(int j=0,i=1,k=2;j<CFLLength;j=j+3,i=i+3,k=k+3)
			{
				int value=CFL[j];
				StartCFL.add(value);
				LastCFL.add(CFL[i]);
				MiddleCFL.add(CFL[k]);
				l++;
			}
			
			//Refer to PDF-4, Page 309: Any value greater than the number of frames in the referenced SOP Instance as the second value shall denote the end of the set of frames in the referenced SOP Instance,
			//and may only occur in the last 3-tuple.
			int lastelementindex=l-1;
			int inputlastframe=LastCFL.get(lastelementindex);
			if(inputlastframe>numberofframes)
			{
				LastCFL.remove(lastelementindex);
				LastCFL.add(numberofframes);
			}
			ArrayList<Integer> FL=new ArrayList<Integer>(); 
			for(int i=0;i<l;i++)
			{
				FL.add(StartCFL.get(i));	
				int diff=MiddleCFL.get(i);
				int frame=StartCFL.get(i);
				for(int j=StartCFL.get(i)+diff;j<=LastCFL.get(i);j=j+diff)
				{
					frame=frame+diff;
					FL.add(frame);
				}				
			}
			int[]SFL=new int[FL.size()];
			for(int i=0;i<FL.size();i++)
			{
				SFL[i]=FL.get(i);
			}		
			extractforSFL( objIDataSetMatch, objDicomParser, SFL);

		}
	}
	
	/**
	 * Extracts every Frame from multi-frame image for Retrieval level-FRAME and Time Range
	 */
	private void extractforTIME(IDataSet objIDataSetMatch,DicomParser objDicomParser,double[] time)
	{
		Double dblfrom=time[0]*1000;
		Double dblto=time[1]*1000;
		int from=Integer.valueOf(dblfrom.intValue());
		int to=Integer.valueOf(dblto.intValue());
		
		System.out.println(" from: "+from+"  to: "+to);

		String strframetimevector= objIDataSetMatch.getDataForTag(0x0018, 0x1065).getDicomValue().toString();
		String arrframetimevector[]=strframetimevector.split(Pattern.quote("\\"));
		int i,sum=0;
		int frametimevector[]=new int[arrframetimevector.length]; 
		ArrayList<Integer> FL=new ArrayList<Integer>(); 
		for( i=0;i<arrframetimevector.length;i++)
		{
			sum=sum+Integer.parseInt(arrframetimevector[i]);
			frametimevector[i]=sum;
			System.out.println("frametimevector: "+frametimevector[i]);
			if(frametimevector[i]>=from && frametimevector[i]<=to)
			{
				
				FL.add(i);
				System.out.println("i value: "+i);
			}				
		}
		int SFL[]=new int[FL.size()];
		for(int j=0;j<FL.size();j++)
		{
			SFL[j]=FL.get(j)+1;
			System.out.println("SFL[]:"+SFL[j]);
		}
		extractforSFL( objIDataSetMatch, objDicomParser, SFL);
	}
}
