/*
 * Copyright (C) 2002-2004, 2006-2007 by the Widelands Development Team
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <vector>
#include "building.h"
#include "building_statistics_menu.h"
#include "error.h"
#include "graphic.h"
#include "i18n.h"
#include "interactive_player.h"
#include "player.h"
#include "productionsite.h"
#include "rendertarget.h"
#include "tribe.h"
#include "ui_button.h"
#include "ui_progressbar.h"
#include "ui_textarea.h"
#include "tribe.h"
#include "wui_plot_area.h"

#define BUILDING_LIST_HEIGHT 220
#define BUILDING_LIST_WIDTH  320

#define LOW_PROD 25

#define UPDATE_TIME 1000  // 1 second, real time

/*
===============
Building_Statistics_Menu::Building_Statistics_Menu

Create all the buttons etc...
===============
*/
Building_Statistics_Menu::Building_Statistics_Menu
(Interactive_Player & parent, UI::UniqueWindow::Registry & registry)
:
UI::UniqueWindow(&parent, &registry, 400, 400, _("Building Statistics")),
m_parent(&parent),

m_table
(this,
 (get_inner_w() - BUILDING_LIST_WIDTH) / 2, 30,
 BUILDING_LIST_WIDTH, BUILDING_LIST_HEIGHT)

{

   // First, we must decide about the size
   int spacing=5;
   int offsx=spacing;
   int offsy=30;
   int posx=offsx;
   int posy=offsy;

   // Building list
	m_table.add_column(_("Name"), 160);
	m_table.add_column(_("Prod"),  40);
	m_table.add_column(_("Owned"), 40);
	m_table.add_column(_("Build"), 40);
   m_table.selected.set(this, &Building_Statistics_Menu::table_changed);

   posy += BUILDING_LIST_HEIGHT + 2*spacing;
   m_end_of_table_y = posy;

   // let place for Picture
   posx = get_inner_w() / 4 + spacing;

   // Toggle when to run button
   UI::Textarea* ta = new UI::Textarea(this, posx, posy, get_inner_w()/4, 24, _("Total Productivity: "), Align_CenterLeft );
   m_progbar = new UI::Progress_Bar(this, posx + ta->get_w() + spacing, posy, get_inner_w() - ( posx + ta->get_w() + spacing) - spacing, 24, UI::Progress_Bar::Horizontal);
   m_progbar->set_total(100);
   posy += 25;

   // owned
   new UI::Textarea(this, posx, posy, get_inner_w()/4, 24, _("Owned: "), Align_CenterLeft);
	m_owned = new UI::Textarea
		(this, posx+ta->get_w(), posy, 100, 24, Align_CenterLeft);

	m_btn[Prev_Owned] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 58, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_left.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Prev_Owned,
		 _("Snow previous"),
		 false);

	m_btn[Next_Owned] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 29, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_right.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Next_Owned,
		 _("Snow next"),
		 false);

   posy += 25;

   // build
   new UI::Textarea(this, posx, posy, get_inner_w()/4, 24, _("In Build: "), Align_CenterLeft);
	m_build = new UI::Textarea
		(this, posx+ta->get_w(), posy, 100, 24, Align_CenterLeft);

	m_btn[Prev_Construction] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 58, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_left.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Prev_Construction,
		 _("Snow previous"),
		 false);

	m_btn[Next_Construction] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 29, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_right.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Next_Construction,
		 _("Snow next"),
		 false);

   posy += 25;

   // Jump to unproductive
   new UI::Textarea(this, posx, posy, get_inner_w()/4, 24, _("Jump to unproductive: "), Align_CenterLeft);

	m_btn[Prev_Unproductive] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 58, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_left.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Prev_Unproductive,
		 _("Snow previous"),
		 false);

	m_btn[Next_Unproductive] = new UI::IDButton<Building_Statistics_Menu, Jump_Targets>
		(this,
		 get_inner_w() - 29, posy, 24, 24,
		 4,
		 g_gr->get_picture(PicMod_UI, "pics/scrollbar_right.png"),
		 &Building_Statistics_Menu::clicked_jump, this, Next_Unproductive,
		 _("Snow next"),
		 false);

   posy += 25;

   // TODO: help button
	new UI::Button<Building_Statistics_Menu>
		(this,
		 spacing, get_inner_w() - 37, 32, 32,
		 0,
		 g_gr->get_picture(PicMod_Game, "pics/menu_help.png"),
		 &Building_Statistics_Menu::clicked_help, this);

   m_lastupdate = m_parent->get_game()->get_gametime();
   m_anim = 0;
   update();

   m_last_building_index = 0;
}

