#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "MPT_Exception.h"
#include "threadwrap.h"

namespace MobilePhotoTool{

	class MPT_Buffer
	{

	public:
		/** 
		 * How to read the input file.
		 * 
		 */
		enum Endian
		{ 
				BigEndian, /**< Read a BigEndian file */  
				LittleEndian, /**< Read a LittleEndian file */   
		}; 	

	private:
		/**
		 * The order of this buffer
		 */
		Endian order;

		/**
		 * The inputstream
		 */
		FILE *file;

		/**
		 * The size of this file in byte;
		 */
		size_t size;

		/**
		 * Synchronize the the buffer by multiple thread access
		 */
		MPT_THREAD_MUTEX_T *mutex;

	public:

		/**
		 * Create a new Buffer the default reading methode is
		 * BigEndian
		 *
		 * @param path The String must contain the path to a file
		 * @exception MPT_Exception The exception will be thrown, if the path is not valid.
		 */
		MPT_Buffer(MPT_Exception *exception, const char *path);

		/**
		 * Get the current position of the buffer.
		 * 
		 * @return Current position.
		 */
		size_t position(MPT_Exception *exception);

		/**
		 * The function sets a new position 
		 *
		 * @param position The The new position.
		 * @exception MPT_Exception If the position out of range
		 */
		void position(MPT_Exception *exception, const size_t position);

		/**
		 * The function sets the order 
		 * 
		 * @param endian BigEndian or LittleEndian
		 */
		void set_order(MPT_Exception *exception, Endian endian);

		/**
		 * Read a short.
		 *
		 * @return unsigned short value
		 */
		unsigned short get_ushort(MPT_Exception *exception);


		/**
		 * Read a unsigned int.
		 *
		 * @return unsigned int value
		 */
		unsigned int get_uint(MPT_Exception *exception);

		/**
		 * Read a int.
		 *
		 * @return int value
		 */
		int get_int(MPT_Exception *exception);

		/**
		 * Read a byte
		 *
		 * @return unsigned byte value;
		 */
		unsigned char get_ubyte(MPT_Exception *exception);

		/**
		 * The size of the inputstream in bytes.
		 *
		 * @return The size of the inputstream in bytes.
		 */
		size_t get_size(MPT_Exception *exception);


		/**
		 * Read count number of bytes writes int data.
		 * The variable data has to point to a large enough memory area.
		 *
		 * @param data The data area where the bytes ara written.
		 * @param count The maximale number of bytes to read.
		 * @return unsigned int The number of byte that a real read;
		 */
		size_t get_ubytes(MPT_Exception *exception, unsigned char *data, size_t count);

		/**
		 * Read count number of bytes writes int data.
		 * The variable data has to point to a large enough memory area.
		 *
		 * @param data The data area where the bytes ara written.
		 * @param count The maximale number of bytes to read.
		 * @return unsigned int The number of byte that a real read;
		 */
		size_t get_bytes(MPT_Exception *exception, char *data, size_t count);


		/**
		 * Threadsave function to read a short.
		 *
		 * @param position The position in the buffer.
		 * @param *value The return value from the buffer;
		 * @return the number off bytes read
		 */
		size_t get_ushort_ts(MPT_Exception *exception, unsigned short *value, unsigned long position);


		/**
		 * Read a unsigned int.
		 *
		 * @param postion The position in the buffer.
		 * @return The number off bytes, that are readed.
		 */
		size_t get_uint_ts(MPT_Exception *exception, unsigned int *value, unsigned long position);

		/**
		 * Read a int.
		 *
		 * @param value The int that is read.
		 * @param postion The position in the buffer
		 * @return the number off bytes read
		 */
		size_t get_int_ts(MPT_Exception *exception, int *value, unsigned long position);

		/**
		 * Read a byte
		 *
		 * @param value The byte that is read
		 * @param postion The position in the buffer
		 * @return the number off bytes read
		 */
		size_t get_ubyte_ts(MPT_Exception *exception, unsigned char *value, unsigned long position);


		/**
		 * Read count number of bytes writes int data.
		 * The variable data has to point to a large enough memory area.
		 *
		 * @param data The data area where the bytes ara written.
		 * @param count The maximale number of bytes to read.
		 * @param postion The position in the buffer
		 * @return  The number of byte that a real read;
		 */
		size_t get_ubytes_ts(MPT_Exception *exception, unsigned char *data, size_t count, unsigned long position);

		/**
		 * Read count number of bytes writes int data.
		 * The variable data has to point to a large enough memory area.
		 *
		 * @param postion The position in the buffer
		 * @param data The data area where the bytes ara written.
		 * @param count The maximale number of bytes to read.
		 * @return The number of byte that a real read;
		 */
		size_t get_bytes_ts(MPT_Exception *exception, char *data, size_t count, unsigned long position);

		~MPT_Buffer(void);
	};
}
