/** @(#) mathpos/statpos.cpp */
/**
* Define las funciones de la cabecera.
*/

#include "statpos.h"

/**
* Cuenta el numero de datos de cada clase en un cierto intervalo
* para un arreglo bidimensional.
* No cuenta datos fuera del rango [leftRange, rightRange].
* Intervalo de la i-esima clase: [left, right).
* @param f Lista de datos 2D. Antes: item.
* @param nr Numero de renglones.
* @param nc Numero de columnas.
* @param leftRange Inicio del intervalo.
* @param rightRange Fin del intervalo.
* @param pClassMark return.
* Uso: float *pClassMark = new float[bins];
* Almacena las marcas de clase.
* @param pFreq return.
* Uso: long *pFreq = new long[bins];
* Almacena las frecuencias absolutas.
* @param bins Numero de clases en el histograma.
* @throws invalid_argument IllegalArgumentException
* No se puede contar frecuencias.
*/
void countFrequency2D(float **f, int nr, int nc,
		float leftRange, float rightRange,
                float *pClassMark, long *pFreq, int bins)
                throw (invalid_argument) {
	// Inicializa
	//[bins + 1]
	float *pClassFrontier = new float[bins + 1];
	int i, j, b;
        float elem;


	// Valida (bins < 1) || (leftClass >= rightClass)
        calculateClassMarks(bins, leftRange, rightRange, pClassMark);
        calculateClassFrontiers(bins, leftRange, rightRange, pClassFrontier);
	vectorToZero(pFreq, bins);	

        // Clasifica cada dato
	// Se incluye el borde.
        for (i = 0; i < nr; ++i) {
        	for (j = 0; j < nc; ++j) {
			elem = f[i][j];	// optimizado
			// si el dato, esta fuera a la izq, se salta
			if (elem < pClassFrontier[0]) {
				continue;
			}
			// si el dato es menor que la superior, termina
			for (b = 0; b < bins; ++b) {
				//right = pClassFrontier[b + 1];
				if (elem < pClassFrontier[b + 1]) {
					++(pFreq[b]);
					break;
				}
			}
			// Si hubo break no debe entrar
			// Si no quedo en el ultimo,
			// Checa el extremo
			if ((b == bins) && (elem <= rightRange)) {
				++(pFreq[bins - 1]);
			}
		} // for j
        } // for i
	// Libera memoria
        delete []pClassFrontier;
}

/**
* Cuenta el numero de datos de cada clase en un cierto intervalo
* para un arreglo bidimensional normalizados a 1.0.
* No cuenta datos fuera del rango [leftRange, rightRange].
* Intervalo de la i-esima clase: [left, right).
* @param f Lista de datos 2D. Antes: item.
* @param nr Numero de renglones.
* @param nc Numero de columnas.
* @param leftRange Inicio del intervalo.
* @param rightRange Fin del intervalo.
* @param pClassMark return.
* Uso: float *pClassMark = new float[bins];
* Almacena las marcas de clase.
* @param pRelFreq return.
* Uso: long *pRelFreq = new long[bins];
* Almacena las frecuencias relativas.
* @param bins Numero de clases en el histograma.
* @throws invalid_argument IllegalArgumentException
* No se puede contar frecuencias.
*/
void relativeFrequency2D(float **f, int nr, int nc,
		float leftRange, float rightRange,
                float *pClassMark, float *pRelFreq, int bins)
                throw (invalid_argument) {
	// Encuentra el histograma
	long *pFreq = new long[bins];
	countFrequency2D(f, nr, nc, leftRange, rightRange,
                pClassMark, pFreq, bins);

	if (pRelFreq == NULL) {
		throw invalid_argument("No hay datos");
	}

	// Suma las frecuencias
        float sum = 0;
	int i;
	for (i = 0; i < bins; ++i) {
        	sum += static_cast<float>(pFreq[i]);
	}
        // Relativo
	for (i = 0; i < bins; ++i) {
        	pRelFreq[i] = static_cast<float>(pFreq[i]) / sum;
	}

	delete []pFreq;
}


