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

/**
 * FL is Single precision binary floating point number represented in IEEE 754:1985 32-bit Floating Point Number Format. 
 */
public class FL extends DicomValue   
{
	


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

	/**
	 * Creates an object of FL with default initialization 
	 */
	FL()
	{
		lMaxLength = DicomConstants.DCM_FL_MAXLENGTH;
		iVRType = DicomConstants.DCM_DT_FL;
	}

	/**
	 * Returns max length of FL 
	 * @return long - lenght of FL type
	 */
	public long getMaxLength()
	{
		return lMaxLength;
	}

	/**
	 * Reads the FL DataType structure from underlying stream
	 * @param objIDicomStream stream from which the DataType is to be written
	 * @param iLength length of the FL 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
			float fData=objIDicomStream.readFloat();
			setValue(new Float(fData));
		}
		else if(iLength > 0)
		{
			int iMultiplicity = iLength/(int)lMaxLength;
			float[] floatDataArray = new float[iMultiplicity];

			for(int index = 0; index < iMultiplicity; index++)
			{
				//Get the each of the data values
				floatDataArray[index] = objIDicomStream.readFloat();
			}
			setValue(floatDataArray);
		}
		return true;
	}

	/**
	 * This method writes the Data Value to the Stream.
	 * @param objIDicomStream object of stream onto which the FL DataType is to be written 
	 * @return 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 float[])
			{
				float[] floatDataArray = (float[])objToWrite;

				for(int index = 0; index < floatDataArray.length; index++)
					objIDicomStream.writeFloat(floatDataArray[index]);
			}
			else
			{
				Float floatValue = (Float)objToWrite;		
				objIDicomStream.writeFloat(floatValue.floatValue());
			}
			return 1;
		}
	}

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

	/**
	 * Validates FD 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 FD
	 * @return integer - actual value length of FD
	 */
	public int getValueLength()
	{
		int iValueLength=0;
		if(value!= null)
		{
			if(value instanceof float[])
			{
				float[] fValues = (float[])value;
				iValueLength = fValues.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 data type validation fails.
	 */
	public void setValue(Object objValue) throws InvalidDataTypeException
	{
		try
		{
			validate(objValue);
			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(objValue instanceof Float)
					iVM = 1;
				else if(objValue instanceof float[])
					iVM = ((float[])objValue).length;
				else
					throw new InvalidValueException(StandardMethods.getStrVRtype(iVRType));
			}
		}
		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 FL Data Type.
	 */
	public String toString()
	{
		if(value != null)
		{
			if (value instanceof Float)
			{
				return value.toString();
			}
			else if (value instanceof Float[])
			{
				Float[] arrFlValue = (Float[])value;
				String strValue = "";
				for(int i=0; i<arrFlValue.length; i++)
				{
					strValue = strValue + arrFlValue[i].toString() + "\\";
				}
				return strValue;
			}
		}
		return null;
	}

	/**
	 *  Dumps the value of Attribute in readable 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 Float)
		{
			objIDicomStream.writeString("Value : " + (Float)value);
		}
		else if (value instanceof Float[])
		{
			Float[] floatValueArray = (Float[])value;
			StringBuffer strFinalString = new StringBuffer("[");
			for(Float floatValue : floatValueArray)
			{
				strFinalString.append(' ');
				strFinalString.append(floatValue);
				strFinalString.append(' ');
			}
			strFinalString.append("]");
			objIDicomStream.writeString("Value : " + strFinalString);
		}
	}
}
