//
// File: Button.cpp
// Created by: Alexander Oster - tensor@ultima-iris.de
//
/*****
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*****/

#include "gui/Button.h"
#include "gui/Container.h"
#include "gui/Label.h"
#include "gui/GUIHandler.h"
#include "Debug.h"
#include "Config.h"
#include <cassert>

using namespace std;

namespace GUI {

Button::Button ()
{
	//Image::Image ();
	m_destPage = 0;
	m_isPageSelector = false;
	for (int i = 0; i < 3; i++)
		m_button_gump[i] = 0;
	m_pressed = 0;
	SetFlag (GUMPFLAG_MOVABLE, false);
	m_onclick_message.type = MESSAGE_NONE;
	m_callback_OnClick = NULL;
	control_type = CONTROLTYPE_BUTTON;

	m_pressed = false;
	m_mouseover = false;
	m_checked = false;
	
	m_label = NULL;
	m_type  = BUTTONTYPE_BUTTON;

	m_groupid = 0;
	m_orderid = 0;
}

Button::Button (int x, int y, int w, int h)
{
	//Image::Image (x, y, 0);
	m_destPage = 0;
	m_isPageSelector = false;
	for (int i = 0; i < 3; i++)
		m_button_gump[i] = 0;
	SetPosition (x, y);
	SetSize(w, h);
	m_pressed = false;
	m_mouseover = false;
	OnClick (NULL);
	SetFlag (GUMPFLAG_MOVABLE, false);
	control_type = CONTROLTYPE_BUTTON;

	m_pressed = false;
	m_mouseover = false;
	m_checked = false;

	m_label = NULL;
	m_type  = BUTTONTYPE_BUTTON;

	m_groupid = 0;
	m_orderid = 0;

	m_direct_onclick = false;
}

Button::~Button ()
{
	delete m_label;
}

void Button::SetGump (int type, int gump)
{
	if ((type >= 0) && (type < 3))
		m_button_gump[type] = gump;
}

int Button::GetGump (int type) const
{
	if ((type >= 0) && (type < 3))
		return m_button_gump[type];
	return 0;
}

void Button::SetClickMessage (gui_message * msg)
{
	m_onclick_message = *msg;
}

void Button::OnClick (int (*callback) (Control * sender))
{
	m_callback_OnClick = callback;
}

bool Button::IsPageSelector (void) const
{
	return m_isPageSelector;
}

void Button::SetPageSelector (bool sel)
{
	m_isPageSelector = sel;
}

void Button::SetDestinationPage (int dp)
{
	m_destPage = dp;
}

int Button::GetDestinationPage (void) const
{
	return m_destPage;
}

int Button::GetCurGump() const
{
	int gump = BUTTONGUMP_NORMAL;
	
	if (m_type != BUTTONTYPE_BUTTON)
		gump = m_checked ? BUTTONGUMP_PRESSED : BUTTONGUMP_NORMAL;
	else if (m_pressed)
		gump = BUTTONGUMP_PRESSED;
	else if (m_mouseover)
		gump = BUTTONGUMP_MOUSEOVER;

	return m_button_gump[gump];
}

void Button::Draw (GumpHandler * gumps)
{
	Control::Draw (gumps);

	int g = GetCurGump();
	Texture *texture = LoadGump (g, gumps, false);

	int x = GetX(), y = GetY(), w = 0, h = 0;

	if (texture)
	{
		w = texture->GetRealWidth (), h = texture->GetRealHeight ();
		if (GetWidth() == 0 || GetHeight() == 0)
			SetSize (w, h);
		
		DrawRect (x, y, texture, GetAlpha ());
	}

	if (m_label && m_type != BUTTONTYPE_BUTTON)
	{
		m_label->SetPosition(x + w + 10, y);
		m_label->Draw(gumps);
	}
}

void Button::SetPressed (int pressed)
{
	m_pressed = pressed;
}

int Button::GetPressed (void) const
{
	return m_pressed;
}

int Button::HandleMessage (gui_message * msg)
{
	gui_message new_message;
	switch (msg->type)
	{
	case MESSAGE_MOUSEDOWN:
		if (MouseIsOver (msg->mouseevent.x, msg->mouseevent.y))
		{
			m_pressed = true;
			
			//if (m_type == BUTTONTYPE_BUTTON) m_pressed = true;
			
			if ((!GetFocus ()))
			{
				new_message.type = MESSAGE_SETFOCUS;
				new_message.windowaction.controlid = GetID ();
				stack.Push (new_message);
			}
			return true;
		}
		else if (GetFocus ())
		{
			new_message.type = MESSAGE_RELEASEFOCUS;
			new_message.windowaction.controlid = GetID ();
			stack.Push (new_message);
		}
		break;
	case MESSAGE_MOUSEMOTION:
		if (MouseIsOver (msg->mousemotionevent.x, msg->mousemotionevent.y))
		{
			if (msg->mousemotionevent.button)
				m_pressed = true;
			m_mouseover = true;
			return true;
		}
		else
		{
			m_pressed = false;
			m_mouseover = false;
		}
		break;
	case MESSAGE_MOUSEUP:
		if (MouseIsOver (msg->mouseevent.x, msg->mouseevent.y) && m_pressed)
		{
			if (m_onclick_message.type != MESSAGE_NONE)
				stack.Push (m_onclick_message);

			if (IsDirectOnClick())
				DoOnClick();
			else
				stack.Push (CreateCallbackMessage (CALLBACK_ONCLICK));

			m_pressed = false;
			m_mouseover = false;
			

			//SetChecked(!m_checked);
#if 1
			if (m_type == BUTTONTYPE_CHECKBOX)
				m_checked = !m_checked;
			else 
			if (m_type == BUTTONTYPE_RADIO && !IsChecked())
			{
				Button *btn = GetSelectedButton();
				if (btn) btn->SetChecked(false);
				
				m_checked = true;

#if 0
				//now uncheck all other radios in group:
				ControlList_t *list = NULL;
				ControlList_t::iterator iter;

				Container *parent = dynamic_cast<Container*>(GetParent());

				if (parent == NULL)
					list = pUOGUI.GetControlList ();
				else
					list = parent->GetControlList ();


				for (iter = list->begin (); iter != list->end (); iter++)
				{
					if (dynamic_cast<Button*>(iter->second) && iter->second->GetID() != GetID())
					{
						Button *r = (Button*)iter->second;
						if (r->GetGroupID () == GetGroupID ())
							r->SetChecked (false);
					}
				}
#endif
			}
#endif

			return true;
		}
		m_pressed = false;
		m_mouseover = false;
		break;
	default:
		Control::HandleMessage (msg);
	}
	return false;
}

void Button::SetChecked(bool checked) 
{
	if (m_checked == checked) return;

	if (m_type != BUTTONTYPE_RADIO) 
	{
		m_checked = checked; 
		return;
	}
	
	if (!m_checked)
	{
		Button *btn = GetSelectedButton();
		if (btn) btn->SetChecked(false);
	}

	m_checked = checked;
}

int Button::GetRadioIndex() const
{
	Button *btn = ((Button*)this)->GetSelectedButton();
	return btn ? btn->GetOrderID() : -1;
}

void Button::SetRadioIndex(int index)
{
	/*Button *btn = GetSelectedButton();
	if (btn) btn->SetChecked(true);*/

	ControlList_t *list = NULL;
	ControlList_t::iterator iter;

	Container *parent = dynamic_cast<Container*>(GetParent());

	if (parent == NULL)
		list = pUOGUI.GetControlList ();
	else
		list = parent->GetControlList ();

	Button *btn = NULL;
	
	for (iter = list->begin (); iter != list->end (); iter++)
	{
		btn = dynamic_cast<Button*>(iter->second);
		if (btn && btn->GetGroupID() == GetGroupID())
			btn->m_checked = (btn->m_orderid == index);
	}
}

Button *Button::GetSelectedButton()
{
	ControlList_t *list = NULL;
	ControlList_t::iterator iter;

	Container *parent = dynamic_cast<Container*>(GetParent());

	if (parent == NULL)
		list = pUOGUI.GetControlList ();
	else
		list = parent->GetControlList ();

	Button *btn = NULL;
	
	for (iter = list->begin (); iter != list->end (); iter++)
	{
		btn = dynamic_cast<Button*>(iter->second);
		if (btn && btn->GetGroupID() == GetGroupID() && btn->IsChecked()) return btn;
	}

	return NULL;
}

bool Button::CheckPixel (int x, int y)
{
	int w = GetWidth(), h = GetHeight();

	if (w > 0 && h > 0) return x < w && y < h;

	int gump = GetCurGump();
	
	Texture *texture = LoadGump (gump, &pGumpHandler, false);

	if (texture)
		return texture->CheckPixel (x, y);
	
	return true;
}

void Button::DoOnClick (void)
{
	if (m_callback_OnClick)
		m_callback_OnClick (this);
}


void Button::SetTitle(const char *text, int align, int hue, int font)
{
	delete m_label;
	m_label = new Label(0, 0, text, align, font);
	m_label->setHue(hue);
	//m_label->SetScriptFunction(FUNC_ONCLICK, GetScriptFunction(FUNC_ONCLICK));
}

const char *Button::GetTitle() const
{
	return m_label ? m_label->text() : "";
}

void Button::SetButtonType(int type)
{
	m_type = type;
}

void Button::SetButtonType(std::string type)
{
	const char *types[] =  {"button", "checkbox", "radio" };
	m_type = str2enum(type, types, 3, m_type);
}

}
