#include "FloodFill.h"
#include "BoundingBox.h"


FloodFill::FloodFill()
{
}


FloodFill::~FloodFill()
{
}

int FloodFill::enclosedPixels(const vector<Point>& contourVec, vector<Point> & regionPixels)
{
	volatile int pointsx[] = { 0, 1, 0, -1 };
	volatile int pointsy[] = { -1, 0, 1, 0 };

	stack<Point> st;
	
	Point p = findStartPoint(contourVec);
	regionPixels.push_back(p);
	st.push(p);

	double runs = 0;
	double maxruns = 4000000;

	while (st.size() > 0)
	{
		Point p = st.top();
		st.pop();

		for (int i = 0; i < 4; i++)
		{
			Point check = Point(p.x + pointsx[i], p.y + pointsy[i]);

			if (contains(contourVec, check))
			{
				continue;
			}
			else if (contains(regionPixels, check))
			{
				continue;
			}
			else
			{
				regionPixels.push_back(check);
				st.push(check);
			}
		}

		runs++;

		if (runs > maxruns)
		{
			cout << "Reached max number of runs" << endl;
			break;
		}
	}
	
	//floodfill(contourVec, regionPixels, p);

	return 1;
}

int FloodFill::floodfill(const vector<Point> & contourVec, vector<Point> & regionPixels, Point &p)
{
	//Check four-connected
	volatile int pointsx[] = {0, 1, 0, -1};
	volatile int pointsy[] = {-1, 0, 1, 0};

	for (int i = 0; i < 4; i++)
	{
		Point check = Point(p.x + pointsx[i], p.y + pointsy[i]);
		
		if (check.y < -200)
		{
			cin.get();
		}

		if (contains(contourVec, check))
		{
			continue;
		}
		else if (contains(regionPixels, check))
		{
			continue;
		}
		else
		{
			regionPixels.push_back(check);
			floodfill(contourVec, regionPixels, check);
		}
	}

	return 1;
}

Point FloodFill::findStartPoint(vector<Point> vec)
{
	int maxy = INT_MIN, maxx = INT_MIN, miny = INT_MAX, minx = INT_MAX;

	for (Point p : vec)
	{
		if (p.y > maxy)
			maxy = p.y;

		if (p.y < miny)
			miny = p.y;

		if (p.x > maxx)
			maxx = p.x;

		if (p.x < minx)
			minx = p.x;
	}

	int centery = (maxy + miny) / 2;

	int x1 = 0, x2 = 0;

	//Find left point
	for (int x = minx; x <= maxx; x++)
	{
		if (contains(vec, Point(x, centery)))
		{
			x1 = x;
			break;
		}
	}

	//Find right point
	for (int x = maxx; x >= minx; x--)
	{
		if (contains(vec, Point(x, centery)))
		{
			x2 = x;
			break;
		}
	}

	int centerx = (x1 + x2) / 2;
	Point start = Point(centerx, centery);

	return start;
}

bool FloodFill::contains(vector<Point> vec, Point p)
{
	for (Point pnt : vec)
	{
		if (pnt.x == p.x && pnt.y == p.y)
			return true;
	}

	return false;
}


int FloodFill::split(const vector<vector<Point>> & contours, const Mat &image, string filename)
{
	//Create filenames
	std::string base_filename = filename.substr(filename.find_last_of("/\\") + 1);
	std::string::size_type const p(base_filename.find_last_of('.'));
	std::string name = base_filename.substr(0, p);

	vector<vector<Point>> regions;

	int i = 0; 
	for (vector<Point> contour : contours)
	{
		vector<Point> temp;
		enclosedPixels(contour, temp);
		regions.push_back(temp);
	}

	vector<vector<Point>> bounds;
	BoundingBox::allBoundingBoxes(contours, bounds);

	//Find largest bounding box
	Size largest = Size(0, 0);
	for (vector<Point> box : bounds)
	{
		int height = abs(box[2].y - box[1].y);
		int width = abs(box[1].x - box[0].x);

		if (height > largest.height)
			largest.height = height;
		if (width > largest.width)
			largest.width = width;
	}

	//Create every image
	for (int i = 0; i < contours.size(); i++)
	{

		// Creeer een witte image
		IplImage* iplimage = cvCreateImage(cvSize(largest.width, largest.height), IPL_DEPTH_8U, 3);
		Mat resultImage = cvarrToMat(iplimage);
		resultImage = Scalar(255, 255, 255);

		Point center = Point((bounds[i][0].x + bounds[i][2].x) / 2, (bounds[i][0].y + bounds[i][2].y) / 2);
		int topx = center.x - (largest.width / 2);
		int topy = center.y - (largest.height / 2);

		//Kopieren van pixels
		for (Point p : regions[i])
		{
			resultImage.at<Vec3b>(Point(p.x - topx, p.y - topy)) = image.at<Vec3b>(p);
		}
		for (Point p : contours[i])
		{
			resultImage.at<Vec3b>(Point(p.x - topx, p.y - topy)) = image.at<Vec3b>(p);
		}


		//imshow(name, resultImage);
		imwrite("output/" + name + "_" + to_string(i) + ".bmp", resultImage);
	}

	return 1;
}

int FloodFill::largest(const vector<vector<Point>> & contours, const Mat &image, string filename)
{
	//Create filenames
	std::string base_filename = filename.substr(filename.find_last_of("/\\") + 1);
	std::string::size_type const p(base_filename.find_last_of('.'));
	std::string name = base_filename.substr(0, p);

	vector<vector<Point>> bounds;
	BoundingBox::allBoundingBoxes(contours, bounds);

	//Find largest bounding box
	Size largest = Size(0, 0);
	int total = 0;
	int bin = -1;
	for (int i = 0; i < bounds.size(); i++)
	{
		vector<Point> box = bounds[i];

		int height = abs(box[2].y - box[1].y);
		int width = abs(box[1].x - box[0].x);
		int size = height + width;

		if (height > largest.height)
			largest.height = height;
		if (width > largest.width)
			largest.width = width;

		if (size > total)
		{
			total = size;
			bin = i;
		}
	}

	vector<Point> region;
	enclosedPixels(contours[bin], region);

	// Creeer een witte image
	IplImage* iplimage = cvCreateImage(cvSize(largest.width, largest.height), IPL_DEPTH_8U, 3);
	Mat resultImage = cvarrToMat(iplimage);
	resultImage = Scalar(255, 255, 255);

	Point center = Point((bounds[bin][0].x + bounds[bin][2].x) / 2, (bounds[bin][0].y + bounds[bin][2].y) / 2);
	int topx = center.x - (largest.width / 2);
	int topy = center.y - (largest.height / 2);

	//Kopieren van pixels
	for (Point p : region)
	{
		resultImage.at<Vec3b>(Point(p.x - topx, p.y - topy)) = image.at<Vec3b>(p);
	}
	for (Point p : contours[bin])
	{
		resultImage.at<Vec3b>(Point(p.x - topx, p.y - topy)) = image.at<Vec3b>(p);
	}


	//imshow(name, resultImage);
	imwrite("output/" + name + "_" + to_string(bin) + ".bmp", resultImage);

	return 1;
}