/*
===============
Building_Statistics_Menu::~Building_Statistics_Menu

Unregister from the registry pointer
===============
*/
Building_Statistics_Menu::~Building_Statistics_Menu()
{
}

/*
 * Think
 *
 * Update this statistic
 */
void Building_Statistics_Menu::think( void ) {
   int gs = m_parent->get_game()->get_speed();

   if(gs==0) gs = 1;

   if((m_parent->get_game()->get_gametime() - m_lastupdate)/gs > UPDATE_TIME ) {
      update();
      m_lastupdate = m_parent->get_game()->get_gametime();
   }
}

/*
 * draw()
 *
 * Draw this window
 */
void Building_Statistics_Menu::draw(RenderTarget* dst) {
	if (m_anim) dst->drawanim
		(Point
		 (5 + get_inner_w() / 8,
		  m_end_of_table_y + (get_inner_h() - m_end_of_table_y) / 2),
		 m_anim,
		 0,
		 0);

	// Draw all the panels etc. above the background
	UI::Window::draw(dst);
}

/*
 * validate if this pointer is ok
 */
int Building_Statistics_Menu::validate_pointer(int* id, int size) {
   if(*id < 0)
      *id = size-1;
   if(*id >= size)
      *id = 0;

   return *id;
}

/*
===========
called when the ok button has been clicked
===========
*/
void Building_Statistics_Menu::clicked_help() {
      log("TODO: help not implemented\n");
}


void Building_Statistics_Menu::clicked_jump(Jump_Targets id) {
	assert(m_table.has_selection());
	const std::vector<Interactive_Player::Building_Stats> & vec =
		m_parent->get_building_statistics(m_table.get_selected());

   bool found = true; // We think, we always find a proper building

	switch (id) {
	case Prev_Owned:
         /* jump prev building */
         m_last_building_index--;
         break;

	case Next_Owned:
         /* Jump next building */
         m_last_building_index++;
         break;

	case Prev_Construction:
         /* Jump to prev constructionsite */
         {
            int curindex = m_last_building_index;
            while( validate_pointer(&(--m_last_building_index), vec.size()) != curindex )
               if( vec[m_last_building_index].is_constructionsite ) break;
         }
         break;

	case Next_Construction:
         /* Jump to next constructionsite */
         {
            int curindex = m_last_building_index;
            while( validate_pointer(&(++m_last_building_index), vec.size()) != curindex )
               if( vec[m_last_building_index].is_constructionsite ) break;
         }
         break;

	case Prev_Unproductive:
         {
            int curindex = m_last_building_index;
            found = false;
            while( validate_pointer(&(--m_last_building_index), vec.size()) != curindex )
               if( !vec[m_last_building_index].is_constructionsite ) {
                  Building* b = ((Building*)m_parent->get_game()->get_map()->get_field(vec[m_last_building_index].pos)->get_immovable());
                  if( b->get_building_type() == Building::PRODUCTIONSITE) {
                     if(((ProductionSite*)b)->get_statistics_percent() <= LOW_PROD ) {
                        found = true;
                        break;
                     }
                  }
               }
            if(!found) { // Now look at the old
               Building* b = ((Building*)m_parent->get_game()->get_map()->get_field(vec[m_last_building_index].pos)->get_immovable());
               if( b->get_building_type() == Building::PRODUCTIONSITE)
                  if(((ProductionSite*)b)->get_statistics_percent() < LOW_PROD )
                     found = true;
            }
         }
         break;

	case Next_Unproductive:
         {
            int curindex = m_last_building_index;
            found = false;
            while( validate_pointer(&(++m_last_building_index), vec.size()) != curindex )
               if( !vec[m_last_building_index].is_constructionsite ) {
                  Building* b = ((Building*)m_parent->get_game()->get_map()->get_field(vec[m_last_building_index].pos)->get_immovable());
                  if( b->get_building_type() == Building::PRODUCTIONSITE) {
                     if(((ProductionSite*)b)->get_statistics_percent() < LOW_PROD ) {
                        found = true;
                        break;
                     }
                  }
               }
            if(!found) { // Now look at the old
               Building* b = ((Building*)m_parent->get_game()->get_map()->get_field(vec[m_last_building_index].pos)->get_immovable());
               if( b->get_building_type() == Building::PRODUCTIONSITE)
                     if(((ProductionSite*)b)->get_statistics_percent() < LOW_PROD )
                        found = true;
               }
         }
         break;



   }

   validate_pointer(&m_last_building_index, vec.size());

	if (found) m_parent->move_view_to(vec[m_last_building_index].pos);
}

