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

import java.io.IOException;
import java.util.Locale;

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataTypeException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidValueException;
import cdac.medinfo.sdk.dcm30_04.exceptions.LengthLimitException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ValidationException;
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.IPairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.PairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;

/**
 * This class is the Super Class of all the String Datatypes.
 * It provides implementation for read from stream and write to stream functions for all its sub classes.
 */
public class DatatypeString extends DicomValue  
{
	
	private static String strREGEX_AE ="[\\s]*[[a-zA-Z_0-9]*[\\s]*[\\p{Punct}&&[^\\\\]]*[\\p{Cntrl}&&[^\\r\\f\\n\\e]]*[a-zA-Z_0-9]*]+[\\s]*[0-9]*";
	private static String strRegEX_AS ="[0-9]{3}[DMWY]";
	private static String strREGEX_CS ="[\\s]*[a-zA-Z_0-9\\s .-]*[\\s]*";	
	private static String strREGEX_DA ="((18|19|20)[0-9]{2})([\\p{Punct}&&[.]]*)((0[0-9])|(1[0-2]))([\\p{Punct}&&[.]]*)(([0-2][0-9])|(3[0-1]))";
	private static String strREGEX_DS ="[\\s]*[\\+|\\-]?[\\p{Digit}]*[\\.]?+[\\p{Digit}]*[eE]?[\\+|\\-]?[\\p{Digit}]*[\\s]*";
	private static String strREGEX_DT ="((18|19|20)[0-9]{2})((0[0-9])|(1[0-2]))(([0-2][0-9])|(3[0-1]))(([0-1][0-9])|(2[0-3]))([0-5][0-9]([0-5][0-9]((\\.[[0-9]{6}]+)((\\+|\\-)(([0-1][0-9])|(2[0-3]))([0-5][0-9])?)?)?)?)?";
	private static String strREGEX_IS ="[\\s]*[\\p{Punct}&&[+-]]?+[0-9]*[\\s]*";
	private static String strREGEX_LO ="[[\\s][\\p{Alpha}][\\p{Cntrl}&&\\e][\\p{Punct}&&[^\\\\]][0-9][\\xa0-\\xff]]*";
	private static String strREGEX_LT ="[[\\s]*[a-zA-Z_0-9]*[\\p{Cntrl}&&[\\r\\n\\f\\e]]*[\\p{Punct}]*[\\xa0-\\xff]]+";
	private static String strREGEX_PN ="[[\\p{Alpha}[0-9]\\-\\.\\s\\,[\\p{Punct}&&[^\\\\]]]*[\\^]]*";
	private static String strREGEX_SH ="[[\\s]*[\\p{Alpha}]*[\\s]*[\\p{Alpha}]*[\\p{Cntrl}&&\\e]*[\\p{Alpha}]*[\\p{Punct}&&[^\\\\]]*[\\p{Alpha}]*[0-9]*]*";
	private static String strREGEX_ST ="[\\p{Cntrl}&&[\\x0A\\x0C\\x0D\\x1B]]*[a-zA-Z_0-9\\p{Punct}\\s]*";
	private static String strREGEX_TM ="(([0-1][0-9])|(2[0-3]))([0-5][0-9]([0-5][0-9](\\.[[0-9]{6}]+)?)?)?[\\s]*";
	private static String strREGEX_TM_OLD ="((([0-1][0-9])|(2[0-3])):?([0-5][0-9](:[0-5][0-9][(\\.[[0-9]{6}])]*)?([0-5][0-9](\\.[[0-9]{6}]+)?)?))?[\\s]*";
	private static String strREGEX_UI ="^[a-zA-Z0-9_ .\\-+=/\"]*$";
	private static String strREGEX_UT ="[[\\s]*[a-zA-Z_0-9]*[\\p{Cntrl}&&[\\r\\n\\f\\e]]*[\\p{Punct}]*]*";


	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	protected long lMaxLength;	//Maximum Length of Data to be read
	protected static final IPairedCollection<Integer, String> objPaireCollection = new PairedCollection<Integer, String>();//HashMap for key:iVRType Value:Regular Expressions 
	static
	{
		/*
		 * AE:
		 * A string of characters that identifies a Application Entity with leading and trailing
		 * spaces (20H) being non-significant. A value consisting soley of spaces shall not be used.
		 */
		//add(DicomConstants.DCM_DT_AE,"[\\s]*[[a-zA-Z_0-9]*[\\p{Punct}&&[^\\\\]]*[\\p{Cntrl}&&[^\\r\\f\\n\\e]]*]+[\\s]*");
		add(DicomConstants.DCM_DT_AE,strREGEX_AE);

		/*AS:
		 * A string of characters with one of the following formats -- nnnD, nnnW, nnnM, nnnY; where
           nnn shall contain the number of days for D, weeks for W, months for M, or years for Y.
		 */
//		add(DicomConstants.DCM_DT_AS,"[[0-9][[A-Z]&&[DMWY]]{1}[[a-z]&&[dmwy]]{1}]+");
		//By AK 19-09-07 modified regular expression to match 3 occurances of digit and only D,M,W,Y letters.
		add(DicomConstants.DCM_DT_AS,strRegEX_AS);

		/*CS:
		 *A string of characters with leading or trailing spaces (20H) being non-significant.
		 */
		add(DicomConstants.DCM_DT_CS,strREGEX_CS);

		/*DA:
		 * A string of characters of the format yyyymmdd; where yyyy shall contain year, mm shall
		   contain the month, and dd shall contain the day. This conforms to the ANSI HISPP
		   MSDS Date common data type.
		   Example: �19930822� would represent August 22,1993.
		 */
		add(DicomConstants.DCM_DT_DA,strREGEX_DA);

		/*
		 * DS:
		 * A string of characters representing either a fixed point number or a floating point number.
		   A fixed point number shall contain only the characters 0-9 with an optional leading "+" or
		   "-" and an optional "." to mark the decimal point. A floating point number shall be
		   conveyed as defined in ANSI X3.9, with an "E" or "e" to indicate the start of the exponent.
		   Decimal Strings may be padded with leading or trailing spaces. Embedded spaces are not
		   allowed.
		 */
		add(DicomConstants.DCM_DT_DS,strREGEX_DS);

		/*
		 * DT:
		 * The Date Time common data type. Indicates a concatenated date-time ASCII string in the
		   format: YYYYMMDDHHMMSS.FFFFFF&ZZZZ The components of this string, from left to
		   right, are YYYY = Year, MM = Month, DD = Day, HH = Hour, MM = Minute, SS = Second,
		   FFFFFF = Fractional Second, & = �+� or �-�,and ZZZZ = Hours and Minutes of offset.
		   &ZZZZ is an optional suffix for plus/minus offset from Coordinated Universal Time. A
		   component that is omitted from the string is termed a null component. Trailing null
		   components of Date Time are ignored. Nontrailing null components are prohibited, given
		   that the optional suffix is not considered as a component.
		 */
		add(DicomConstants.DCM_DT_DT,strREGEX_DT);
		//By Atreya on 21-05-07,Modified to support leading and trailing spaces

		/*
		 * IS:
		 * A string of characters representing an Integer in base-10 (decimal), shall contain only the
		   characters 0 - 9, with an optional leading "+" or "-". It may be padded with leading and/or
		   trailing spaces. Embedded spaces are not allowed. The integer, n, represented shall be in the
		   range: -231 <= n <= (231 - 1).
		 */
		add(DicomConstants.DCM_DT_IS,strREGEX_IS);

		/*
		 * LO:
		 * A character string that may be padded with leading and/or trailing spaces.
		 *  The character code 5CH (the BACKSLASH �\� in ISO-IR 6) shall not be present, 
		 *  as it is used as the delimiter between values in multiple valued
			data elements. The string shall not have Control Characters except for ESC.
		 */
		//add(DicomConstants.DCM_DT_LO,"[[\\s]*[\\p{Alpha}]*[\\s]*[\\p{Alpha}]*[\\p{Cntrl}&&\\e]*[\\p{Alpha}]*[\\p{Punct}&&[^\\\\]]*[\\p{Alpha}]*[0-9]*]*");
		add(DicomConstants.DCM_DT_LO,strREGEX_LO);	
		/*
		 * LT:
		 * A character string that may contain one or more paragraphs. It may contain the Graphic
		   Character set and the Control Characters, CR,LF, FF, and ESC. It may be padded with
		   trailing spaces, which may be ignored, but leading spaces are considered to be
		   significant. Data Elements with this VR shall not be multi-valued and therefore character
		   code 5CH (the BACKSLASH �\� in ISO-IR 6) may be used.
		   LT can contains all characters.
		 */
		add(DicomConstants.DCM_DT_LT,strREGEX_LT);

		/*
		 * PN:
		 * A character string encoded using a 5 component convention. The character code
		 * 5CH (the BACKSLASH �\� in ISO-IR 6) shall not be present, as it is used as the delimiter
		 * between values in multiple valued data elements. The string may be padded with
		 * trailing spaces. The five components in their order of occurrence are: family name complex,
		 * given name complex, middle name, name prefix, name suffix. Any of the five components
		 * may be an empty string. The component delimiter shall be the caret �^� character (5EH).
		 * Delimiters are required for interior null components. Trailing null components and
		 * their delimiters may be omitted. Multiple entries are permitted in each component and
		 * are encoded as natural text strings, in the format preferred by the named person.
		 */
		add(DicomConstants.DCM_DT_PN,strREGEX_PN);

		/*
		 * SH:
		 * A character string that may be padded with leading and/or trailing spaces. The character
		   code 05CH (the BACKSLASH �\� in ISO-IR 6) shall not be present, as it is used as the
		   delimiter between values for multiple data elements. The string shall not have Control
	       Characters except ESC.

		 */
		add(DicomConstants.DCM_DT_SH,strREGEX_SH);

		/*
		 * ST:
		 * A character string that may contain one or more paragraphs. It may contain the Graphic 
		 * Character set and the Control Characters, CR, LF, FF, and ESC. It may be padded with
		   trailing spaces, which may be ignored, but leading spaces are considered to be
		   significant. Data Elements with this VR shall not be multi-valued and therefore character
		   code 5CH (the BACKSLASH �\� in ISO-IR 6) may be used.
		   ST can contains all characters.
		 */
		add(DicomConstants.DCM_DT_ST,strREGEX_ST);

		/*
		 * TM:
		 * A string of characters of the format hhmmss.frac; where hh contains hours (range
	  	   "00" - "23"), mm contains minutes (range "00" - "59"), ss contains seconds (range "00" -
		   "59"), and frac contains a fractional part of a second as small as 1 millionth of a second
		   (range �000000� - �999999�). A 24 hour clock is assumed. Midnight can be represented by 
		   only �0000� since �2400� would violate the hour range. The string may be padded with
		   trailing spaces. Leading and embedded spaces are not allowed. One or more of the
		   components mm, ss, or frac may be unspecified as long as every component to the
	 	   right of an unspecified component is also unspecified. If frac is unspecified the
		   preceding �.� may not be included.
		 */
		add(DicomConstants.DCM_DT_TM,strREGEX_TM);

		/*
		 * This regular expression is for backward comatibility with versions of this standard prior to V3.0,
		 */
		add(DicomConstants.DCM_DT_TM_OLD,strREGEX_TM_OLD);

		/*
		 * UI:
		 * A character string containing a UID that is used to uniquely identify a wide variety of
		   items. The UID is a series of numeric components separated by the period "."
		   character. If a Value Field containing one or more UIDs is an odd number of bytes in
		   length, the Value Field shall be padded with a single trailing NULL (00H) character to ensure
		   that the Value Field is an even number of bytes in length.
		 */
		add(DicomConstants.DCM_DT_UI,strREGEX_UI);

		/*
		 * UT:
		 * A character string that may contain one or more paragraphs. It may contain the Graphic
		   Character set and the Control Characters, CR, LF, FF, and ESC. It may be padded with trailing spaces, which may be ignored, but
		   leading spaces are considered to be significant. Data Elements with this VR shall
           not be multi-valued and therefore character code 5CH (the BACKSLASH �\� in ISO-IR 6)
		   may be used.
		   UT can contains all characters. 
		 */
		add(DicomConstants.DCM_DT_UT,strREGEX_UT);
	}

