//
// This source code is property of the Computer Graphics and Visualization
// chair of the TU Dresden. Do not distribute in modified or unmodified form!
// Copyright (C) 2016 CGV TU Dresden - All Rights Reserved
//
#include "non_recursive_fill_tool.h"
#include <deque>

#include <iostream>

// Initialize the tool and store a reference of a canvas_buffer
non_recursive_fill_tool::non_recursive_fill_tool(canvas_buffer &canvas) : tool_base(canvas)
{
	// This tool has no shape and is not draggable
	shape = TS_NONE;
	is_draggable = false;
}

// A pixel to be put into the queue of pixels to process
struct waiting_pixel
{
	waiting_pixel(int x, int y) : x(x), y(y) {}
	waiting_pixel() : x(0), y(0) {}

	int x, y;
};

void print_point(int x, int y)
{
	std::cout << "point (" << x << ", " << y << ")" << std::endl;
}

void non_recursive_fill_tool::draw(int x, int y)
{
	waiting_pixel p;
	std::deque<waiting_pixel> stack;

	/************
	Task 3.2.2.    Implement a filling algothim without recursion. Use a stack instead.
				   The source code below inserts the first element into the stack and
				   starts a loop that reads the front element from the stack and removes
				   it. Your task is to fill the functionality in the loop. Before you begin
				   think about when to set the pixel (at the beginning of the loop or after
				   the stack was updated with neighbours). Use "canvas.set_pixel" to set
				   a pixel and "canvas.get_pixel" to read the state of a pixel.
    Aufgabe 3.2.2. Implementieren Sie einen F�llalgorithmus ohne Rekursion zu verwenden.
	               Nutzen Sie stattdessen einen Stack. Der vorgegebene Quelltext unten fuegt
				   das erste Element in den Stack ein und startet eine Schleife, die das
				   vorderste Element aus dem Stack liest und es anschlie�end entfernt.
				   Ihre Aufgabe ist es die Funktionalitaet im Inneren der Schleife zu
				   ergaenzen. Bevor Sie beginnen machen Sie sich Gedanken an welcher Stelle
				   das tatsaechliche Setzen eines Pixels erfolgt (am Beginn der Schleife oder
				   nachdem der Stack mit Nachbarinformationen aktualisiert wurde). Nutzen
				   Sie "canvas.set_pixel" um einen Pixel zu setzen und "canvas.get_pixel" um
				   den Zustand eines Pixels zu erhalten.
   *************/

	// Put the initial pixel into the stack
	if (!canvas.get_pixel(x, y))
	{
		p.x = x;
		p.y = y;
		stack.push_back(p);
	}

	// While there are pixels to be checked
	while (!stack.empty())
	{
		int x = stack.front().x;
		int y = stack.front().y;
		// Complete the algorithm here

		if (!canvas.get_pixel(x, y))
		{
			canvas.set_pixel(x, y);

			// add neighbours with bounds check
			if (x > 0)
			{
				stack.emplace_back(x - 1, y);
			}

			if (y > 0)
			{
				stack.emplace_back(x, y - 1);
			}

			if (y < canvas.get_height() - 1)
			{
				stack.emplace_back(x, y + 1);
			}

			if (x < canvas.get_width() - 1)
			{
				stack.emplace_back(x + 1, y);
			}
		}

		stack.pop_front();
	}
}

// Put debug output into the stream "stream" to be displayed in the
// main window
void non_recursive_fill_tool::set_text(std::stringstream &stream)
{
	stream << "Tool: Non-Recursive Fill (click to fill)";
}