#include "button.h"
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_primitives.h>
#include "color.h"
#include <memory>
#include "wrappers.h"

using namespace std;

static const int BUTTON_MARGIN = 8; //TODO: add to skin

double Button::getPreferredWidth()
{
	return BUTTON_MARGIN + al_get_text_width(sfont, text.c_str());
}

void Button::doDraw (const GraphicsContext &gc)
{
	Bitmap dst = Bitmap(gc.buffer);

	// get the button state
	int state = Disabled() ? 2 : (Selected() ? 1 : (HasFocus() ? 3 : 0));

	int x1 = getx() + gc.xofst;
	int y1 = gety() + gc.yofst;
	int x2 = x1 + w;
	int y2 = y1 + h;

	int displacement = pressed ? GetSkin()->buttonDisplacement : 0;

    // copied from MASkinG
	if (border) {
		border.TiledBlit(dst, 0, state, x1, y1, w, h, 1, 4);
	}

	if (icon) {
		//TODO: state vs icon...
		al_draw_bitmap_region(icon, 0, state * h, w, h, 0, 0, 0);
	}

//	al_draw_filled_rectangle(x1, y1, x2, y2, enabled ? BLACK : GREY);


    al_draw_text (sfont, (enabled ? DARK_GREY : LIGHT_GREY),
        (x2 + x1) / 2 + displacement, (y2 + y1 - al_get_font_line_height(sfont)) / 2 + displacement, ALLEGRO_ALIGN_CENTRE,
		text.c_str());

    if (hasFocus())
    {
    	//TODO
    	// replace with border function
     //   dotted_rect (gc.buffer, x, y, x + w - 1, y + h - 1, BLACK);
    	al_draw_rectangle (x1 + 3, y1 + 3, x2 - 3, y2 - 3, GREEN, 1.0);
    }
}

/*
void Button::draw(const GraphicsContext &gc)
{
	// get the button state
	int state = Disabled() ? 2 : (Selected() ? 1 : (HasFocus() ? 3 : 0));

	// get the button colors and font
	Color fg = GetFontColor(state);
	Color bg = GetShadowColor(state);
	Font f = GetFont(state);

	// update the size if necessary
	UpdateSize();

	// Draw the button

	if (text) {
		// Calculate the position of the text
		int text_x = w()/2 - 1;
		int text_y = (h() - f.TextHeight())/2 - 1;

		// Displace the text a little when the button is down
		if (state == 1) {
			text_x += skin->buttonDisplacement;
			text_y += skin->buttonDisplacement;
		}

		// Print the text
		f.GUITextoutEx(canvas, text, text_x, text_y, fg, bg, GetTextMode(), 2);
	}

	// draw the dotted rectangle
	if (skin->drawDots && HasFocus() && !TestFlag(D_AUTOSIZE) && text) {
		canvas.DrawDottedRect(3, 3, w()-3, h()-3, fg);
	}

}
*/

/**
guibutton message handler
*/
void Button::handleEvent(ALLEGRO_EVENT &event)
{
	switch (event.type)
	{
		case ALLEGRO_EVENT_TWIST_MOUSE_LEAVE_WIDGET:
		{
			if (!isToggleButton())
			{
				if (Selected()) Deselect();
			}
		}
			break;
		case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
			if (!isEnabled()) break;
			if (isToggleButton())
			{
				Toggle();
			}
			else
			{
				Select();
			}
			break;
		case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
			if (Selected())
			{
				doAction();
			}
			if (!isToggleButton())
			{
				Deselect();  //TODO - also when mouse exits... // guarantee exit event
			}
			break;
		case ALLEGRO_EVENT_KEY_CHAR:
		{
			if (!isEnabled()) break;
			switch (event.keyboard.keycode)
			{
				case ALLEGRO_KEY_SPACE: case ALLEGRO_KEY_ENTER:
					if (isToggleButton())
					{
						Toggle();
					}
					doAction();
					break;
			}
			break;
		}
    }
}

void Button::doAction()
{
	if (actionFunc) { actionFunc(); }
	else pushMsg(action);
}

void Button::handleMessage(std::shared_ptr<IComponent> src, int msg)
{
	// for component, unfocus means that "awake" and "visible" are set to false. -> This should be the meaning for Layer...
	// for Button, focus means that component is highlighted.
	switch (msg)
	{
	case MSG_FOCUS:
		setFocus(true);
		break;
	case MSG_UNFOCUS:
		setFocus(false);
		break;
	}
}

ComponentBuilder<Button> Button::build(int action, std::string text, ALLEGRO_BITMAP* icon)
{
	return ComponentBuilder<Button>(make_shared<Button>(action, text, icon));
}

void Button::Setup (int x, int y, int w, int h, int scancode, int msg, const char *label) { assert(false); /* TODO */ }
void Button::MakeExit() { /* TODO */ } // make this button exit the dialog
