/*  $Id: messagebox_generic.cpp,v 1.37 2004/01/03 21:43:00 sphair Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
**
*/

#include "precomp.h"
#include "messagebox_generic.h"
#include "API/GUI/stylemanager.h"
#include "API/Display/display.h"
#include "API/Display/font.h"
#include "API/Core/XML/dom_element.h"
#include "API/Core/Resources/resourcetype_integer.h"
#include "API/Core/Resources/resourcetype_boolean.h"

// private namespace for constants
namespace {
	int const space_between_buttons = 10;
	int const space_between_title_and_text = 10;
	int const space_between_text_and_buttons = 20;
	int const space_between_buttons_and_bottom = 10;
	int const space_between_text_and_left_edge = 10;
	int const space_between_text_and_right_edge = 10;
} // end of private namespace for constants

CL_MessageBox_Generic::CL_MessageBox_Generic(
	CL_MessageBox *self,
	const std::string &title,
	const std::string &text,
	const std::string &button1,
	const std::string &button2,
	const std::string &button3)
:
	text(text),
	messagebox(self),
	result_button(-1)
{
	CL_ResourceManager * resources = messagebox->get_style_manager()->get_resources();
	font = new CL_Font("MessageBox/font", resources);

	bool is_fixed_size_buttons = CL_Boolean("MessageBox/fixed_size_buttons", resources, false);
	int min_button_width = CL_Integer("MessageBox/min_button_width", resources, 80);
	int min_button_height = CL_Integer("MessageBox/min_button_height", resources, 20);

	int width = CL_Integer("MessageBox/min_width", resources, 400);
	int height = 0;

	messagebox->set_title(title);

	// We need to know how many space get client_area in 
	// CL_Window, and then we can calculate offsets from edges
	CL_Rect const msgbox_rc(
		CL_Display::get_width()  / 2 - 400 / 2,
		CL_Display::get_height() / 2 - 400 / 2,
		CL_Display::get_width()  / 2 + 400 / 2,
		CL_Display::get_height() / 2 + 400 / 2);

	messagebox->set_position(msgbox_rc);

	CL_Rect const client_area_rc = messagebox->get_client_area()->get_position();

	// Now calculate edges offsets
	int const left_edge_offset   = client_area_rc.left;
	int const top_edge_offset    = client_area_rc.top;
	int const right_edge_offset  = msgbox_rc.right - client_area_rc.right - msgbox_rc.left;
	int const bottom_edge_offset = msgbox_rc.bottom - client_area_rc.bottom - msgbox_rc.top;

	int num_buttons = 0;
	if (!button1.empty())
		num_buttons = 1;
	if (!button2.empty())
		num_buttons = 2;
	if (!button3.empty())
		num_buttons = 3;

	height += space_between_title_and_text + space_between_text_and_buttons;
	int const btn_pos_y = height;
	height += space_between_buttons_and_bottom;

	switch(num_buttons)
	{
	case 1:
		{
			if (is_fixed_size_buttons)
			{
				button[0] = new CL_Button(CL_Point(width / 2, btn_pos_y), button1,
					messagebox->get_client_area());
				if (button[0]->get_width() > min_button_width)
					min_button_width = button[0]->get_width();
				if (button[0]->get_height() > min_button_height)
					min_button_height = button[0]->get_height();

				button[0]->set_width(min_button_width);
				button[0]->set_height(min_button_height);
			}
			else
			{
				button[0] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button1,
					messagebox->get_client_area());
			}

			if (width < button[0]->get_width())
				width = button[0]->get_width();

			width += space_between_text_and_left_edge + space_between_text_and_right_edge;
			
			button[0]->set_position(
				width / 2 - button[0]->get_width() / 2,
				btn_pos_y);

			slot_button[0] = button[0]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 0);

			// add buttons height to height
			height += button[0]->get_height();
		}
		break;
	case 2:
		{
			if (is_fixed_size_buttons)
			{
				button[0] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button1,
					messagebox->get_client_area());
				button[1] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button2,
					messagebox->get_client_area());
				
				// calculate min width and height of buttons,
				// if some button is bigger than min size
				for(int i = 0; i < 2; ++i)
				{
					if (button[i]->get_width() > min_button_width)
						min_button_width = button[i]->get_width();
					if (button[i]->get_height() > min_button_height)
						min_button_height = button[i]->get_height();
				}
				// set buttons size to max width and height.
				// and use 'j' for msvc workaround :(
				for(int j = 0; j < 2; ++j)
				{
					button[j]->set_width(min_button_width);
					button[j]->set_height(min_button_height);
				}
			}
			else
			{
				button[0] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button1,
					messagebox->get_client_area());
				button[1] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button2,
					messagebox->get_client_area());
			}

			int const total_buttons_size =
				button[0]->get_width() +
				space_between_buttons  +
				button[1]->get_width();

			if (width < total_buttons_size)
				width = total_buttons_size;

			width += space_between_text_and_left_edge + space_between_text_and_right_edge;

			button[0]->set_position(
				width / 2 - total_buttons_size / 2,
				btn_pos_y);
			button[1]->set_position(
				width / 2 - total_buttons_size / 2 +
				button[0]->get_width() + space_between_buttons,
				btn_pos_y);

			slot_button[0] = button[0]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 0);
			slot_button[1] = button[1]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 1);

			// add buttons height to height
			height += button[0]->get_height();
		}
		break;
	case 3:
		{
			if (is_fixed_size_buttons)
			{
				button[0] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button1,
					messagebox->get_client_area());
				button[1] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button2,
					messagebox->get_client_area());
				button[2] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button3,
					messagebox->get_client_area());
				
				// calculate min width and height of buttons,
				// if some button is bigger than min size
				for(int i = 0; i < 3; ++i)
				{
					if (button[i]->get_width() > min_button_width)
						min_button_width = button[i]->get_width();
					if (button[i]->get_height() > min_button_height)
						min_button_height = button[i]->get_height();
				}
				// set buttons size to max width and height
				for(int j = 0; j < 3; ++j)
				{
					button[j]->set_width(min_button_width);
					button[j]->set_height(min_button_height);
				}
			}
			else
			{
				button[0] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button1,
					messagebox->get_client_area());
				button[1] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button2,
					messagebox->get_client_area());
				button[2] = new CL_Button(
					CL_Point(width / 2, btn_pos_y),
					button3,
					messagebox->get_client_area());
			}

			int const total_buttons_size =
				button[0]->get_width() + space_between_buttons +
				button[1]->get_width() + space_between_buttons +
				button[2]->get_width();

			if (width < total_buttons_size)
				width = total_buttons_size;
			
			width += space_between_text_and_left_edge + space_between_text_and_right_edge;

			button[0]->set_position(
				width / 2 - total_buttons_size / 2, btn_pos_y);
			button[1]->set_position(
				width / 2 - total_buttons_size / 2 +
				button[0]->get_width() + space_between_buttons,
				btn_pos_y);
			button[2]->set_position(
				width / 2 - total_buttons_size / 2 +
					button[0]->get_width() + space_between_buttons +
					button[1]->get_width() + space_between_buttons,
				btn_pos_y);

			slot_button[0] = button[0]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 0);
			slot_button[1] = button[1]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 1);
			slot_button[2] = button[2]->sig_clicked().connect(
				this, &CL_MessageBox_Generic::on_button, 2);

			// add buttons height to height
			height += button[0]->get_height();
		}
		break;
	}

 	button_count = num_buttons;
 
	// Calc and set real dialog position
	width += left_edge_offset + right_edge_offset;
	height += top_edge_offset + bottom_edge_offset;
	
	// Calculating height of text
	int text_height = font->get_height(text,
		CL_Size(width - space_between_text_and_left_edge -
			space_between_text_and_right_edge,
			0));

	height += text_height;

	// Repositioning buttons to reflect text height
	for(int i = 0; i < button_count; ++i)
	{
		CL_Rect rc = button[i]->get_position();
		button[i]->set_position(rc.left, rc.top + text_height);
	}

	messagebox->set_position(CL_Rect(
		CL_Display::get_width()  / 2 - width / 2,
		CL_Display::get_height() / 2 - height / 2,
		CL_Display::get_width()  / 2 + width / 2,
		CL_Display::get_height() / 2 + height / 2));

	slot_end_paint = messagebox->get_client_area()->sig_end_paint().connect(
		this, &CL_MessageBox_Generic::on_end_paint);
}

CL_MessageBox_Generic::~CL_MessageBox_Generic()
{
	delete font;
	for(int i = 0; i < button_count; i++)
		delete button[i];
}

void CL_MessageBox_Generic::on_button(int button)
{
	result_button = button;
	messagebox->quit();
}

void CL_MessageBox_Generic::on_end_paint()
{
	CL_Rect text_rect = messagebox->get_client_area()->get_position();

	text_rect.left   += space_between_text_and_left_edge;
	text_rect.right  -= space_between_text_and_right_edge;
	text_rect.top    += space_between_title_and_text;
	// don't need to modify bottom, because text wasn't changed, so
	// it shouldn't overwrite buttons

	font->draw(text_rect, text);
}

