/*
   client/reputationwindow.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#include <iomanip>

#include "ui/paint.h"
#include "ui/ui.h"
#include "client/client.h"
#include "client/reputationwindow.h"
#include "core/reputation.h"
#include "core/range.h"

namespace client {
	
class ReputationBar : public ui::Widget {
public:
	ReputationBar(ui::Widget *parent = 0) : ui::Widget(parent)
	{
		bar_reputation = 0;
		set_border(false);
	}
	
	~ReputationBar()
	{
	}
	
	inline const float reputation() const
	{
	
		return bar_reputation;
	}
	
	void set_reputation(const float reputation)
	{
		bar_reputation = reputation;
	}

protected:
	
	virtual void resize()
	{
		if (parent()) {
			// small hack to keep the bars aligned within the listviewitem if the listview scrollbar appears/dissapears
			const float padding =  ui::root()->font_large()->height();
			set_width(parent()->width() - padding);
		}
	}
	
	virtual void draw()
	{		
		const float box_padding = 4.0f;
		float box_width = floorf((width() - 19.0f * box_padding) / 20.0f);
		if (box_width < 1.0f) {
			box_width =  floorf(width() / 20.0f);
		}
				
		math::Vector2f s(box_width, height());
		const math::Vector2f g (global_location());
		math::Vector2f pos (g);
		
		// draw squares
		math::Color c1;
		math::Color c2;

		for (int i = 0; i < 20; i++) {
			pos[0] = g[0] + floorf (width() / 20.0f * (float) i);			
			if (i < 10) {
				if (bar_reputation <=  (i - 10) * 10.0f ) {
					c1.assign(1.0f, 0.1f * (float) ( i), 0.1f * (float) ( i) );
					c2.assign(1.0f, 0.1f * (float) (i +1), 0.1f * (float) (i + 1));
					ui::Paint::draw_rectangle_gradient(pos, s, c1, c2);
				}
				
			} else {
				if (bar_reputation > (i - 10) * 10.0f) {
					c1.assign(0.1f * (float) (20 - i), 1.0f, 0.1f * (float) (20 - i));
					c2.assign(0.1f * (float) (20 - i + 1), 1.0f, 0.1f * (float) (20 - i + 1));
					ui::Paint::draw_rectangle_gradient(pos, s, c1, c2);
				}
			}
		}
		
		ui::Paint::set_color(palette()->border());
		for (int i = 0; i < 20; i++) {
			pos[0] = g[0] + floorf (width() / 20.0f * (float) i);
			ui::Paint::draw_border(pos, s);
		}
	}

private:
	float		bar_reputation;
};

ReputationWindow::ReputationWindow(ui::Widget *parent) : ui::Window(parent)
{
	reputationwindow_info = 0;
	reputationwindow_info_timestamp = 0;
	reputationwindow_reputation_timestamp = 0;
	
	// window title
	reputationwindow_titlelabel = new ui::Label(this);
	reputationwindow_titlelabel->set_label("title");
	reputationwindow_titlelabel->set_background(false);
	reputationwindow_titlelabel->set_border(false);
	reputationwindow_titlelabel->set_font(ui::root()->font_large());
	reputationwindow_titlelabel->set_alignment(ui::AlignCenter);
	reputationwindow_titlelabel->set_text("REPUTATION");	
	
	// close button
	reputationwindow_closebutton = new ui::IconButton(reputationwindow_titlelabel, "bitmaps/icons/window_close");
	
	// reputation listview
	reputationwindow_listview = new ui::ListView(this);
	reputationwindow_listview->set_label("listview");
	
	// ---- right pane
	reputationwindow_pane_right = new ui::Widget(this);
	reputationwindow_pane_right->set_background(true);
	reputationwindow_pane_right->set_border(true);
	
	// ---- right pane: target label
	reputationwindow_targetlabel = new ui::Label(reputationwindow_pane_right);
	reputationwindow_targetlabel->set_label("info");
	reputationwindow_targetlabel->set_background(false);
	reputationwindow_targetlabel->set_border(false);
	reputationwindow_targetlabel->set_alignment(ui::AlignCenter);	
	
	// ---- right pane: target info
	reputationwindow_scrollpane = new ui::ScrollPane(reputationwindow_pane_right, reputationwindow_infotext);
	reputationwindow_scrollpane->set_background(false);
	reputationwindow_scrollpane->set_border(false);
	reputationwindow_scrollpane->set_alignment(ui::AlignTop);
	
	hide();
}

ReputationWindow::~ReputationWindow()
{
	
}

void ReputationWindow::show()
{
	if (hidden()) {
		reputationwindow_info = 0;
		refresh();
	}
	
	ui::Window::show();
}

void ReputationWindow::refresh()
{
	reputationwindow_listview->clear();
	
	const float padding =  ui::root()->font_large()->height();
	ui::ListItem *selected_listitem = 0;
	
	for (core::Reputation::FactionReps::const_iterator it = core::localplayer()->reputation().factionreps().begin(); it != core::localplayer()->reputation().factionreps().end(); ++it) {
		if ((*it)->faction()) {
			
			std::string strdescription;
			if (roundf((*it)->reputation()) <= core::range::reputation_hostile) {
				strdescription.append("^1");
			} else if (roundf((*it)->reputation()) >= core::range::reputation_friendly) {
				strdescription.append("^2");
			} else {
				strdescription.append("^B");
			}
			strdescription.append((*it)->faction()->name());
			
			ui::ListItem *listitem = new ui::ListItem(reputationwindow_listview, strdescription.c_str());
			listitem->set_alignment(ui::AlignTop | ui::AlignHCenter);
			listitem->set_font(ui::root()->font_tiny());
			listitem->set_height(listitem->font()->height() * 3.5f);
			listitem->set_info((*it)->faction());
			
			std::ostringstream strsortkey;
			strsortkey << std::setfill('0') << std::setw(3) << roundf((*it)->reputation() + 100);
			listitem->set_sortkey(strsortkey.str().c_str());
			
			ReputationBar *bar = new ReputationBar(listitem);
			bar->set_reputation((*it)->reputation());
			bar->set_size(reputationwindow_listview->width() - padding, bar->font()->height());
			bar->set_location( padding * 0.5f, listitem->height() - bar->height() - padding * 0.5f);
			
			if ((*it)->faction() == reputationwindow_info) {
				selected_listitem = listitem;
			}
		}
	}
	
	reputationwindow_listview->sort();
	reputationwindow_listview->event_resize();
	
	reputationwindow_reputation_timestamp = core::localplayer()->reputation().timestamp();
	
	if (selected_listitem) {
		reputationwindow_listview->select(selected_listitem);
		reputationwindow_info = selected_listitem->info();
	} else {
		reputationwindow_info = 0;
	}
	
	set_info(reputationwindow_info);
}

void ReputationWindow::set_info(const core::Info *info)
{
	reputationwindow_infotext.clear();
	reputationwindow_targetlabel->clear();
	reputationwindow_info = info;
	
	if (!info) {
		// player name
		reputationwindow_targetlabel->set_text(core::localplayer()->name());
		
		std::ostringstream  strinfotext;
		
		// player level
		strinfotext.str("");
		strinfotext.clear();
		strinfotext << "^NLevel:         ";
		strinfotext << core::localplayer()->level();
		reputationwindow_infotext.push_back(strinfotext.str());
			
		// player credits
		strinfotext.str("");
		strinfotext.clear();
		strinfotext << "^NCredits:       ";
		strinfotext << core::localplayer()->credits();
		reputationwindow_infotext.push_back(strinfotext.str());
		
		// ------------------
		strinfotext.str("");
		strinfotext.clear();
		reputationwindow_infotext.push_back(strinfotext.str());
		
		// player NPC kills
		strinfotext.str("");
		strinfotext.clear();
		strinfotext << "^NNPC kills:     ";
		strinfotext << core::localplayer()->npckills();
		reputationwindow_infotext.push_back(strinfotext.str());
		
		// player PVP kills
		strinfotext.str("");
		strinfotext.clear();
		strinfotext << "^NPVP kills:     ";
		strinfotext << core::localplayer()->pvpkills();
		reputationwindow_infotext.push_back(strinfotext.str());
		
		// player time wasted
		strinfotext.str("");
		strinfotext.clear();
		strinfotext << "^NTime wasted:   ";
		long time_wasted = (core::localplayer()->time_wasted() + core::game()->timestamp() - core::localplayer()->time_joined()) / 1000;	
		const long time_wasted_seconds = time_wasted % 60;
	
		time_wasted = (time_wasted - time_wasted_seconds) / 60;
		const long time_wasted_minutes = time_wasted % 60;
	
		time_wasted = (time_wasted - time_wasted_minutes) / 60;
		const long time_wasted_hours = time_wasted % 24;
	
		const long time_wasted_days = (time_wasted - time_wasted_hours) / 24;
	
		if (time_wasted_days > 0) {
			strinfotext << time_wasted_days << aux::plural("day", time_wasted_days) << " ";
		}
		strinfotext << std::setfill('0') << std::setw(2) << time_wasted_hours << ":" ;
		strinfotext << std::setfill('0') << std::setw(2) << time_wasted_minutes << ":";
		strinfotext << std::setfill('0') << std::setw(2) << time_wasted_seconds;
		reputationwindow_infotext.push_back(strinfotext.str());
		
		reputationwindow_info_timestamp = 0;
		
	} else {
		core::game()->request_info(info->id());
		
		reputationwindow_targetlabel->set_text(info->name());				
		for (core::Info::Text::const_iterator it = info->text().begin(); it != info->text().end(); it++) {
			reputationwindow_infotext.push_back((*it));
		}
		
		reputationwindow_info_timestamp = info->timestamp();
	}
}

void ReputationWindow::draw()
{
	if (reputationwindow_reputation_timestamp != core::localplayer()->reputation().timestamp()) {
		// refresh window content
		refresh();
		
	} else if (!reputationwindow_info) {
		// update player info
		set_info(0);
			
	} else if (reputationwindow_info_timestamp != reputationwindow_info->timestamp()) {
		// update faction info
		set_info(reputationwindow_info);
	}
	
	ui::Window::draw();
}

void ReputationWindow::resize()
{
	const float padding =  ui::root()->font_large()->height();
	
	// resize label
	reputationwindow_titlelabel->set_size(width() - padding * 2.0f, reputationwindow_titlelabel->font()->height());	
	reputationwindow_titlelabel->set_location(padding, padding);
	
	// resize close button
	reputationwindow_closebutton->set_size(reputationwindow_titlelabel->font()->height(), reputationwindow_titlelabel->font()->height());
	reputationwindow_closebutton->set_location(reputationwindow_titlelabel->width() - reputationwindow_closebutton->width(), 0);
	
	// resize reputation listview
	reputationwindow_listview->set_size(ui::UI::elementsize.width(), height() - reputationwindow_titlelabel->bottom() - padding * 2.0f);
	reputationwindow_listview->set_location(reputationwindow_titlelabel->left(), reputationwindow_titlelabel->bottom() + padding);

	// resize right pane
	reputationwindow_pane_right->set_size(width() - reputationwindow_listview->right() - padding * 2.0f, reputationwindow_listview->height());
	reputationwindow_pane_right->set_location(reputationwindow_listview->right() + padding,reputationwindow_titlelabel->bottom() + padding);
	
	{
		const ui::Widget *pane = reputationwindow_pane_right;
		const float margin_horizontal = pane->font()->width();
		const float margin_vertical = pane->font()->height() * 0.5f;
					
		// resize reputation info label
		reputationwindow_targetlabel->set_size(pane->width() - 2.0f * margin_horizontal, reputationwindow_targetlabel->font()->height());
		reputationwindow_targetlabel->set_location(margin_horizontal, margin_vertical);

		// resize infotext scrollpane
		reputationwindow_scrollpane->set_size(pane->width()- 2.0f * margin_horizontal, pane->height() - reputationwindow_targetlabel->bottom() - 2.0f * margin_vertical);
		reputationwindow_scrollpane->set_location(margin_horizontal, reputationwindow_targetlabel->bottom() + margin_vertical);
	}
}

bool ReputationWindow::on_emit(ui::Widget *sender, const Event event, void *data)
{
	if (event == ui::Widget::EventButtonClicked) {
	
		if (sender == reputationwindow_closebutton) {
			hide();
		}		
		return true;	

		
	} else if (event == ui::Widget::EventListViewChanged) {
		
		if (sender == reputationwindow_listview) {
			set_info( reputationwindow_listview->selected() ? reputationwindow_listview->selected()->info() : 0);
		}
		
		return true;
	}
	
	return Window::on_emit(sender, event, data);
}

bool ReputationWindow::on_keypress(const int key, const unsigned int modifier)
{
	switch (key) {

		case SDLK_ESCAPE:
			this->hide();
			return true;
			break;
			
		default:
			break;
	}

	return Window::on_keypress(key, modifier);
}


} //namespace client