#pragma once

//#include <cstdlib>
#include <stdlib.h>
#include "MobilePhoteTool_IFD.h"
#include "Mathe.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;
	};

	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} demosaik;

		demosaik demosaik_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];

		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);

	private:
		static void *get_zoom_image_02(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 *);

	private:

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