#pragma once

//#include <cstdlib>
#include <stdlib.h>
#include "MobilePhoteTool_IFD.h"
#include "Mathe.h"
#include "short_buffer.h"
#include "Raw_Processor_implC.h"

#define VIRTUAL

namespace MobilePhotoTool{
	class Raw_Processor;

	struct zoomer{
		unsigned int from;
		unsigned int to;
		float factor;
	};

	struct struct_mul_matrix_function_variable_1{
		unsigned short 	*comp0;
		unsigned short 	*comp1;
		unsigned short 	*comp2;
		int					start_row;
		int					number_row;
		int					start_col;
		int					number_col;
		int					linestride;
		float				*matrix;
	};

	class demosaik_AHD_variable{
		public:
			bool creater;
			MPT_THREAD_T thread;
			int start_row;
			int number_row;
			int block_size;
			int filter_extra_size;
			demosaik_AHD_variable();
			~demosaik_AHD_variable();
			Raw_Processor *thiss;
			MPT_Exception  *exception;

			/**
			 * buffer[0]	v_green_0
			 * buffer[1]	h_green_0
			 * buffer[2]	v_green_3
			 * buffer[3]	h_green_3
			 * buffer[4]	v_blue_0
			 * buffer[5]	h_blue_0
			 * buffer[6]	v_blue_1
			 * buffer[7]	h_blue_1
			 * buffer[8]	v_blue_2
			 * buffer[9]	h_blue_2
			 * buffer[10]	v_red_1
			 * buffer[11]	h_red_1
			 * buffer[12]	v_red_2
			 * buffer[13]	h_red_2
			 * buffer[14]	v_red_3
			 * buffer[15] 	h_red_3
			 *
			 * buffer[16] 	red_0
			 * buffer[17]	green_1
			 * buffer[18]	green_2
			 * buffer[19]	blue_3
			 *
			 */
			short_buffer *buffer[20];

			int_buffer *i_buffer[6];

			uchar_buffer *homo_map[2];

			float *lut;

			int *maximum_read;
			int *pos_read;
			void set_maximum_read_length(unsigned int maximum);
			MPT_THREAD_MUTEX_T	*read_write_mutex;
			MPT_THREAD_COND_T	*start_reading_cond;

			int *number_off_threads;
			int *arrieved_thread;
			MPT_THREAD_MUTEX_T	*arrieved_threads_mutex;
			MPT_THREAD_COND_T	*all_threads_start_cond;
/*
			void init( int block_size,
						int filter_extra_size,
						Raw_Processor *thiss,
						MPT_Exception  *exception,
						int *maximum_read,
						int *pos_read,
						MPT_THREAD_MUTEX_T	*read_write_mutex,
						MPT_THREAD_COND_T	*start_reading_cond,
						int *number_off_threads,
						int *arrieved_thread,
						MPT_THREAD_MUTEX_T	*arrieved_threads_mutex,
						MPT_THREAD_COND_T	*all_threads_start_cond);
*/
			void init(int block_size,
						int filter_extra_size,
						int number_off_threads_in,
						Raw_Processor *thiss,
						MPT_Exception  *exception);

			void init(	demosaik_AHD_variable *variable);

			bool get_next_block();
			void wait_for_all_threads();
			void set_variable_demosaic_AHD(variable_demosaic_AHD *variable);

	};

	struct struct_get_zoom_imager_02{
		Raw_Processor	*thiss;
		MPT_Exception	*exception;
		unsigned short	*data_out;
		unsigned int	linestride;
		unsigned int	width;
		unsigned int	length;
		unsigned int	out_x0;
		unsigned int	out_y0;
		unsigned int	in_x0;
		unsigned int	in_y0;
	};


	class Raw_Processor
	{

	protected:

		typedef enum{BILINEAR, AHD} demosaik;

		demosaik demosaic_type;

		/**
		 * The IFD that contains the raw data.
		 */
		IFD *raw_ifd;

		/**
		 * The first ifd.
		 */
		IFD *ifd0;

		/**
		 * The complete width of data.
		 */
		unsigned int width;

		/**
		 * The complete length of data;
		 */
		unsigned int length;

		/**
		 * The size of the finish image
		 */
		unsigned int cropSize[4];

		/**
		 * The origin of the finish image in the Raw image
		 */
		unsigned int cropOrigin[4];

		/**
		 * The size of the output image
		 */
		unsigned int zoomsize[2];

		/**
		 * The output image
		 */
		unsigned int *outputimage;


		/**
		 * Current zoom factor
		 */
		float zoomfactor;

		struct zoomer *zooms;
		unsigned int zoomssize;

		/**
		 *
		 */
		unsigned int outputimage_linestride;

		/**
		 * The number of components.
		 */
		unsigned int number_components;

		/**
		 * The pointer to the pixel.
		 *  data[component][pixel]
		 */
		pixeltype **pixel;

		/**
		 * The linestride for one row.
		 * The linestride for every componente;
		 */
		unsigned int *linestride;


		/**
		 * This variable points to the first valid value
		 * in the pixelarray. pixel[component][start_pointer[component]]
		 */
		unsigned int *start_pointer;

		/**
		 * The histrogramm for the components;
		 */
		unsigned int **histogramm;

