#include "Mathe.h"

namespace MobilePhotoTool{

	Mathe::Mathe(void)
	{
	}


	Mathe::~Mathe(void)
	{
	}

	float Mathe::det_matrix_2x2(const float matrix[4])
	{
		float det = 0.f;

		det = matrix[0] * matrix[3] - matrix[1] * matrix[2];

		return det;
	}

	float Mathe::det_matrix_3x3(const float matrix[9])
	{
		float det = 0.f;

		det =	matrix[0] * matrix[4] * matrix[8] + 
				matrix[1] * matrix[5] * matrix[6] +
				matrix[2] * matrix[3] * matrix[7] -
				matrix[0] * matrix[5] * matrix[7] -
				matrix[1] * matrix[3] * matrix[8] -
				matrix[2] * matrix[4] * matrix[6];
			

		return det;
	}


	void Mathe::invers_matrix3x3(const float in_matrix[9], float out_matrix[9])
	{
		float temp_matrix1[9], temp_matrix2[4], det_in;
		int i_pos1, k_pos1, i_length1, k_length1, i_pos2, k_pos2,  i_pos3, k_pos3, i_length3, k_length3;
	
		for(i_pos1 = 0; i_pos1 < 9; i_pos1 += 1){
			temp_matrix1[i_pos1] = 0;
		}

		i_length1 = 3;
		k_length1 = 3;

		i_length3 = i_length1 - 1;
		k_length3 = k_length1 - 1;

		det_in = det_matrix_3x3(in_matrix);

		if(det_in != 0){
			for(i_pos1 = 0; i_pos1 < i_length1; i_pos1 += 1){
				for(k_pos1 = 0; k_pos1 < k_length1; k_pos1 += 1){
					for(i_pos2 = 0, i_pos3 = 0; i_pos2 < i_length1; i_pos2 += 1){
						if(i_pos2 != i_pos1){
							for(k_pos2 = 0, k_pos3 = 0; k_pos2 < k_length1; k_pos2 += 1){
								if(k_pos2 != k_pos1){
									temp_matrix2[i_pos3 * k_length3 + k_pos3] = in_matrix[i_pos2 * k_length1 + k_pos2];  
									k_pos3 += 1;
								}
							}
							i_pos3 += 1;
						}
					}
					temp_matrix1[i_pos1 * i_length1 + k_pos1] = det_matrix_2x2(temp_matrix2);
					if((i_pos1 + k_pos1) % 2 == 1){
						temp_matrix1[i_pos1 * i_length1 + k_pos1] *= -1.0f;
					}

					temp_matrix1[i_pos1 * i_length1 + k_pos1] /= det_in;
				}
			}
		}

		for(i_pos1 = 0; i_pos1 < i_length1; i_pos1 += 1){
			for(k_pos1 = 0; k_pos1 < k_length1; k_pos1 += 1){
				out_matrix[i_pos1 * k_length1 + k_pos1] = temp_matrix1[k_pos1 * k_length1 + i_pos1];
			}
		}
	}

	void Mathe::mul_matrix3x3(const float in1_matrix[9], const float in2_matrix[9], float out_matrix[9])
	{
		int i_pos1, k_pos1, size, pos;
		float temp, tempMatrix[9];
		size = 3;

		for(k_pos1 = 0; k_pos1 < size; k_pos1 += 1){
			for(i_pos1 = 0; i_pos1 < size; i_pos1 += 1){
				temp = 0.0f;
				for(pos = 0 ; pos < size; pos +=1 ){
					temp += in1_matrix[k_pos1 * size + pos] * in2_matrix[pos * size + i_pos1];
				}
				tempMatrix[k_pos1 * size + i_pos1] = temp;
			}
		}

		for(i_pos1 = 0; i_pos1 < 9; i_pos1 += 1){
			out_matrix[i_pos1] = tempMatrix[i_pos1];
		}
	}

	void Mathe::mul_matrix3x3_vector(const float in1_matrix[9], const float in2_vector[3], float out_vector[3])
	{
		int k_pos1, i_pos1, k_length1, i_length1;
		float temp;

		k_length1 = 3;
		i_length1 = 3;

		for(k_pos1 = 0; k_pos1 < k_length1; k_pos1 += 1){
			temp = 0.0f;
			for(i_pos1 = 0; i_pos1 < i_length1; i_pos1 += 1){
				temp += in1_matrix[k_pos1 * i_length1 + i_pos1] * in2_vector[i_pos1];
			}
			out_vector[k_pos1] = temp;
		}
	}

	void Mathe::normal_matrix3x3(float in_out_matrix[9], float value, float out_vector[3])
	{
		int k_pos1, k_length1, i_length1;
		float *row, *end, value1;
		k_length1 = i_length1 = 3;

		for(k_pos1 = 0; k_pos1 < k_length1; k_pos1 += 1){
			row = &in_out_matrix[k_pos1 * i_length1];
			end = row + i_length1;
			value1 = 0.0f;
			for(;row < end; row += 1){
				value1 += *row;
			}
			if(out_vector != NULL){
				out_vector[k_pos1] = value / value1;
			}
			row = &in_out_matrix[k_pos1 * i_length1];

			for(;row < end; row += 1){
				*row = value * *row/ value1;
			}
		}
	}

	void Mathe::min_max_vector3(float vector[3], float *min, float *max)
	{
		int size;

		*min = vector[0];
		*max = vector[0];
		size = 3;
		for(int i = 1; i < size; i += 1){
			if(*min > vector[i]){
				*min = vector[i];
			}
			if(*max < vector[i]){
				*max = vector[i];
			}
		}
	}

	void Mathe::scalar_vector3(float vector[3], float scalar)
	{
		int pos, size;
		size = 3;
	
		for(pos = 0; pos < size; pos += 1){
			vector[pos] *= scalar;
		}
	}

	float Mathe::gamma(float in)
	{
		if(in <= 0.018){
			return in * 4.5f;
		}else{
			return 1.099f * pow(in, 0.45f) - 0.099f; 
		}
	}



}
