/*
**  ClanLib SDK
**  Copyright (c) 1997-2005 The ClanLib Team
**
**  This software is provided 'as-is', without any express or implied
**  warranty.  In no event will the authors be held liable for any damages
**  arising from the use of this software.
**
**  Permission is granted to anyone to use this software for any purpose,
**  including commercial applications, and to alter it and redistribute it
**  freely, subject to the following restrictions:
**
**  1. The origin of this software must not be misrepresented; you must not
**     claim that you wrote the original software. If you use this software
**     in a product, an acknowledgment in the product documentation would be
**     appreciated but is not required.
**  2. Altered source versions must be plainly marked as such, and must not be
**     misrepresented as being the original software.
**  3. This notice may not be removed or altered from any source distribution.
**
**  Note: Some of the libraries ClanLib may link to may have additional
**  requirements or restrictions.
**
**  File Author(s):
**
**    Magnus Norddahl
**    (if your name is missing here, please add it)
*/

#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_screen_rect();

	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);
}

