#include "Bias.h"
#include <iostream>
#include <omp.h>
#include "taos.h"

Bias::Bias() {
	master = NULL;
}

Bias::Bias(string name):Calibration(name){
	master = NULL;
}

Bias::~Bias() {
	if (data) {
		std::cout << "Liberando BIAS data ... ";
		free(data);
		data = NULL;
		std::cout << "Done \n";
	}
	if (master) {
		std::cout << "Liberando BIAS MASTER data ... ";
		free(master);
		master = NULL;
		std::cout << "Done \n";
	}
}

void Bias::ObtainMaster() {
	//Apartamos memoria para guardar la informacion de BIAS
	long int * ptrmaster = master;
	ptrmaster = (long int*)calloc(Xs * Ys, sizeof(long int));
	int xs = Xs;
	int ys = Ys;
	int xys = xs * ys;
	int frames = Frames;
	int row;
	int pixel;
	std::list<long> pixel_list;

	std::cout << "Bias Master ... ";

	//Recorremos Y's
#pragma omp parallel for shared(ptrmaster, xs, ys, frames, xys) private(pixel_list, row, pixel) num_threads(THREADNUM)
	for (int py = 0; py < ys; py++)
	{

		row = py * xs;

		//Recorremos X's
		for (int px = 0; px < xs; px++)
		{
			pixel = px + row;

			//Recorremos cada Frame
			for (int frm = 0; frm < frames; frm++)
			{
				//Guardamos el dato del frame en una lista
				pixel_list.push_back(data[pixel + (frm * xys)]);
			}

			//Ordenamos la lista para sacar la mediana
			pixel_list.sort();
			ptrmaster[pixel] = getMedian(pixel_list);
			//*(ptrmaster + px + (py * xs)) = getMedian(pixel_list);

			//Una vez que tenemos la mediana agregada limpiamos la lista para continuar con el siguiente pixel
			pixel_list.clear();
		}
	}

	master = ptrmaster;
	ptrmaster = NULL;

	std::cout << "Done" << std::endl;
}

long* Bias::getMaster() {
	//Regresa un puntero hacia MASTER BIAS, que es donde se encuentra toda la informacion del archivo MASTER BIAS
	return master;
}

void Bias::free_data() {
	if (data) {
		std::cout << "Liberando Bias data ... ";
		free(data);
		data = NULL;
		std::cout << "Done" << std::endl;
	}
}

void Bias::free_Master() {
	if (master) {
		std::cout << "Liberando Bias Master ... ";
		free(master);
		master = NULL;
		std::cout << "Done" << std::endl;
	}
}

void Bias::PrintMasterData(int limx, int limy) {

	std::cout << "\t" << "Master Data \n";
	std::cout << "\t" << filename << "\n";

	//Recorremos Y's
	for (int py = 0; py < limy; py++)
	{
		//Recorremos X's
		for (int px = 0; px < limx; px++)
		{
			std::cout << "[" << px << "]" << "[" << py << "]" << "[1]:" << master[px + (py * Xs)] << "\n";
		}
	}

	std::cout << "\n\n";
}

//Lectura de archvio master
void Bias::setMaster(string masterfile) {
	std::cout << "Lectura de Masterfile BIAS " << masterfile;

	//Conversion de string a char[] para funcion de fits_open_file
	char* file = new char[masterfile.size() + 1];
	masterfile.copy(file, masterfile.size() + 1);
	file[masterfile.size()] = '\0';

	//Abrimos el archivo
	if (fits_open_file(&fptr, file, READONLY, &status)) {
		fits_report_error(stderr, this->status); //Imprime error de status
		exit(EXIT_FAILURE);
	}

	//Declaramos desde donde queremos comenzar a leer la imagen en fpixel:
	long fpixel[] = { 1, 1, 1 };

	//Debemos obtener el total de pixeles que contiene la imagen y la cantidad de frames del archivo
	long int nelements = Xs;	//Pixeles a leer por renglon

	//Debemos tener cuidado con que tipo de datos declaramos el master y con que tipo de dato leemos el archivo
	master = (long int*)calloc(Xs * Ys, sizeof(long int));
	long int* tempdata = (long int*)calloc(nelements, sizeof(long int));

	//nulval se de clara como short -1 y anynul se trabaja con un int 0, datatype para leer TULONG
	short nulval = -1;

	//Recorremos cada renglon
	for (int j = 1; j <= nelements; j++)
	{
		fpixel[1] = j;

		if (fits_read_pix(this->fptr, TLONG, fpixel, nelements, &nulval, tempdata, 0, &status)) {
			fits_report_error(stderr, this->status); //Imprime error de status
			exit(EXIT_FAILURE);
		}

		for (int k = 0; k < nelements; k++)
		{
			*(master + ((j - 1) * nelements) + k) = tempdata[k];
		}
	}

	//Cerramos el archivo
	if (fits_close_file(fptr, &status)) {
		fits_report_error(stderr, this->status); //Imprime error de status
		exit(EXIT_FAILURE);
	}

	free(tempdata);
	delete file;

	std::cout << "Done \n\n";
}

void Bias::setNewBias(string newbias) {
	if (master) {
		free(master);
		master = NULL;
	}

	Calibration::setNewFile(newbias);
}

void Bias::setNullMaster(int xs, int ys) {

	int indx;
	master = (long*)calloc(xs * ys, sizeof(long));

	for (int py = 0; py < ys; py++) {
		
		indx = py * xs;

		for (int px = 0; px < xs; px++) {
			master[px + indx] = 0;
		}
	}

}