/*
 * The table has been selected
 */
void Building_Statistics_Menu::table_changed(uint) {update();}

/*
 * Update table
 */
void Building_Statistics_Menu::update( void ) {
   m_owned->set_text("");
   m_build->set_text("");
   m_progbar->set_state(0);

   // List all buildings
	const Tribe_Descr & tribe = m_parent->player().tribe();
	const Map         & map   = m_parent->get_game()->map();
	for (Building_Descr::Index i = 0; i < tribe.get_nrbuildings(); ++i) {
		const Building_Descr & building = *tribe.get_building_descr(i);
		{
			const std::string & name = building.name();
			if (name == "constructionsite" or name == "headquarters") continue;
		}

      const std::vector< Interactive_Player::Building_Stats >& vec = m_parent->get_building_statistics(i);

      // walk all entries, add new ones if needed
		UI::Table<const uintptr_t>::Entry_Record * te = 0;
		const uint table_size = m_table.size();
		for (uint l = 0; l < table_size; ++l) {
			UI::Table<const uintptr_t>::Entry_Record & er = m_table.get_record(l);
			if (UI::Table<const uintptr_t>::get(er) == i) {
				te = &er;
            break;
         }
      }

      // If not in list, add new one, as long as this building is
      // enabled
      if(!te) {
         if(! m_parent->get_player()->is_building_allowed(i) ) continue;
			te = &m_table.add(i, building.get_buildicon());
      }

		uint nr_owned   = 0;
		uint nr_build   = 0;
		uint total_prod = 0;
		const ProductionSite_Descr * const productionsite =
			dynamic_cast<const ProductionSite_Descr * const>(&building);
		for (uint l = 0; l < vec.size(); ++l) {
			if (vec[l].is_constructionsite) ++nr_build;
			else {
				++nr_owned;
				if (productionsite) total_prod +=
					dynamic_cast<ProductionSite &>
					(*map.get_field(vec[l].pos)->get_immovable())
					.get_statistics_percent();

             }
          }

          // Is this entry selected?
		const bool is_selected =
			m_table.has_selection() and m_table.get_selected() == i;

		if (is_selected) {
			m_anim = building.get_ui_anim();
			m_btn[Prev_Owned]       ->set_enabled(nr_owned);
			m_btn[Next_Owned]       ->set_enabled(nr_owned);
			m_btn[Prev_Construction]->set_enabled(nr_build);
			m_btn[Next_Construction]->set_enabled(nr_build);
		}

          // Add new Table Entry
          char buffer[100];
		te->set_string(0, building.descname());

          // Product
		if (productionsite and nr_owned) {
			const uint percent = static_cast<const uint>
				(static_cast<const float>(total_prod)
				 /
				 static_cast<const float>(nr_owned));
			snprintf(buffer, sizeof(buffer), "%i", percent );
			if (is_selected)  {
				m_progbar->set_state(percent);
				m_btn[Prev_Unproductive]->set_enabled(true);
				m_btn[Next_Unproductive]->set_enabled(true);
			}
		} else {
			snprintf(buffer, sizeof(buffer), "-");
			if (is_selected) {
				m_btn[Prev_Unproductive]->set_enabled(false);
				m_btn[Next_Unproductive]->set_enabled(false);
			}
		}
          te->set_string(1, buffer);

          // Number of this buildings
		snprintf(buffer, sizeof(buffer), "%i", nr_owned);
          te->set_string(2, buffer);
          if(is_selected)
            m_owned->set_text(buffer);

          // Number of currently builds
		snprintf(buffer, sizeof(buffer), "%i", nr_build);
          te->set_string(3, buffer);
          if(is_selected)
            m_build->set_text(buffer);
   }

   // Disable all buttons, if nothing to select
	if (not m_table.has_selection()) {
      m_btn[Prev_Owned]       ->set_enabled(false);
      m_btn[Next_Owned]       ->set_enabled(false);
      m_btn[Prev_Construction]->set_enabled(false);
      m_btn[Next_Construction]->set_enabled(false);
      m_btn[Prev_Unproductive]->set_enabled(false);
      m_btn[Next_Unproductive]->set_enabled(false);
	}
}
