#include <iostream>
#include "gui/Style.h"
#include "simulation/Simulation.h"
#include "Tool.h"
#include "gui/interface/Window.h"
#include "gui/interface/Button.h"
#include "gui/interface/Label.h"
#include "gui/interface/Textbox.h"
#include "gui/interface/DropDown.h"
#include "gui/game/GameModel.h"

class SignWindow: public ui::Window
{
public:
	ui::DropDown * justification;
	ui::Textbox * textField;
	SignTool * tool;
	sign * movingSign;
	bool signMoving;
	Simulation * sim;
	int signID;
	ui::Point signPosition;
	SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Point position_);
	void OnDraw() override;
	void DoDraw() override;
	void DoMouseMove(int x, int y, int dx, int dy) override;
	void DoMouseDown(int x, int y, unsigned button) override;
	void DoMouseUp(int x, int y, unsigned button) override
	{
		if(!signMoving)
			ui::Window::DoMouseUp(x, y, button);
	}
	void DoMouseWheel(int x, int y, int d) override
	{
		if(!signMoving)
			ui::Window::DoMouseWheel(x, y, d);
	}
	void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override
	{
		if(!signMoving)
			ui::Window::DoKeyPress(key, scan, repeat, shift, ctrl, alt);
	}
	void DoKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override
	{
		if(!signMoving)
			ui::Window::DoKeyRelease(key, scan, repeat, shift, ctrl, alt);
	}
	virtual ~SignWindow() {}
	void OnTryExit(ui::Window::ExitMethod method) override;
	class OkayAction: public ui::ButtonAction
	{
	public:
		SignWindow * prompt;
		OkayAction(SignWindow * prompt_) { prompt = prompt_; }
		void ActionCallback(ui::Button * sender) override
		{
			prompt->CloseActiveWindow();
			if(prompt->signID==-1 && prompt->textField->GetText().length())
			{
				prompt->sim->signs.push_back(sign(prompt->textField->GetText(), prompt->signPosition.X, prompt->signPosition.Y, (sign::Justification)prompt->justification->GetOption().second));
			}
			else if(prompt->signID!=-1 && prompt->textField->GetText().length())
			{
				prompt->sim->signs[prompt->signID] = sign(sign(prompt->textField->GetText(), prompt->signPosition.X, prompt->signPosition.Y, (sign::Justification)prompt->justification->GetOption().second));
			}
			prompt->SelfDestruct();
		}
	};
	class DeleteAction: public ui::ButtonAction
	{
	public:
		SignWindow * prompt;
		DeleteAction(SignWindow * prompt_) { prompt = prompt_; }
		void ActionCallback(ui::Button * sender) override
		{
			prompt->CloseActiveWindow();
			if(prompt->signID!=-1)
			{
				prompt->sim->signs.erase(prompt->sim->signs.begin()+prompt->signID);
			}
			prompt->SelfDestruct();
		}
	};

	class SignTextAction: public ui::TextboxAction
	{
	public:
		SignWindow * prompt;
		SignTextAction(SignWindow * prompt_) { prompt = prompt_; }
		void TextChangedCallback(ui::Textbox * sender) override
		{
			if(prompt->signID!=-1)
			{
				prompt->sim->signs[prompt->signID].text = sender->GetText();
				prompt->sim->signs[prompt->signID].ju = (sign::Justification)prompt->justification->GetOption().second;
			}
		}
	};

	class MoveAction: public ui::ButtonAction
	{
	public:
		SignWindow * prompt;
		MoveAction(SignWindow * prompt_) { prompt = prompt_; }
		void ActionCallback(ui::Button * sender) override
		{
			if(prompt->signID!=-1)
			{
				prompt->movingSign = &prompt->sim->signs[prompt->signID];
				prompt->sim->signs[prompt->signID].ju = (sign::Justification)prompt->justification->GetOption().second;
				prompt->signMoving = true;
			}
		}
	};
};

