/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2004  by Diether Knof and Borg Enders
 *
 *   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 can find this license in the file 'gpl.txt'.
 *
 *   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
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 *********************************************************************/

#include "constants.h"

#ifdef USE_UI_GTKMM

#include "party_points.h"
#include "game_overview.h"

#include "ui.h"
#include "main_window.h"
#include "cards.h"
#include "bug_report.h"

#include "../../party/party.h"
#include "../../game/gamepointstable.h"
#include "../../misc/setting.h"

#include "../../utils/string.h"

#include "widgets/stock_button.h"
#include <gtkmm/stock.h>
#include <gtkmm/treeview.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/alignment.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>

namespace UI_GTKMM_NS {

  /**
   **
   ** Constructor for the model
   **
   ** @param	playerno	number of players in the party
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   ** @todo	the row can be deselected
   ** @todo	extra window for the game summary
   **
   **/
  PartyPoints::PartyPointsModel::PartyPointsModel(unsigned const playerno) :
    gameno(),
  playerpoints(playerno),
  gametype()
  {
    this->add(this->gameno);
    for (unsigned p = 0; p < playerno; p++)
      this->add(this->playerpoints[p]);
    this->add(this->gametype);

    return ;
  } // PartyPoints::PartyPointsModel::PartyPointsModel(unsigned const playerno)

