#pragma once


#include "MPT_Exception.h"
#include "MPT_Buffer.h"
#include "IFD_ENTRY.h"


namespace MobilePhotoTool{
	class IFD
	{

	private:
		/**
		 * The position in the buffer.
		 */
		size_t position;

		/**
		 * The input buffer
		 */
		MPT_Buffer *buffer;

		/**
		 * The number of IFD entrys in this IFD.
		 */
		unsigned int numberofEntrys;

		/**
		 * The entry of this IFD
		 */
		IFD_ENTRY **ifd_entrys;

		/**
		 * The number of sub_ifd in this IFD:
		 */
		size_t numberofSub_ifd;

		/**
		 * The array contains all subifds.
		 */
		IFD **sub_ifd;

	public:

		/**
		 * Constructs a new IFD with a given buffer and the position in the buffer.
		 *
		 * @param buffer The input buffer.
		 * @param position The position of this IFD in the buffer.
		 */
		IFD(MPT_Exception *exception, MPT_Buffer *buffer, size_t position);
		
		/**
		 * Read all IFD_ENTRY and stores this in the array ifd_entry[].
		 * If it finds some sub_ifd it starts reading the sub_ifd and stores this 
		 * in the array sub_ifd[].
		 * 
		 * @return The position of the next IFD.
		 * @exception MPT_Exception*
		 */
		size_t read(MPT_Exception *exception );
		

		/**
		 * Search for a IFD_ENTRY in this IFD. Returns the first IFD_ENTRY that it finds.
		 * If it does not find any IFD_ENTRY with this tag, it returns null.
		 * 
		 * @param tag The tag, an example 254 for NewSubfileType.
		 * @return null or the corresponding IFD_ENTRY.
		 */
		IFD_ENTRY *get_IFD_ENTRY(MPT_Exception *exception, int tag);

		/**
		 * @return Returns true if this IFD contains a reduced resolution image. Else it return false.
		 */
		bool is_reduced_resolution(MPT_Exception *exception);

		/**
		 * @return Returns true if this IFD contains the raw image. Else it return false.
		 */
		bool is_raw(MPT_Exception *exception );


		/**
		 * Returns the first IFD that contains a reduce resolution image.
		 * It searchs in all sub ifd too.
		 *
		 * @return The Sub_ifd or NULL.
		 */
		IFD *reduced_resolution_IFD(MPT_Exception *exception );

		/**
		 * Search for raw IFD in this IFD or in all 
		 * sub_ifds. It returns the first it can find or null.
		 * 
		 * @return null or the IFD
		 */
		IFD *raw_IFD(MPT_Exception *exception );

		/**
		 * 
		 * @return The width of this image or 0.
		 */
		unsigned int getImageWidth(MPT_Exception *exception );

		/**
		 * 
		 * @return The length of this image or 0.
		 */
		unsigned int getImageLength(MPT_Exception *exception );

		/**
		 * @return Returns a array of all Bits Per Sample
		 */
		unsigned int *getBitsPerSample(MPT_Exception *exception, size_t *size);
		
		/**
		 * @return Return the PhotometricInterpretation.
		 */
		unsigned int getPhotometricInterpretation(MPT_Exception *exception );

		/**
		 * @return Return the Compress state
		 */
		unsigned int getCompression(MPT_Exception *exception );

		/**
		 * @return The offset to the Strip
		 */
		unsigned int *getStripOffsets(MPT_Exception *exception, size_t *size);

		/**
		 * @return The number of rows per strip.
		 */
		unsigned int getRowsPerStrip(MPT_Exception *exception );

		/**
		 * @return The number of bytes per strip.
		 */
		unsigned int getStripByteCounts(MPT_Exception *exception );

		/**
		 * @return The CFA Layout
		 */
		unsigned int getCFALayout(MPT_Exception *exception );
		
		/**
		 * Care to delete the return pointer.
		 *
		 * @return The pattern for this CFA.
		 */
		unsigned int *getCFAPattern(MPT_Exception *exception, size_t *size);


		/**
		 * The number of Components (Samples) per Pixel.
		 *
		 * @return the number of Components.
		 */
		unsigned int getSamplesPerPixel(MPT_Exception *exception );

		/**
		 * Return a byte array with the raw data.
		 * The caller must free the memory.
		 *
		 * @return array of raw data.
		 */
		unsigned char* getRawData(MPT_Exception *exception );


		/**
		 * Get the raw data from this IFD
		 *
		 * @param length_pos 	The first row
		 * @param num_row	 	The number of rows
		 * @param data The pointer to the memory, where the data should be saved.
		 * @param data_size The size int bytes of memor
		 * @return The number of rows that are readed.
		 */
		unsigned int getRawData_ts(
					MPT_Exception *exception,
					unsigned int length_pos,
					unsigned int num_row,
					unsigned char *data,
					unsigned int data_size);

		/**
		 * Return the DefaultCropOrigin
		 *
		 * @param value is the return value for four unsigned int.
		 */
		void getDefaultCropOrigin(MPT_Exception *exception, unsigned int *value);


		/**
		 * Return the DefaultCropSize
		 *
		 * @param value is the return value for four unsigned int.
		 */
		void getDefaultCropSize(MPT_Exception *exception, unsigned int *value);

		/**
		 *
		 */
		void getAsShotNeutral(MPT_Exception *exception, unsigned int *value);

		/**
		 *
		 */
		void getColorMatrix1(MPT_Exception *exception, float *values);

		/**
		 *
		 */
		void getColorMatrix2(MPT_Exception *exception, float *values);

		/**
		 *
		 */
		void getAnalogBalance(MPT_Exception *exception, float *values);



		~IFD(void);
	};
}