SignWindow::SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Point position_):
	ui::Window(ui::Point(-1, -1), ui::Point(250, 87)),
	tool(tool_),
	movingSign(NULL),
	signMoving(false),
	sim(sim_),
	signID(signID_),
	signPosition(position_)
{
	ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), "New sign");
	messageLabel->SetTextColour(style::Colour::InformationTitle);
	messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
	messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
	AddComponent(messageLabel);

	ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
	okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
	okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
	okayButton->Appearance.BorderInactive = (ui::Colour(200, 200, 200));
	okayButton->SetActionCallback(new OkayAction(this));
	AddComponent(okayButton);
	SetOkayButton(okayButton);

	ui::Label * tempLabel = new ui::Label(ui::Point(8, 48), ui::Point(40, 15), "Pointer:");
	okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
	okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
	AddComponent(tempLabel);

	justification = new ui::DropDown(ui::Point(52, 48), ui::Point(50, 16));
	AddComponent(justification);
	justification->AddOption(std::pair<String, int>(0xE020 + String(" Left"), (int)sign::Left));
	justification->AddOption(std::pair<String, int>(0xE01E + String(" Middle"), (int)sign::Middle));
	justification->AddOption(std::pair<String, int>(0xE01F + String(" Right"), (int)sign::Right));
	justification->AddOption(std::pair<String, int>(0xE01D + String(" None"), (int)sign::None));
	justification->SetOption(1);
	justification->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;

	textField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 17), "", "[message]");
	textField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
	textField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
	textField->SetLimit(45);
	textField->SetActionCallback(new SignTextAction(this));
	AddComponent(textField);
	FocusComponent(textField);

	if(signID!=-1)
	{
		messageLabel->SetText("Edit sign");

		textField->SetText(sim->signs[signID].text);
		justification->SetOption(sim->signs[signID].ju);

		ui::Point position = ui::Point(justification->Position.X+justification->Size.X+3, 48);
		ui::Button * moveButton = new ui::Button(position, ui::Point(((Size.X-position.X-8)/2)-2, 16), "Move");
		moveButton->SetActionCallback(new MoveAction(this));
		AddComponent(moveButton);

		position = ui::Point(justification->Position.X+justification->Size.X+3, 48)+ui::Point(moveButton->Size.X+3, 0);
		ui::Button * deleteButton = new ui::Button(position, ui::Point((Size.X-position.X-8)-1, 16), "Delete");
		//deleteButton->SetIcon(IconDelete);
		deleteButton->SetActionCallback(new DeleteAction(this));

		signPosition.X = sim->signs[signID].x;
		signPosition.Y = sim->signs[signID].y;

		AddComponent(deleteButton);
	}

	MakeActiveWindow();
}

void SignWindow::OnTryExit(ui::Window::ExitMethod method)
{
	CloseActiveWindow();
	SelfDestruct();
}

void SignWindow::DoDraw()
{
	for (auto &currentSign : sim->signs)
	{
		int x, y, w, h, dx, dy;
		Graphics * g = GetGraphics();

		String text = currentSign.getDisplayText(sim, x, y, w, h);
		g->clearrect(x, y, w+1, h);
		g->drawrect(x, y, w+1, h, 192, 192, 192, 255);
		g->drawtext(x+3, y+3, text, 255, 255, 255, 255);

		if (currentSign.ju != sign::None)
		{
			x = currentSign.x;
			y = currentSign.y;
			dx = 1 - currentSign.ju;
			dy = (currentSign.y > 18) ? -1 : 1;
#ifdef OGLR
			glBegin(GL_LINES);
			glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
			glVertex2i(x, y);
			glVertex2i(x+(dx*4), y+(dy*4));
			glEnd();
#else
			for (int j=0; j<4; j++)
			{
				g->blendpixel(x, y, 192, 192, 192, 255);
				x+=dx;
				y+=dy;
			}
#endif
		}
	}
	if(!signMoving)
	{
		ui::Window::DoDraw();
	}
}

void SignWindow::DoMouseMove(int x, int y, int dx, int dy) {
	if(!signMoving)
		ui::Window::DoMouseMove(x, y, dx, dy);
	else
	{
		ui::Point pos = tool->gameModel->AdjustZoomCoords(ui::Point(x, y));
		if(pos.X < XRES && pos.Y < YRES)
		{
			movingSign->x = pos.X;
			movingSign->y = pos.Y;
			signPosition.X = pos.X;
			signPosition.Y = pos.Y;
		}
	}
}

void SignWindow::DoMouseDown(int x, int y, unsigned button)
{
	if(!signMoving)
		ui::Window::DoMouseDown(x, y, button);
	else
	{
		signMoving = false;
	}
}

void SignWindow::OnDraw()
{
	Graphics * g = GetGraphics();

	g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3);
	g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 200, 200, 200, 255);
}

VideoBuffer * SignTool::GetIcon(int toolID, int width, int height)
{
	VideoBuffer * newTexture = new VideoBuffer(width, height);
	for (int y=0; y<height; y++)
	{
		for (int x=0; x<width; x++)
		{
			pixel pc =  x==0||x==width-1||y==0||y==height-1 ? PIXPACK(0xA0A0A0) : PIXPACK(0x000000);
			newTexture->SetPixel(x, y, PIXR(pc), PIXG(pc), PIXB(pc), 255);
		}
	}
	newTexture->AddCharacter((width/2)-5, (height/2)-5, 0xE021, 32, 64, 128, 255);
	newTexture->BlendCharacter((width/2)-5, (height/2)-5, 0xE020, 255, 255, 255, 255);
	return newTexture;
}

void SignTool::Click(Simulation * sim, Brush * brush, ui::Point position)
{
	int signX, signY, signW, signH, signIndex = -1;
	for (size_t i = 0; i < sim->signs.size(); i++)
	{
		sim->signs[i].getDisplayText(sim, signX, signY, signW, signH);
		if (position.X > signX && position.X < signX+signW && position.Y > signY && position.Y < signY+signH)
		{
			signIndex = i;
			break;
		}
	}
	if (signIndex != -1 || sim->signs.size() < MAXSIGNS)
		new SignWindow(this, sim, signIndex, position);
}