		/**
		 * Histogramm size.
		 */
		static const unsigned int histogramm_size = 1 << 12;

		/**
		 * The percent of pixel that failed in the hight area
		 */
		static const float failPixel;

		static const float RGBtoXYZ[9];

		/**
		 *
		 */
		float RGB_white_point[4];

		float factor[3];

		float CamtoRGB[9];

		float CamtoXYZ[9];

		pixeltype gamme_curve[pixeltypeMAX];

	public:
		/**
		 * Construct a new Raw Processor with the given rawifd
		 *
		 * @param rawifd must be a valid ifd with the raw data
		 */
		Raw_Processor(MPT_Exception *exception, IFD *, IFD *ifd0);

		/**
		 * init special CPU GPU stuff.
		 */
		VIRTUAL void init(MPT_Exception *exception);

		/**
		 * Creates a Raw Processor and used the optimal Processor
		 */
		//static Raw_Processor *create_Raw_Processor(MPT_Exception *exception, IFD *raw_ifd, IFD *ifd0);


		VIRTUAL ~Raw_Processor(void);

		/**
		 *	Copy the current Raw data in the data array
		 *
		 * %param data The output array
		 * %param size The size of the data array.
		 */
		void updata_RGB(MPT_Exception *exception, unsigned int *data, size_t size);

		/**
		 * %return the raw width
		 */
		unsigned int get_Width(MPT_Exception *exception);

		/**
		 * %return the raw length.
		 */
		unsigned int get_Length(MPT_Exception *exception);

		/**
		 * %return the zoomimage width
		 */
		unsigned int get_ZoomWidth(MPT_Exception *exception);

		/**
		 * %return the zoomimage length.
		 */
		unsigned int get_ZoomLength(MPT_Exception *exception);

		/**
		 * set the new zoom image
		 *
		 * %param zoom must < 1.0
		 * %param size size is the new zoomedimage size.
		 */
		VIRTUAL void set_zoom(MPT_Exception *exception, float zoom, unsigned int size[2]);

		VIRTUAL void get_zoom_image(	MPT_Exception *exception,
										unsigned int *data_out,
										unsigned int linestride,
										unsigned int width,
										unsigned int length,
										unsigned int out_x0,
										unsigned int out_y0,
										unsigned int in_x0,
										unsigned int in_y0);

		VIRTUAL void get_zoom_image(	MPT_Exception	*exception,
										unsigned short	*data_out,
										unsigned int	linestride,
										unsigned int	width,
										unsigned int	length,
										unsigned int	out_x0,
										unsigned int	out_y0,
										unsigned int	in_x0,
										unsigned int	in_y0);

		float *get_CamtoXYZ();

		unsigned short *get_pixel_pointer(int componente, int row);

		int get_pixel_linestride(int componente);
	private:
		static void *get_zoom_image_02(void *in);
		static void *get_zoom_image_03(void *in);


	protected:

		/**
		 *	init common stuff like picture size
		 */
		void init(MPT_Exception *exception, IFD *raw_ifd, IFD *ifd0);

		/**
		 *
		 */
		VIRTUAL void createBuffer(MPT_Exception *exception);

		/*
		 * Calculate the a basic RGB image
		 */
		void basicPipline(MPT_Exception *exception);


		static void zoom_line(pixeltype *in, unsigned *out, unsigned int size, float factor, unsigned int shift);
		static void zoom_row(unsigned *in, unsigned *out, unsigned linestride_in, unsigned linestride_out, unsigned size, float factor);
		static void zoom_row(unsigned *in, unsigned short *out, unsigned linestride_in, unsigned linestride_out, unsigned size, float factor);
		void write_ppm();

		/**
		 *	Decode the raw Data and stores the components in the raw array.
		 */
		void loadRaw(MPT_Exception *exception);

		/**
		 * The number of components.
		 */
		unsigned int get_number_components(MPT_Exception *exception);

		/**
		 * Update the histogramm with the current data
		 */
		void updata_histogramm(MPT_Exception *exception);

		/**
		 * Start the demosaikprocess.
		 */
		void start_demosaik(MPT_Exception *exception);

		/**
		 * Bilinear interpolation of green.
		 */
		void bilinear_green_01(MPT_Exception *exception);

		/**
		 * Bilinear interpolateion of red
		 */
		void billinear_red_01(MPT_Exception *exception);

		/**
		 * Bilinear interpolateion of blue
		 */
		void billinear_blue_01(MPT_Exception *exception);

		void set_white_point(MPT_Exception *exception);

		/**
		 * Create the matrix CameraToXYZ
		 */
		void create_CameraToXYZ(MPT_Exception *exception);

		/**
		 *
		 */
		void mul_matrix(float matirx[9]);

		void setup_gammacurve(pixeltype white);

		void gamma_correction(MPT_Exception *);

		/**
		 * Replace loadRaw and start_demosaik
		 */
		void demosaik_AHD(MPT_Exception *exception);

	private:

		static void* mul_matrix_02(void* in);
		static void* updata_histogramm_02(void *in);

		void mul_matrix_03(float matrix[9]);
		void set_data(unsigned short in);

		static void *demosaik_AHD_start_thread(void *obj);
		static void *loadRaw_thread(void *obj);


	};
}
