#include "IFD_ENTRY.h"

namespace MobilePhotoTool{

	IFD_ENTRY::IFD_ENTRY(MPT_Exception *exception, MPT_Buffer *buffer, size_t position)
	{
		this->buffer	= buffer;
		this->position	= position;

		this->type 		= NULL;

		read(exception );
	}


	IFD_ENTRY::~IFD_ENTRY(void)
	{
		delete this->type;
	}

	void IFD_ENTRY::read(MPT_Exception *exception)
	{
		buffer->position(exception, position);
		int tag		= buffer->get_ushort(exception);
		int type	= buffer->get_ushort(exception);
		

		this->type 	= new IFD_TYPE(exception, tag, type);
		this->number_values = buffer->get_uint(exception);
		MPT_EXCEPTION_TEST;

		if((this->type->type_length(exception) * this->number_values) <= 4){
			this->position_values = buffer->position(exception);
			MPT_EXCEPTION_TEST;
		}else{
			this->position_values = buffer->get_uint(exception);
			MPT_EXCEPTION_TEST;
		}
	}

	size_t *IFD_ENTRY::get_integer_as_streamoff(MPT_Exception *exception, size_t *size)
	{
		size_t *values = NULL;

		*size	= number_values;
		values	= new size_t[number_values];
		if(values == NULL){
			 MPT_EXCEPTION("Out of memory.") NULL;
		}

		if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ||
			this->type->IN_TYPE == IFD_TYPE::IN_IFD){
				
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_uint(exception);
			}
			MPT_EXCEPTION_TEST NULL;
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_ushort(exception);
			}			
			MPT_EXCEPTION_TEST NULL;
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_ubyte(exception);
			}					
			MPT_EXCEPTION_TEST NULL;
		}
		return values;
	}

	unsigned int IFD_ENTRY::get_integer_as_uinterger(MPT_Exception *exception)
	{
		unsigned int value = 0;

		if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ||
			this->type->IN_TYPE == IFD_TYPE::IN_IFD){
			
			this->buffer->position(exception, this->position_values);
			value = this->buffer->get_uint(exception);
			MPT_EXCEPTION_TEST 0;
			
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){
			
			this->buffer->position(exception, this->position_values);
			value = this->buffer->get_ushort(exception);
			MPT_EXCEPTION_TEST 0;
					
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){
			
			this->buffer->position(exception, this->position_values);
			value = this->buffer->get_ubyte(exception);
			MPT_EXCEPTION_TEST 0;	
		}
		return value;
	}

	unsigned int *IFD_ENTRY::get_integer_as_uinterger_array(MPT_Exception *exception, size_t *size)
	{
		unsigned int *values = NULL;

		*size	= number_values;
		values = new unsigned[number_values];
		if(values == NULL){
			MPT_EXCEPTION("Out of memory") NULL;
		}

		if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ||
			this->type->IN_TYPE == IFD_TYPE::IN_IFD){
				
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_uint(exception);
			}
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_ushort(exception);
			}			
		}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){
			
			this->buffer->position(exception, this->position_values);
			MPT_EXCEPTION_TEST NULL;
			for(unsigned int i = 0; i < this->number_values; i += 1){
				values[i] = this->buffer->get_ubyte(exception);
			}					
		}
		return values;
	}

	void IFD_ENTRY::get_as_rational(MPT_Exception *exception, unsigned int *value, size_t size)
	{
		if(size >= this->number_values * 2){

			if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_uint(exception);
					value[i * 2 + 1] = 1;
				}
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_ushort(exception);
					value[i * 2 + 1] = 1;
				}			
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_ubyte(exception);
					value[i * 2 + 1] = 1;
				}					
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_RATIONAL){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_uint(exception);
					value[i * 2 + 1] = this->buffer->get_uint(exception);
				}					
			}

		}else{
			MPT_EXCEPTION("Array is to small.");
		}
	}

	void IFD_ENTRY::get_as_srational(MPT_Exception *exception, int *value, size_t size)
	{
		if(size >= this->number_values * 2){

			if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_uint(exception);
					value[i * 2 + 1] = 1;
				}
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_ushort(exception);
					value[i * 2 + 1] = 1;
				}
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_ubyte(exception);
					value[i * 2 + 1] = 1;
				}
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_SRATIONAL){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					value[i * 2] = this->buffer->get_int(exception);
					value[i * 2 + 1] = this->buffer->get_int(exception);
				}
			}

		}else{
			MPT_EXCEPTION("Array is to small.");
		}
	}


	void IFD_ENTRY::get_as_float(MPT_Exception *exception, float *values, size_t size)
	{
		if(size >= this->number_values){

			if(	this->type->IN_TYPE == IFD_TYPE::IN_LONG ){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					values[i] = (float)this->buffer->get_uint(exception);
				}
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_SHORT ){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					values[i] = (float)this->buffer->get_ushort(exception);
					
				}			
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_BYTE){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					values[i] = (float)this->buffer->get_ubyte(exception);
					
				}					
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_RATIONAL){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					values[i] = (float)this->buffer->get_uint(exception);
					values[i] /= (float)this->buffer->get_uint(exception);
				}					
			}else if(this->type->IN_TYPE == IFD_TYPE::IN_SRATIONAL){
			
				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;
				for(unsigned int i = 0; i < this->number_values; i += 1){
					values[i] = (float)this->buffer->get_int(exception);
					values[i] /= (float)this->buffer->get_int(exception);
				}					
			}

		}else{
			MPT_EXCEPTION("Array is to small.");
		}
	}

	void IFD_ENTRY::get_as_char(MPT_Exception *exception, char *values, size_t size)
	{
		if(size >= this->number_values){

			if(	this->type->IN_TYPE == IFD_TYPE::ID_ASCII){

				this->buffer->position(exception, this->position_values);
				MPT_EXCEPTION_TEST ;

				this->buffer->get_bytes(exception, values, this->number_values);
				MPT_EXCEPTION_TEST ;

			}
		}
	}

	unsigned int IFD_ENTRY::get_number_values(MPT_Exception * )
	{
		return number_values;
	}
}
