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

import java.io.File;
import java.util.Arrays;
import java.util.regex.PatternSyntaxException;

import cdac.medinfo.sdk.dcm30_04.baselibs.AT;
import cdac.medinfo.sdk.dcm30_04.baselibs.ExplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
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.enums.EnumMetaSOPClassUID;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPClassUIDs;
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.EnumFeatureList;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * The Class StandardMethods contains many utility methods.
 */
public class DataTypeConvertor  
{
	/**
	 * This method generates string array from a string.
	 * @param str String from which strict array is to be generated.
	 * @return String[] - array of string
	 */
	public static String[] stringToArray(String str)
	{
		if(str == null)
			return null;
		String[] stringArray = null;
		try
		{
			stringArray = str.split("\\\\");
		}
		catch(PatternSyntaxException ex)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ex.getMessage());
			}
			//ex.printStackTrace();
			stringArray =  new String[1];
			stringArray[0] = str;
		}
		return stringArray;
	}

	/**
	 * This method generates string from a string array
	 * @param str - String array from which string to be constructed.
	 * @return String - containing strings separated by "\\"
	 */
	public static String arrayToString(String[] str)
	{
		if (str == null)
			return null;
		String stringArray = "";
		for (int i=0;i<str.length;i++ )
		{
			if (str[i] != null && str[i] != "")
            {
                if(stringArray != "")
                    stringArray = stringArray + File.separator + str[i];
                else
                    stringArray = stringArray + str[i];
            }
		}
		return stringArray;
	}


	/**
	 * This method generates string from a int array
	 * @param iArray - int array from which string to be constructed
	 * @return  String - containing strings separated by "\\"
	 */
	public static String iArrayToString(int[] iArray)
	{
		String temp = Arrays.toString(iArray).replace(", ", "\\");
		return temp.substring(1, temp.length()-1);
	}

	/**
	 * This method generates int array from a string
	 * @param striArray - string containing "\\" as separator from which int array to be constructed 
	 * @return int[] integer array constructed from string specified
	 */
	public static int[] stringToiArray(String striArray)
	{
		if(null == striArray)
			return null;
		String temp[] =	striArray.split("\\\\");
		int[] iArray = new int[temp.length];
		int i = 0;
		for(String istring : temp)
		{
			iArray[i++] = Short.parseShort(istring);
		}
		return iArray;
	}




	/**
	 * This method generates string from a short array
	 * @param sArray short array from which string to be constructed
	 * @return String - containing strings separated by "\\"
	 */
	public static String sArrayToString(short[] sArray)
	{
		String temp = Arrays.toString(sArray).replace(", ", "\\");
		return temp.substring(1, temp.length()-1);
	}


	/**
	 * This method generates short array from a string
	 * @param strsArray string containing "\\" as separator from which short array to be constructed 
	 * @return  short[] short array constructed from string specified
	 */
	public static short[] stringTosArray(String strsArray)
	{
		if(null == strsArray)
			return null;
		String temp[] =	strsArray.split("\\\\");
		short[] sArray = new short[temp.length];
		int i = 0;
		for(String sstring : temp)
		{
			sArray[i++] = Short.parseShort(sstring);
		}
		return sArray;
	}



	/**
	 * This method generates string from a float array
	 * @param fArray float array from which string to be constructed
	 * @return String - containing strings separated by "\\"
	 */
	public static String fArrayToString(float[] fArray)
	{
		String temp = Arrays.toString(fArray).replace(", ", "\\");
		return temp.substring(1, temp.length()-1);
	}



	/**
	 * This method generates float array from a string
	 * @param strfArray string containing "\\" as separator from which float array to be constructed 
	 * @return  float[] float array constructed from string specified
	 */
	public static float[] stringTofArray(String strfArray)
	{
		if(null == strfArray)
			return null;
		String temp[] =	strfArray.split("\\\\");
		float[] fArray = new float[temp.length];
		int i = 0;
		for(String fstring : temp)
		{
			fArray[i++] =Float.parseFloat(fstring);
		}
		return fArray;
	}

	/**
	 * This method generates string from a double array
	 * @param dArray double array from which string to be constructed
	 * @return String - containing strings separated by "\\"
	 */
	public static String dArrayToString(double[] dArray)
	{
		String temp = Arrays.toString(dArray).replace(", ", "\\");
		return temp.substring(1, temp.length()-1);
	}


	/**
	 * This method generates double array from a string
	 * @param strdArray string containing "\\" as separator from which double array to be constructed 
	 * @return  double[] double array constructed from string specified
	 */
	public static double[] stringTodArray(String strdArray)
	{
		if(null == strdArray)
			return null;
		String temp[] =	strdArray.split("\\\\");
		double[] dArray = new double[temp.length];
		int i = 0;
		for(String dstring : temp)
		{
			dArray[i++] = Double.parseDouble(dstring);
		}
		return dArray;
	}

	/**
	 * This mehod constructs string for specified object 
	 * @param objValue instance of object
	 * @return string String value of Object
	 */
	@SuppressWarnings("unchecked")
	public static String objectToString(Object objValue)
	{
		String strDicomValueValue = null;
		if(objValue instanceof String)
		{
			strDicomValueValue =objValue.toString();
		}

		else if (objValue instanceof Integer)
		{
			strDicomValueValue = Integer.toString((Integer)objValue);
		}

		// in case of short
		else if (objValue instanceof Short)
		{
			strDicomValueValue = Short.toString((Short)objValue);
		}
		// in case of double
		else if (objValue instanceof Double)
		{
			strDicomValueValue = Double.toString((Double)objValue);
		}
		// in case of float
		else if (objValue instanceof Float)
		{
			strDicomValueValue = Float.toString((Float)objValue);
		}
		// in case of Tag
		else if(objValue instanceof ITag )
		{
			strDicomValueValue = objValue.toString();
		}

		//in case of StringArray
		else if (objValue instanceof String[])
		{
			strDicomValueValue = arrayToString((String[])objValue);				
		}

		//in case of int array
		else if (objValue instanceof int[])
		{
			strDicomValueValue = iArrayToString((int[])objValue);
		}

		//in case of Short array
		else if (objValue instanceof short[])
		{	
			strDicomValueValue = sArrayToString((short[])objValue);
		}

		//in case of Double array
		else if (objValue instanceof double[])
		{
			strDicomValueValue = dArrayToString((double[])objValue);
		}

		//in case of Float array
		else if (objValue instanceof float[])
		{		
			strDicomValueValue = fArrayToString((float[])objValue);

		}
		// In case of Tag Array
		else if(objValue instanceof ISingleCollection )
		{
			if(((ISingleCollection)objValue).size()>0)
			{
				ISingleCollection objSingleCollection = (ISingleCollection)objValue;
				if(objSingleCollection instanceof ITag)
					strDicomValueValue = iSingleCollectionITagtoString((ISingleCollection<ITag>)objValue);
			}
		}			

		return strDicomValueValue;
	}

	/**
	 * This mehod constructs string for specified object of DicomValue depending
	 * on its value multiplicity and value representation.
	 * @param objIDicomValue instance of IDicomValue
	 * @return string constructed from specified IDicomValue instance.
	 */
	@SuppressWarnings("unchecked")
	public static String dicomDatatoString(IDicomValue objIDicomValue)
	{
		if(null == objIDicomValue.getValue())
			return null;
		Object objDicomValueValue =	objIDicomValue.getValue();
		String strDicomValueValue = null;
		insert:
			if(objIDicomValue.getValueMultiplicity() >= 1)
			{
				// in case of String
				if (objDicomValueValue instanceof String)
				{
					strDicomValueValue =objDicomValueValue.toString();
					break insert;
				}

				//in case of int
				if (objDicomValueValue instanceof Integer)
				{
					strDicomValueValue = Integer.toString((Integer)objDicomValueValue);
					break insert;
				}

				// in case of short
				if (objDicomValueValue instanceof Short)
				{
					strDicomValueValue = Short.toString((Short)objDicomValueValue);
					break insert;
				}
				// in case of double
				if (objDicomValueValue instanceof Double)
				{
					strDicomValueValue = Double.toString((Double)objDicomValueValue);
					break insert;
				}
				// in case of float
				if (objDicomValueValue instanceof Float)
				{
					strDicomValueValue = Float.toString((Float)objDicomValueValue);
					break insert;
				}
				// in case of Tag
				if(objDicomValueValue instanceof ITag && objIDicomValue instanceof AT)
				{
					strDicomValueValue = objDicomValueValue.toString();
					break insert;
				}

				//in case of StringArray
				if (objDicomValueValue instanceof String[])
				{
					strDicomValueValue = arrayToString((String[])objDicomValueValue);				
					break insert;
				}

				//in case of int array
				if (objDicomValueValue instanceof int[])
				{
					strDicomValueValue = iArrayToString((int[])objDicomValueValue);
					break insert;
				}

				//in case of Short array
				if (objDicomValueValue instanceof short[])
				{	
					strDicomValueValue = sArrayToString((short[])objDicomValueValue);
					break insert;
				}

				//in case of Double array
				if (objDicomValueValue instanceof double[])
				{
					strDicomValueValue = dArrayToString((double[])objDicomValueValue);
					break insert;
				}

				//in case of Float array
				if (objDicomValueValue instanceof float[])
				{		
					strDicomValueValue = fArrayToString((float[])objDicomValueValue);

					break insert;
				}
				// In case of Tag Array
				if(objDicomValueValue instanceof ISingleCollection && objIDicomValue instanceof AT)
				{
					strDicomValueValue = iSingleCollectionITagtoString((ISingleCollection<ITag>)objDicomValueValue);
					break insert;
				}			
			}

		return strDicomValueValue;

	}

	/**
	 * This mehod constructs from ISingleCollection of ITag.
	 * @param objISingleCollection - instance of ISingleCollection<ITag>
	 * @return string constructed from specified SingleCollection of Tag.
	 */
	private static String iSingleCollectionITagtoString(ISingleCollection<ITag>  objISingleCollection)
	{
		String strTagArray = null;
		for (ITag tag : objISingleCollection)
		{
			if(strTagArray == null)
				strTagArray = tag.toString();
			else
				strTagArray += tag.toString();
		}
		return strTagArray;
	}

	/**
	 * This method constructs ISingleCollection<ITag> from string specified separated by "\\".
	 * @param strIDicomValueValue -String from which SingleCollection to be constructed
	 * @return ISingleCollection<ITag>  collection of ITag.
	 */
	private static ISingleCollection<ITag> stringToISingleCollectionITag(String strIDicomValueValue)
	{
		if(null == strIDicomValueValue)
			return null;
		ISingleCollection<ITag> objISingleCollection = new SingleCollection<ITag>();

		String[] strArrayISingleCollectionITag = strIDicomValueValue.split("\\\\");
		String[] strArrayITag = new String[2];
		for (String string : strArrayISingleCollectionITag)
		{
			strArrayITag =string.split(",");
			objISingleCollection.add(new Tag(Integer.valueOf(strArrayITag[0].trim(), 16),
					Integer.valueOf(strArrayITag[1].trim(), 16)));
		}
		return objISingleCollection;
	}

	/**
	 * This method constructs instance of Object using specified arguments and 
	 * depending on value representation.
	 * @param strValue - String from which Object to constructed.
	 * @param iVRType - Value Representation of DataElement
	 * @return Object - instance of Object.
	 */
	public static Object stringToObject(String strValue, int iVRType)
	{
		Object objValue = null;
		if(strValue == null)
			return null;
		if(strValue.contains("\\"))// in case of Array
		{						
			switch(iVRType)
			{
			case DicomConstants.DCM_DT_AE :
			case DicomConstants.DCM_DT_AS :
			case DicomConstants.DCM_DT_CS :
			case DicomConstants.DCM_DT_DA :
			case DicomConstants.DCM_DT_DS :
			case DicomConstants.DCM_DT_DT :
			case DicomConstants.DCM_DT_IS :
			case DicomConstants.DCM_DT_LO :
			case DicomConstants.DCM_DT_LT :
			case DicomConstants.DCM_DT_PN :
			case DicomConstants.DCM_DT_SH :
			case DicomConstants.DCM_DT_ST :
			case DicomConstants.DCM_DT_TM :
			case DicomConstants.DCM_DT_UI :
			case DicomConstants.DCM_DT_UT :
				objValue = stringToArray(strValue);
				return objValue;

			case DicomConstants.DCM_DT_AT : 
				objValue = stringToISingleCollectionITag(strValue);
				return objValue;


			case DicomConstants.DCM_DT_FD :
				objValue = stringTodArray(strValue);
				return objValue;

			case DicomConstants.DCM_DT_FL :
				objValue = stringTofArray(strValue);
				return objValue;

			case DicomConstants.DCM_DT_SL :
			case DicomConstants.DCM_DT_UL :
				objValue = stringToiArray(strValue);
				return objValue;

			case DicomConstants.DCM_DT_SS :
			case DicomConstants.DCM_DT_US :
				objValue =stringTosArray(strValue);
				return objValue;

			case DicomConstants.DCM_DT_OB :
			case DicomConstants.DCM_DT_OW :
			case DicomConstants.DCM_DT_SQ :
			case DicomConstants.DCM_DT_UN :
			{
				return strValue.getBytes();
			}
			default : 
			{
				return null;
			}

			}
		}
		else 
		{
			switch(iVRType)
			{
			case DicomConstants.DCM_DT_AE :
			case DicomConstants.DCM_DT_AS :
			case DicomConstants.DCM_DT_CS :
			case DicomConstants.DCM_DT_DA :
			case DicomConstants.DCM_DT_DS :
			case DicomConstants.DCM_DT_DT :
			case DicomConstants.DCM_DT_IS :
			case DicomConstants.DCM_DT_LO :
			case DicomConstants.DCM_DT_LT :
			case DicomConstants.DCM_DT_PN :
			case DicomConstants.DCM_DT_SH :
			case DicomConstants.DCM_DT_ST :
			case DicomConstants.DCM_DT_TM :
			case DicomConstants.DCM_DT_UI :
			case DicomConstants.DCM_DT_UT :
				objValue =strValue;
				return objValue;

			case DicomConstants.DCM_DT_AT : // ITAg Array need to be implemented??
				objValue =stringToISingleCollectionITag(strValue);
				return objValue;

			case DicomConstants.DCM_DT_FD :
				if(strValue.equals(""))
					objValue = null;
				else
					objValue = Double.parseDouble(strValue);
				return objValue;

			case DicomConstants.DCM_DT_FL :
				if(strValue.equals(""))
					objValue = null;
				else
					objValue = Float.parseFloat(strValue);
				return objValue;

			case DicomConstants.DCM_DT_SL :
			case DicomConstants.DCM_DT_UL :
				if(strValue.equals(""))
					objValue = null;
				else
					objValue = Integer.parseInt(strValue);
				return objValue;
			case DicomConstants.DCM_DT_SS :
			case DicomConstants.DCM_DT_US :
				if(strValue.equals(""))
					objValue = null;
				else
					objValue = Short.parseShort(strValue);
				return objValue;
			case DicomConstants.DCM_DT_OB :
			case DicomConstants.DCM_DT_OW :
			case DicomConstants.DCM_DT_SQ :
			case DicomConstants.DCM_DT_UN :
				return strValue.getBytes();
			default : 
				return null;
			}
		}
	}

	/**
	 * This method constructs instance of IDataElement using specified arguments and 
	 * depending on value representation and its value multiplicity.
	 * @param strDicomValueValue - String from which DicomValue to constructed.
	 * @param iGroupNumber - Group Number
	 * @param iElementNumber - Element Number
	 * @param iVRType - Value Representation of DataElement
	 * @param objITransferSyntax - object of TransferSyntax
	 * @param objIDictionaryReader - object of DictionaryReader
	 * @return - instance of DataElement.
	 */
	public static IDataElement stringtoDataElement(String strDicomValueValue,
			int iGroupNumber,int iElementNumber,int iVRType,
			ITransferSyntax objITransferSyntax,IDictionaryReader objIDictionaryReader)
	{
		if (null == strDicomValueValue)
		{
			if (objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
				return new ImplicitDE(iGroupNumber, iElementNumber, null, objIDictionaryReader);
			else
				return new ExplicitDE(iGroupNumber, iElementNumber, iVRType, null);
		}
		Object objValue = stringToObject(strDicomValueValue, iVRType);
		if(objITransferSyntax.getVRTransferSyntax()==DicomConstants.DCM_VR_IMPLICIT)
			return  new ImplicitDE(iGroupNumber,iElementNumber,objValue,objIDictionaryReader);
		else
			return new ExplicitDE(iGroupNumber,iElementNumber,iVRType,objValue);
	}

}
