#pragma once
#include <vector>
#include <list>
#include "Star.h"
#include "Point.h"

std::vector<Star> StarSearch(long* searchframe, int xs, int ys, int radius_pct);
void SearchForCoordenates(std::vector<Point>& coordenates, long* frame, int limx, int limy);
void GroupStarCoordenates(std::vector<Point> coordenates, std::vector<Star>& Stars);
bool ContiguousPoints(Point p1, Point p2);
bool ComparePoints(Point p1, Point p2);

/*
	Devuelve un vector de estrellas
*/
std::vector<Star> StarSearch(long* searchframe, int xs, int ys, int radius_pct) {

	//Creamos un vector que contendra todas las estrellas en la imagen
	std::vector<Star> Stars;

	//Localizacion de coordenadas
	std::vector<Point> coordenates;
	SearchForCoordenates(coordenates, searchframe, xs, ys);

	//Agrupacion de coordenadas
	GroupStarCoordenates(coordenates, Stars);

	//Buscamos los parametros de cada estrella
	//Vector para verificar proximidades
	std::list<Star> lp;
	for (std::vector<Star>::iterator itr = Stars.begin(); itr != Stars.end(); itr++) {
		itr->FindParameters();
		lp.push_back(*itr);
	}

#pragma region Verificar cercania de estrellas
	//Verificamos que en un radio de X pixeles del centro de las estrellas no se encuentre otra estrella
	Star s1, s2;
	std::list<Star>::iterator itr;

	do {

		s1 = lp.front();

		itr = lp.begin();
		itr++;

		for (itr; itr != lp.end(); itr++) {
			s2 = *itr;

			if (s1.InRadius(s2.getCenter(), radius_pct) || s2.InRadius(s1.getCenter(), radius_pct)) {
				if (s1.getCoordenates().size() > s2.getCoordenates().size()) {
					//Eliminamos s2 de la lista actual
					itr = lp.erase(itr);
					itr--;
					//Eliminamos s2 del vector de estrellas
					for (vector<Star>::iterator sitr = Stars.begin(); sitr != Stars.end(); sitr++) {
						if (ComparePoints(sitr->getCenter(), s2.getCenter())) {
							Stars.erase(sitr);
							break;
						}
					}
				}
				else {
					//Eliminamos s1 del vector de estrellas
					for (vector<Star>::iterator sitr = Stars.begin(); sitr != Stars.end(); sitr++) {
						if (ComparePoints(sitr->getCenter(), s1.getCenter())) {
							Stars.erase(sitr);
							break;
						}
					}

					break;
				}
			}
		}

		lp.pop_front();

	} while (!lp.empty());
#pragma endregion

#pragma region Checamos margenes
	//Margenes permisibles
	int margin_left = MARGIN;
	int margin_right = xs - MARGIN;
	int margin_top = ys - MARGIN;
	int margin_bottom = MARGIN;

	Point star_center;
	int x, y;

	for (std::vector<Star>::iterator itr = Stars.begin(); itr != Stars.end(); itr++) {

		star_center = itr->getCenter();
		x = star_center.getX();
		y = star_center.getY();

		if (x < margin_left || x > margin_right || y < margin_bottom || y > margin_top) {
			//Esta estrella se encuentra fuera del margen, por lo que no la debemos tomar en cuenta
			itr = Stars.erase(itr);

			if (itr != Stars.begin()) {
				itr--;
			}
		}
	}
#pragma endregion

	return Stars;
}

void SearchForCoordenates(std::vector<Point>& coordenates, long* frame, int limx, int limy) {

	int indx = 0;

	for (int y = 0; y < limy; y++) {
		for (int x = 0; x < limx; x++) {

			indx = x + (y * limx);

			if (frame[indx] != 0) {
				coordenates.push_back(Point(x, y));
			}
		}
	}
}

void GroupStarCoordenates(std::vector<Point> coordenates, std::vector<Star>& Stars) {

	//Creamos un vector de estrella
	vector<Point> star;

	do {

		//Iterador para borrar
		vector<Point>::iterator clr_itr = coordenates.begin();

		star.push_back(coordenates[0]);
		coordenates.erase(clr_itr);

		for (int i = 0; i < star.size(); i++) {
			for (int j = 0; j < coordenates.size(); j++) {
				if (ContiguousPoints(star[i], coordenates[j])) {
					star.push_back(coordenates[j]);
					clr_itr = coordenates.begin();
					coordenates.erase(clr_itr + j);
					j--;
				}
			}
		}

		//Agregamos la estrella y sus puntos al vector de estrellas
		Stars.push_back(Star(star));

		//Limpiamos las coordenadas de la estrella y buscamos la siguiente
		star.clear();

	} while (!coordenates.empty());

}

//Comprueba 2 coordenadas bidimensionales y devuelve TRUE si son contiguas
bool ContiguousPoints(Point p1, Point p2) {

	//Coordenadas de p1
	int p1x = p1.getX();
	int p1y = p1.getY();
	//Coordenadas de p2
	int p2x = p2.getX();
	int p2y = p2.getY();

	if (p1x == p2x) {
		//Misma posicion en X
		if (p1y + 1 == p2y || p1y - 1 == p2y) {
			//p2 arriba o abajo

			return TRUE;
		}
	}
	else if (p1y == p2y) {
		//Misma posicion en Y
		if (p1x + 1 == p2x || p1x - 1 == p2x) {
			//p2 izquierda o derecha

			return TRUE;
		}
	}

	if (p1x + 1 == p2x) {
		//Derecha
		if (p1y + 1 == p2y || p1y - 1 == p2y) {
			//Derecha arriba o abajo

			return TRUE;
		}
	}
	else if (p1x - 1 == p2x) {
		//Izquierda
		if (p1y + 1 == p2y || p1y - 1 == p2y) {
			//Izquierda arriba o abajo

			return TRUE;
		}
	}

	return FALSE;
}

//Compara 2 puntos y devuelve TRUE si son iguales
bool ComparePoints(Point p1, Point p2) {

	if (p1.getX() == p2.getX() && p1.getY() == p2.getY()) {
		return true;
	}
	else {
		return false;
	}

}