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

/**
 * This is Unsigned Long Datatype class.Since its maximum length is 4 bytes . Hence we read integer from the stream.
 */
public class UL extends DicomValue  
{
	

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	protected long lMaxLength;

	/**
	 * Creates an object of UL with default initialization 
	 */
	UL()
	{
		lMaxLength = DicomConstants.DCM_UL_MAXLENGTH;
		iVRType = DicomConstants.DCM_DT_UL;
	}

	/**
	 * Retrieves the max length for UL DataType
	 * @return long - max length for FD DataType
	 */
	public long getMaxLength()
	{
		return lMaxLength;
	}

	/**
	 * Reads the UL DataType structure from underlying stream
	 * @param objIDicomStream stream from which the DataType is to be written
	 * @param iLength length of the DicomValue to be read from the stream
	 * @return int - returns status success/failure
	 * @throws InvalidDataTypeException If data type validation fails.
	 * @throws IOException If Input/Output operation fails.
	 */
	public boolean read(IDicomStream objIDicomStream,int iLength) throws InvalidDataTypeException, IOException
	{
		if(iLength == lMaxLength)
		{
			//Only Single data value present
			int lData=objIDicomStream.readInt();
			setValue(new Integer(lData));
		}
		else if(iLength > 0)
		{
			int iMultiplicity = iLength/(int)lMaxLength;
			int[] intValueArray = new int[iMultiplicity];

			for(int index = 0; index < iMultiplicity; index++)
				intValueArray[index] = objIDicomStream.readInt();

			setValue(intValueArray);
		}
		return true;
	}

	/**
	 * This function writes the Data Value to the Stream
	 * @param objIDicomStream stream onto which the FD DataType is to serialized
	 * @return int - status indicating success/failure of write method
	 * @throws IOException If Input/Output operation fails.
	 */
	public int write(IDicomStream objIDicomStream) throws IOException
	{
		Object objToWrite  = getValue();
		//Check if the the object ot be written is null
		if(objToWrite == null)
		{
			return 0;
		}	
		else
		{
			//Code to write the object with multiple data values
			if(objToWrite instanceof int[])
			{
				int[] intValueArray = (int[])objToWrite;

				for(int index = 0; index < intValueArray.length; index++)
					objIDicomStream.writeInt(intValueArray[index]);
			}
			//Write the Object with single value
			else
			{
				Integer iData = (Integer)objToWrite;		
				objIDicomStream.writeInt(iData.intValue());
			}	
			return 1;
		}
	}

	/**
	 * Validates UL DataType according to the rules specified in the DICOM Standard
	 * @param objToValidate instance of base Object class.
	 * @return boolean - status indicating success/failure of validation
	 */	
	public boolean validate(Object objToValidate)
	{
		return true;
	}

	/**
	 * Validates UL DataType according to the rules specified in the DICOM Standard
	 * @return boolean - status indicating success/failure of validation
	 */	
	public boolean validate()
	{
		return validate(value);
	}

	/**
	 * Retrieves the actual value length of UL
	 * @return integer - actual value length of UN
	 */
	public int getValueLength()
	{
		int iValueLength=0;
		if(value != null)
		{
			if(value instanceof int[])
			{
				int[] intValueArray = (int[])value;
				iValueLength = intValueArray.length * 4;
			}
			else
			{
				iValueLength=4;
			}
		}
		return iValueLength;
	}

	/**
	 * Sets the value in the DicomValue after performing validation on the value.
	 * After setting the value setValue returns the errorcode indicating whether the validation of value was successful or failing 
	 * @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
		{
			/*
			 * This If-Else block checking whether given value is valid for this Type or not and sets VM according to that
			 */
			if(objValue != null)
			{
				if(objValue instanceof Integer)
					iVM = 1;
				else if(objValue instanceof int[])
					iVM = ((int[])objValue).length;
				else
					throw new InvalidValueException(StandardMethods.getStrVRtype(iVRType));
			}
			validate(objValue);
			value=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 UL Data Type.
	 */
	public String toString()
	{
		if(value != null)
		{
			if (value instanceof Integer)
			{
				return value.toString();
			}
			else if (value instanceof Integer[])
			{
				Integer[] arrIntValue = (Integer[])value;
				String strValue = "";
				for(int i=0; i<arrIntValue.length; i++)
				{
					strValue = strValue + arrIntValue[i].toString() + "\\";
				}
				return strValue;
			}
		}
		return null;
	}

	/**
	 *  Dumps the value of Attribute in redable form.
	 *  @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 Integer)
		{
			objIDicomStream.writeString("Value : " + (Integer)value);
		}
		else if (value instanceof int[])
		{
			int[] intValueArray = (int[])value;
			StringBuffer strFinalString = new StringBuffer("[");
			for(int intValue : intValueArray)
			{
				strFinalString.append(' ');
				strFinalString.append(intValue);
				strFinalString.append(' ');
			}
			strFinalString.append("]");
			objIDicomStream.writeString("Value : " + strFinalString);
		}
	}
}