/**
* Busca las marcas de clase.
* @param bins Numero de clases en el histograma.
* @param leftRange Inicio del intervalo.
* @param rightRange Fin del intervalo.
* @param pClassMark return. Uso: float *pClassMark = new float[bins];
* Cada renglon tiene la marca de clase.
* @throws invalid_argument IllegalArgumentException
* No se puede contar frecuencias.
*/
void calculateClassMarks(int bins, float leftRange, float rightRange,
		float *pClassMark)
                throw (invalid_argument) {
	if ( (bins < 1) || (leftRange >= rightRange) ) {
		throw invalid_argument(
				"No se pueden crear marcas de clase.");
	}

	float interval = rightRange - leftRange; // =8
	float base = interval / bins;  // base de la barra

	//Inicia de izq a der
	pClassMark[0] = leftRange + (base / 2.0);
        int i;
	for (i = 1; i < bins; ++i) {
	     pClassMark[i] = pClassMark[i - 1] + base;
        }
}

/**
* Busca las fronteras entre las marcas de clase.
* @param bins Numero de clases en el histograma.
* @param leftRange Inicio del intervalo.
* @param rightRange Fin del intervalo.
* @param pClassFrontier return.
* Uso: float *pClassFrontier = new float[bins + 1];
* Cada renglon tiene la frontera de clase.
* @throws invalid_argument IllegalArgumentException
* No se puede contar frecuencias.
*/
void calculateClassFrontiers(int bins, float leftRange, float rightRange,
		float *pClassFrontier)
                throw (invalid_argument) {
			// ejem: 4, -4, 4
	if ( (bins < 1) || (leftRange >= rightRange) ) {
		throw invalid_argument(
                	"No se pueden crear las fronteras de clase.");
	}

	float interval = rightRange - leftRange; // =8
	float base = interval / bins;  // base de la barra

	//Inicia de izq a der
	pClassFrontier[0] = leftRange;
        int i;
	for (i = 1; i < bins; ++i) {
		pClassFrontier[i] = pClassFrontier[i - 1] + base;
	}
	// Ajusta la ultima
	pClassFrontier[bins] = rightRange;
}

//template <class TObj>
// constructor, ~, friend-----------------------------------------------------
/* Constructor predeterminado. */
/** Construye. */

/* Destructor predeterminado. */
/** Libera recursos. */

// operator-------------------------------------------------------------------

// public---------------------------------------------------------------------

// private--------------------------------------------------------------------

/**
*
* @param
* @param
* @return
* @see paq1.paq2.MyClass#MyMethod(int,Object)
* @throws Exception
*/

/**
* Se incluye el borde.
*/
void calculateMeanMinMax2D(float **f, int nr, int nc,
		double &mean, float &min, float &max) {
        double sum = 0.0;
        float elem;
        min = max = f[0][0];

        int i, j;

	// Se incluye el borde.
        for (i = 0; i < nr; ++i) {
        	for (j = 0; j < nc; ++j) {
                	elem = f[i][j];
			sum += elem;
                	if (elem < min) {
				min = elem;
			} else if (f[i][j] > max) {
                        	max = elem;
                        }
                }
        }
        mean = sum / (nr * nc);
}

/**
* Se incluye el borde.
*/
void findMinMax2D(float **f, int nr, int nc, float &min, float &max) {
        float elem;
        min = max = f[0][0];

        int i, j;

	// Se incluye el borde.
        for (i = 0; i < nr; ++i) {
        	for (j = 0; j < nc; ++j) {
                	elem = f[i][j];
                	if (elem < min) {
				min = elem;
			} else if (f[i][j] > max) {
                        	max = elem;
                        }
                }
        }
}

/**
* @param pRelFreq Arreglo con las frecuencias relativas.
* @param pCumFreq Arreglo con las frecuencias acumuladas.
*/
void cumulativeFrequency(float *pRelFreq, int bins, float *pCumFreq) {
	int i;
       	pCumFreq[0] = pRelFreq[0];
	for (i = 1; i < bins; ++i) {
        	pCumFreq[i] = pCumFreq[i - 1] + pRelFreq[i];
        }
}

// Fin------------------------------------------------------------------------