  /**
   **
   ** Constructor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  PartyPoints::PartyPoints(Base* const parent) :
    Base(parent),
  Dialog("Party points", false, true),
  party_points_list(),
  party_points_treeview(NULL),
  party_points_sum_treeview(NULL),
  show_game_overview_button(NULL),
  close_button(NULL),
  game_overview(NULL)
  {
    DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		  "PartyPoints::PartyPoints(parent)");

    this->signal_realize().connect(SigC::slot(*this,
					      &PartyPoints::init));

#ifndef POSTPHONED
    // ToDo: remove
    // when 'GamePoints' doesn't need a pointer to Game any more
    this->realize();
#endif

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		    "PartyPoints::PartyPoints(parent)");
  } // PartyPoints::PartyPoints(Base* const parent)

  /**
   **
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  PartyPoints::~PartyPoints()
  {
    DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		  "PartyPoints::~PartyPoints()");

    delete this->party_points_model;
    delete this->game_overview;

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		    "PartyPoints::~PartyPoints()");
  } // PartyPoints::~PartyPoints()

  /**
   **
   ** create all subelements
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  void
    PartyPoints::init()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		    "PartyPoints::init()");

      this->ui->add_for_translation(*this, ::translator("Party points"));

      this->set_icon(this->ui->main_window->icon);

      this->game_overview = new GameOverview(this);
      this->signal_show().connect(SigC::slot(*this,
					     &PartyPoints::show_game_overview_toggled));


      { // vbox

	// the points table
	this->party_points_model = new PartyPointsModel(::party.playerno());

	// of the sum treeview only the header is neeede
	// (since there exists no foot for a treeview)
	this->party_points_sum_treeview
	  = Gtk::manage(new Gtk::TreeView(Gtk::ListStore::create(*(this->party_points_model))));

	this->party_points_list
	  = Gtk::ListStore::create(*(this->party_points_model));
	this->party_points_treeview
	  = Gtk::manage(new Gtk::TreeView(this->party_points_list));
	this->party_points_treeview->get_selection()->set_mode(Gtk::SELECTION_SINGLE);

	this->party_points_treeview->append_column("Game",
						   this->party_points_model->gameno);
	this->party_points_treeview->get_column_cell_renderer(0)->property_xalign() = 1;
	this->party_points_sum_treeview->append_column("",
						       this->party_points_model->gameno);
	this->party_points_sum_treeview->get_column_cell_renderer(0)->property_xalign() = 1;
	for (unsigned p = 0; p < ::party.playerno(); p++) {
	  this->party_points_treeview->append_column(Glib::locale_to_utf8(::party.player(p).name()),
						     this->party_points_model->playerpoints[p]);
	  this->party_points_treeview->get_column_cell_renderer(p + 1)->property_xalign() = 0.5;
	  this->party_points_sum_treeview->append_column("0",
							 this->party_points_model->playerpoints[p]);
	  this->party_points_sum_treeview->get_column(p + 1)->set_resizable(false);
	  this->party_points_sum_treeview->get_column(p + 1)->set_alignment(Gtk::ALIGN_CENTER);
	} // for (p < ::party.playerno())
	this->party_points_treeview->append_column("Game type",
						   this->party_points_model->gametype);
	this->party_points_sum_treeview->append_column("",
						       this->party_points_model->gametype);

	{ // the scrolled window
	  Gtk::ScrolledWindow* scrolled_window
	    = Gtk::manage(new Gtk::ScrolledWindow);
	  scrolled_window->set_policy(Gtk::POLICY_NEVER,
				      Gtk::POLICY_AUTOMATIC);
	  scrolled_window->add(*(this->party_points_treeview));

	  this->get_vbox()->pack_start(*scrolled_window);
	} // the scrolled window
	this->get_vbox()->pack_start(*(this->party_points_sum_treeview), false, true);

	{ // the buttons
	  Gtk::Alignment* alignment
	    = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					     Gtk::ALIGN_CENTER,
					     0, 0));
	  this->show_game_overview_button
	    = Gtk::manage(new Gtk::CheckButton("show game overview"));
	  this->ui->add_for_translation(*(this->show_game_overview_button),
					::translator("show game overview"));
	  alignment->add(*(this->show_game_overview_button));
	  this->get_vbox()->pack_end(*alignment, Gtk::PACK_SHRINK);
	} // the buttons
      } // vbox

      { // action area
	this->close_button
	  = Gtk::manage(new Gtk::StockButton(Gtk::Stock::CLOSE, "close"));
	this->ui->add_for_translation(*(this->close_button),
				      ::translator("close"));
	this->add_action_widget(*(this->close_button), Gtk::RESPONSE_CLOSE);

	this->close_button->grab_default();
      } // action area

      this->show_all_children();

      this->signal_hide().connect(SigC::bind<bool>(SigC::slot(*(this->show_game_overview_button),
							      &Gtk::ToggleButton::set_active),
						   false));

      this->party_points_treeview->get_selection()->signal_changed().connect(SigC::slot(*this, &PartyPoints::row_selection_changed));
      this->show_game_overview_button->signal_toggled().connect(SigC::slot(*this, &PartyPoints::show_game_overview_toggled));
      this->close_button->signal_clicked().connect(SigC::slot(*this, &Gtk::Widget::hide));

      this->signal_show().connect(SigC::slot(*this,
					     &PartyPoints::sum_columns_size_update));
      this->sum_columns_size_update();

      this->language_update();

      this->set_default_size(0, 2 * this->ui->cards->height());

      this->show_game_overview_button->set_sensitive(false);

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_INIT,
		      "PartyPoints::init()");
    } // void PartyPoints::init()

  /**
   **
   ** the game has finished:
   ** add a new row with the current game
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::game_finished()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_GAMEPLAY,
		    "PartyPoints::game_finished()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_GAMEPLAY,
			"PartyPoints::game_finished()");

      this->add_game(::party.gameno());
      Gtk::TreeModel::Children
	children = this->party_points_treeview->get_model()->children();
      Gtk::TreeModel::Row row = children[children.size() - 1];
      this->party_points_treeview->get_selection()->select(row);
      this->party_points_treeview->scroll_to_row(Gtk::TreePath(row));

      this->show_game_overview_button->set_sensitive(true);

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_GAMEPLAY,
		      "PartyPoints::game_finished()");
    } // void PartyPoints::game_finished()

  /**
   **
   ** the name of 'player' has changed
   **
   ** @param	player	the player with the changed name
   **
   ** @return	-
   **
   ** @version	0.6.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::name_changed(Player const& player)
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		    "PartyPoints::name_changed(player)");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
			"PartyPoints::name_changed(player)");

      // ToDo: Here 'player.no()' means the number in the party, not in the game
      this->party_points_treeview->get_column(player.no() + 1)->set_title(" " + Glib::locale_to_utf8(player.name()) + " ");
      this->game_overview->name_changed(player);

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		      "PartyPoints::name_changed(player)");
    } // void PartyPoints::name_changed(Player const& player)

  /**
   **
   ** recreates the party points
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::recreate_party_points()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		    "PartyPoints::recreate_party_points()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
			"PartyPoints::recreate_party_points()");

      this->party_points_list->clear();
      for (unsigned g = 0; g < ::party.gameno(); g++)
	this->add_game(g);
      if (::game_status == GAMESTATUS::GAME_FINISHED)
	this->game_finished();

      this->show_game_overview_button->set_sensitive(::party.gameno()
						     > 0);

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		      "PartyPoints::recreate_party_points()");
    } // void PartyPoints::recreate_party_points()

  /**
   **
   ** add the row for the game 'gameno'
   **
   ** @param	gameno	number of the game to be added
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   ** @todo	color the row according to the gametype
   **
   **/
  void
    PartyPoints::add_game(unsigned const gameno)
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		    "PartyPoints::add_game(gameno)");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
			"PartyPoints::add_game(gameno)");

      GamePoints const& game_points
	= (static_cast<Party const&>(::party)).gamepointstable().gamepoints(gameno);

      Gtk::TreeModel::Row row = *(this->party_points_list->append());
      row[this->party_points_model->gameno] = gameno + 1;
      if (game_points.gametype() == GAMETYPE::NORMAL)
	row[this->party_points_model->gametype] = "";
      else
	row[this->party_points_model->gametype]
	  = Glib::locale_to_utf8(::translator(game_points.gametype()).translation());
      for (unsigned p = 0; p < ::party.playerno(); p++) {
	// ToDo: p is here the player in the party, not in the game
	if ((game_points.team(p) == game_points.winnerteam())
	    || (game_points.winnerteam() == TEAM::NOTEAM))
	  row[this->party_points_model->playerpoints[p]]
	    = DK::Utils::String::to_string(game_points.points());
	else
	  row[this->party_points_model->playerpoints[p]]
	    = "";
      } // for (p < ::party.playerno())

      // udpate the sum
      for (unsigned p = 0; p < ::party.playerno(); ++p)
	this->party_points_sum_treeview->get_column(p + 1)->set_title(DK::Utils::String::to_string(const_cast<Party const&>(::party).gamepointstable().points(p)));

      this->sum_columns_size_update();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		      "PartyPoints::add_game(gameno)");
    } // void PartyPoints::add_game(unsigned const gameno)

  /**
   **
   ** the row selection has changed:
   ** show the belonging game summary
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::row_selection_changed()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		    "PartyPoints::row_selection_changed()");

      Glib::RefPtr<Gtk::TreeView::Selection> selection
	= this->party_points_treeview->get_selection();

      if (selection->get_selected()) {
	Gtk::TreeRow row = *(selection->get_selected());

	unsigned const gameno = row[this->party_points_model->gameno] - 1;

	this->game_overview->set_gameno(gameno);
      } else {	// if !(selection->get_selected())
	this->game_overview->set_gameno(UINT_MAX);
	this->game_overview->hide();
      }	// if !(selection->get_selected())

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		      "PartyPoints::row_selection_changed()");
    } // void PartyPoints::row_selection_changed()

  /**
   **
   ** update the column size of the sum treeview
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::sum_columns_size_update()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		    "PartyPoints::sum_columns_size_update()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
			"PartyPoints::sum_columns_size_update()");

      for (unsigned c = 0; c < ::party.playerno() + 1; ++c) {
	int const width
	  = this->party_points_treeview->get_column(c)->get_width();
	//this->party_points_sum_treeview->get_column(c)->set_fixed_width(width);
	this->party_points_sum_treeview->get_column(c)->set_min_width(width);
	this->party_points_sum_treeview->get_column(c)->set_max_width(width);
      }

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		      "PartyPoints::sum_columns_size_update()");
    } // void PartyPoints::sum_columns_size_update()

  /**
   **
   ** clear the selection
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.3
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::clear_selection()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		    "PartyPoints::clear_selection()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
			"PartyPoints::clear_selection()");

      this->party_points_treeview->get_selection()->unselect_all();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		      "PartyPoints::clear_selection()");
    } // void PartyPoints::clear_selection()

  /**
   **
   ** toggle the showing of the 'game overview' window
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.3
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::show_game_overview_toggled()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		    "PartyPoints::show_game_overview_toggled()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
			"PartyPoints::show_game_overview_toggled()");


      if (this->game_overview) {
	if (this->show_game_overview_button->get_active()) {
	  this->row_selection_changed();
	  this->game_overview->present();
#ifdef WORKAROUND
	  // if no row is selected select the last
	  if (this->game_overview->gameno() == UINT_MAX) {
	    unsigned const gameno = const_cast<Party const&>(::party).gamepointstable().gameno() - 1;
	    this->game_overview->set_gameno(gameno);
	  }
#endif
	} else {
	  this->game_overview->hide();
	}
      } // if (this->game_overview)

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_EVENT,
		      "PartyPoints::show_game_overview_toggled()");
    } // void PartyPoints::show_game_overview_toggled()

  /**
   **
   ** updates all language elements
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    PartyPoints::language_update()
    {
      DEBUG_CALLING(INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		    "PartyPoints::language_update()");

      if (!this->is_realized())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
			"PartyPoints::language_update()");

      this->party_points_treeview->get_column(0)->set_title(Glib::locale_to_utf8(::translator("game").translation()));
      this->party_points_treeview->get_column(::party.playerno() + 1)->set_title(Glib::locale_to_utf8(::translator("gametype").translation()));

      this->recreate_party_points();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_PARTY_POINTS && INFO_GTKMM_UPDATE,
		      "PartyPoints::language_update()");
    } // void PartyPoints::language_update()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
