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

/**
 * US is signifies Unsigned binary integer 16 bits long.Represents integer n in the range:0 <= n < 216.
 */
public class US extends DicomValue  
{
	


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

	/**
	 * Creates an object of AE with default initialization 
	 */
	US()
	{
		lMaxLength = DicomConstants.DCM_US_MAXLENGTH;
		iVRType = DicomConstants.DCM_DT_US;
	}

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

	/**
	 * Validates US DataType
	 * @param objToValidate value of US to be validated
	 * @return boolean - status indicating success/failure
	 */
	public boolean validate(Object objToValidate)
	{
		return true;
	}

	/**
	 * Validates US DataType
	 * @return boolean - status indicating success/failure
	 */
	public boolean validate()
	{
		return validate(value);
	}

	/**
	 * Reads the US 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 integer - 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
			short sData=objIDicomStream.readShort();
			setValue(new Short(sData));
		}
		else 
		{
			int iMultiplicity = iLength/(int)lMaxLength;
			short[] shortValueArray = new short[iMultiplicity];

			for(int index = 0; index < iMultiplicity; index++)
				shortValueArray[index] = objIDicomStream.readShort();

			setValue(shortValueArray);
		}
		return true;
	}

	/**
	 * This fucntion writes the Data Value to the Stream
	 * @param objIDicomStream  stream onto which the FD DataType is to serialized
	 * @return ineteger - 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 short[])
			{
				short[] shortValueArray = (short[])objToWrite;

				for(int index = 0; index < shortValueArray.length; index++)
					objIDicomStream.writeShort(shortValueArray[index]);
			}

			//Write the Object with single value
			else
			{
				Short sData = (Short)objToWrite;		
				objIDicomStream.writeShort(sData.shortValue());
			}			
			return 1;
		}
	}

	/**
	 * Retrieves the actual value length of US
	 * @return integer - actual value length of US
	 */
	public int getValueLength()
	{
		int iValueLength=0;
		if(value!= null)
		{
			if(value instanceof short[])
			{
				short[] shortValueArray = (short[])value;
				iValueLength = shortValueArray.length * 2;
			}
			else
			{
				iValueLength=2;
			}
		}
		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 Signals Data Type is not valid.
	 */
	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 Short)
					iVM = 1;
				else if(objValue instanceof short[])
					iVM = ((short[])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 US Data Type.
	 */
	public String toString()
	{
		if(value != null)
		{
			if (value instanceof Short)
			{
				return value.toString();
			}
			else if (value instanceof short[])
			{
				short[] arrShValue = (short[])value;
				String strValue = "";
				for(int i=0; i<arrShValue.length; i++)
				{
					strValue = strValue + arrShValue[i] + "\\";
				}

				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 Short)
		{
			objIDicomStream.writeString("Value : " + (Short)value);
		}
		else if (value instanceof short[])
		{
			short[] shortValueArray = (short[])value;
			StringBuffer strFinalString = new StringBuffer("[");
			for(short shortValue : shortValueArray)
			{
				strFinalString.append(' ');
				strFinalString.append(shortValue);
				strFinalString.append(' ');
			}
			strFinalString.append("]");
			objIDicomStream.writeString("Value : " + strFinalString);
		}
	}
}