	/**
	 * Default constructor for DataTypeString class.
	 */
	DatatypeString()
	{

	}

	/**
	 * Contructor for DataTypeString which initializes VR type.
	 * @param iVRType integer value of VR type.
	 */
	DatatypeString(int iVRType)
	{
		setIVRType(iVRType);
	}

	/**
	 * This method maps a key with specified regular expression in the HashMap
	 * @param iKey This is the Value Representation Type
	 * @param strRegex This is the regular Expression for validating the datatype
	 */
	private static void add(int iKey,String strRegex)
	{
		objPaireCollection.put(new Integer(iKey), strRegex);
	}

	/**
	 * Retrieves maximum allowed length by this datatype.
	 * @return long - max length of Datatype
	 */
	public long getMaxLength()
	{
		return lMaxLength;
	}

	/**
	 * Reads and validates the data value from the stream of specified length of bytes.
	 * @param objIDicomStream isntance of class implementing the IDicomStream interface.
	 * @param iLength Number of bytes to be read from the Stream.
	 * @return boolean - status if read was successful.
	 * @throws InvalidDataTypeException If DataType validation fails.
	 * @throws IOException If Input/Output operation fails.
	 */
	public boolean read(IDicomStream objIDicomStream,int iLength) throws InvalidDataTypeException, IOException
	{
		try
		{
			String strData = null;
			String strDataArray[]=null;
			int cnt=0;
			//If length of value is zero, then the value is not present.
			if(iLength == 0)
			{
				iVM = 0;
				return true;
			}

			strData=objIDicomStream.readString(iLength);
			// (\) character is used as delimeter between multiple values.Get the array of data values.
			if(strData.contains(DicomConstants.DCM_DOUBLE_BACKSLASH))
			{
				strDataArray=strData.split(DicomConstants.DCM_QUADRUPLE_BACKSLASH);
			}
			//Set single string value
			if(strDataArray==null)
			{
				//If the String contains a padded NULL character then strip it from the actual value
				if(strData.contains(DicomConstants.DCM_NULL))
					strData = strData.substring(0, strData.length() - 1);
				else if(strData.endsWith(DicomConstants.DCM_SPACE))
					strData = strData.substring(0, strData.length() - 1);


				setValue(strData);
			}
			else 
			{
				/* For multiple values check if last value in the array contains a
				 * NULL character appended. If NULL character is present then strip the
				 * character from actual value and reduce the value's length by 1.
				 * NULL character is appended to the string value to make the length
				 * of the value even since according to DICOM standard the values should 
				 * have even lengths.
				 */
				cnt = strDataArray.length -1 ;
				String strTemp = null;
				if(strDataArray[cnt].contains(DicomConstants.DCM_NULL))
				{
					strTemp = strDataArray[cnt];
					strDataArray[cnt] = strTemp.substring(0, strTemp.length() -1);
				}
				else if(strDataArray[cnt].endsWith(DicomConstants.DCM_SPACE))
				{
					strTemp = strDataArray[cnt];
					strDataArray[cnt] = strTemp.substring(0, strTemp.length() -1);
				}
				//Once the proper value array is ready set it to the DicomValue
				setValue(strDataArray);
			}
		}
		catch( InvalidValueException ive)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ive.getMessage());
			}
			throw new InvalidDataTypeException(ive.getMessage(),ive);
		}
		catch( LengthLimitException lle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(lle.getMessage());
			}
			throw new InvalidDataTypeException(ResourceBundleWrapper.getValue("exceptions", "InvalidDataType", new Locale(DicomConfig.createInstance().getLocale()))+ "Length of value is greater than the Maximum Length Allowed", lle);
		}
		return true;
	}

	/**
	 * This method checks for the length of string read from stream to be less or equal to max allowed length by the datatype of the value. 
	 * @param iLengthToValidate length of the value to be validated.
	 * @return int - status indicating success/failure of length validation.
	 * @throws LengthLimitException If length exceeds from allowed length.
	 */
	public int validateLength(int iLengthToValidate) throws LengthLimitException
	{
		if(iLengthToValidate > lMaxLength)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(new LengthLimitException(ResourceBundleWrapper.getValue("exceptions", "LengthLimit", new Locale(DicomConfig.createInstance().getLocale()))).getMessage() + StandardMethods.getStrVRtype(getIVRType()));
			throw new LengthLimitException(ResourceBundleWrapper.getValue("exceptions", "LengthLimit", new Locale(DicomConfig.createInstance().getLocale())));
		}
		return DicomConstants.DCM_DT_VALID_LENGTH;
	}

	/**
	 * Validates the data value object as per the encoding rules provided in the DICOM Standard. 
	 * @param objToValidate object representing value to be validated.
	 * @return boolean - status indicating success/failure of the validation.
	 * @throws ValidationException If validation fails according to Dicom rules.
	 */
	public boolean validate(Object objToValidate) throws ValidationException
	{		
		try{
		
		if(objToValidate == null) // This facilitates creation of empty data type String.
			return true;
		//validate the length of string value
		if(objToValidate instanceof String[])
		{
			String[] arrStrTemp = (String[]) objToValidate;
			for(String strVal : arrStrTemp)
			{
				if(strVal != null)
					validateLength(strVal.length());
			}
		}
		else
			validateLength(objToValidate.toString().length());

		//Get the regular expression according to the value representation of the value
		String strRegex=objPaireCollection.get(new Integer(iVRType)).toString();

		//Match the value with the regular expression  
		if(objToValidate instanceof String)
		{
			String strValue = (String)objToValidate;
			//check if the value matches the regular expression
			if(strValue != null && !strValue.matches(strRegex))
			{
				throw new InvalidValueException(strValue);
			}
		}
		else if(objToValidate instanceof String[])
		{
			String[] strValueArray = (String[])objToValidate;
			//check if each value in string array matches the regular expression
			for(int index = 0; index < strValueArray.length; index++)
			{
				String strValue = strValueArray[index];

				if(strValue != null && !(strValue.matches(strRegex)))
				{
					throw new InvalidValueException(strValue);
				}
			}
		}
		return true;
		}
		catch(LengthLimitException lle)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log( lle.getMessage());
			}
			throw new ValidationException(lle.getMessage(),lle);
		}
	}

	/**
	 * Validates the data value object as per the encoding rules provided in the DICOM Standard. 
	 * @return boolean - status indicating success/failure of the validation.
	 * @throws ValidationException If validation fails according to Dicom rules.
	 */
	public boolean validate() throws ValidationException
	{
		return validate(value);
	}

	/**
	 * This method writes the Data Value to the given Stream.
	 * @param objIDicomStream object of the stream onto which the DataTypeString is to be written.
	 * @return integer - status indicating success/failure of the write method.
	 * @throws IOException If Input/Output operation fails.
	 */
	public int write(IDicomStream objIDicomStream) throws IOException
	{
		String strData = null;
		Object objToWrite  = value;

		//Check if the the object to be written is null then write should fail
		if(objToWrite == null)
		{
			return 0;
		}	
		else
		{
			//Code to write the object with multiple data values
			if(objToWrite instanceof String[])
			{
				String[]  strValueArray = (String[])objToWrite;
				int iSize = strValueArray.length;	//size of the string array

				int iIndex = 0;
				while(iIndex < iSize)
				{
					if(strValueArray[iIndex] != null)
					{
						//get string value from the array
						if(strData == null)
							strData = strValueArray[iIndex];
						else
							strData = strData + strValueArray[iIndex];

						/*
						 * If the length of the string value is odd then pad a NULL character to the last 
						 * value in the array.Also increment the length by 1. This code change is to make 
						 * the length even when writing value to stream since DICOM standard specifies 
						 * that on the stream value length should always be even.
						 */
						if(iVRType == DicomConstants.DCM_DT_UI)
						{
							if(((getValueLength() % 2) != 0) && (iIndex == iSize - 1))
							{
								strData = strData + DicomConstants.DCM_NULL;
							}
						}
						else if(((getValueLength() % 2) != 0) && (iIndex == iSize - 1))
						{
							strData = strData + DicomConstants.DCM_SPACE;
						}
						/*The \ character is added after every value,except the last element,
						 *in case of multiple values.*/
						if(iIndex != iSize - 1)
							strData = strData + DicomConstants.DCM_DOUBLE_BACKSLASH;
					}
					iIndex++;
				}
			}
			//Code to write object with single value
			else
			{
				strData = (String) objToWrite;
				/*Check if the length is odd then pad a NULL character to the last value in array.
				 *Also increment the length by 1. This code change is to make the length even when
				 *writing value to stream*/
				if(iVRType == DicomConstants.DCM_DT_UI)
				{
					if((getValueLength() % 2) != 0)
					{
						strData = strData + DicomConstants.DCM_NULL;
					}
				}
				else if((getValueLength() % 2) != 0)
				{
					strData = strData + DicomConstants.DCM_SPACE;
				}
			}
			//The String write operation
			if(strData != null)
			{
				byte[] arrChar = strData.getBytes(); //Get the bytes from the string
				objIDicomStream.writeChars(arrChar); //write the bytes to the given stream
			}
			return 1;//Write Successful
		}
	}


	/**
	 * Retrieves the actual value length set in the DataTypeString. This length doesn't include the padding bytes.
	 * @return int - length of Dicomdata
	 */
	public int getValueLength()
	{
		int iValueLength = 0;

//		Check if value is null then length cannot be calculated so return.
		if(value == null)
			return 0;

		/*If the value is a string array then length of each value in array is summed and
		 *the total length of value is calculated.
		 *If value is a single string then set length of value.*/
		if(value instanceof String[])
		{
			//since value is object type then cast it to string array
			String[] strValueArray = (String[])value;
			if(strValueArray.length == 0)
				return 0;
			//Sum up the lengths of each string in array
			for(int index=0;index<strValueArray.length;index++)
			{
				if(strValueArray[index] != null)
				{
					iValueLength += strValueArray[index].length();
//					Add Number of back slashes to length
					if(index != strValueArray.length-1)
						iValueLength = iValueLength +1;
				}
			}
		}
		else
		{
			//For Single value assign the length of value as ValueLength
			iValueLength=value.toString().length();
		}
		return iValueLength;
	}

	/**
	 * Sets the value in the DicomValue after performing validation on the value.
	 * @param objValue value that is to be set into the DicomValue
	 * @throws InvalidDataTypeException If DataType validation fails.
	 */
	public void setValue(Object objValue) throws InvalidDataTypeException
	{
		try
		{
			
			
			//Assign the value
			value=objValue;
			/*
			 * This If-Else block checking whether given value is valid for this Type or not and sets VM according to that
			 */
			if(value != null)
			{
				if(value instanceof String[])
					iVM = ((String[])value).length;
				else if(value instanceof String)
					iVM = 1;
				else
					throw new InvalidValueException(StandardMethods.getStrVRtype(iVRType));
			}
			
			//Validate the value before setting it in DicomValue
			validate(objValue);
		}
		catch( InvalidValueException ive)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ive.getMessage());
			}
			throw new InvalidDataTypeException(ive.getMessage(),ive);
		}
		catch( ValidationException ive)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ive.getMessage());
			}
			throw new InvalidDataTypeException(ive.getMessage(),ive);
		}
	}

	/**
	 * This function returns the String value of Data Type String.
	 */
	public String toString()
	{
		if(value != null)
		{
			if (value instanceof String)
			{
				return (String)value;
			}
			else if (value instanceof String[])
			{
				String[] arrStrValue = (String[])value;
				String strValue = "";
				for(int i=0; i<arrStrValue.length; i++)
				{
					if (arrStrValue[i] != null && i != (arrStrValue.length - 1))
                        strValue = strValue + arrStrValue[i] + "\\";
                    else
                        strValue = strValue + arrStrValue[i];
				}
				return strValue;
			}
		}
		return null;
	}

	/**
	 * 	Dumps the value of Data Type String in readable form to the specified Stream.
	 * 	@param objIDicomStream - the Stream on which the Data is to be written.
	 *  @throws IOException - Exception is thrown indicating runtime failure of writing operation.
	 */
	public void dumpDICOMInfo(IDicomStream objIDicomStream) throws IOException
	{
		if(value instanceof String)
		{
			//if value is String Type
			objIDicomStream.writeString("Value : " + (String)value);
		}
		else if (value instanceof String[])
		{
			//if value is Array of String
			String[] strValueArray = (String[])value;
			StringBuffer strFinalString = new StringBuffer("[");
			for(String strValue : strValueArray)
			{
				strFinalString.append(' ');
				strFinalString.append(strValue);
				strFinalString.append(' ');
			}
			strFinalString.append("]");
			objIDicomStream.writeString("Value : " + strFinalString);
		}
	}
}