/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  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 "reservation.h"
#include "table.h"
#include "name.h"
#include "icongroup.h"
#include "ui.h"
#include "main_window.h"

#include "widgets/stock_button.h"
#include "../../party/rule.h"
#include "../../game/game.h"
#include "../../player/player.h"
#include "../../basistypes.h"

#include "../../os/bug_report_replay.h"
extern ::OS_NS::BugReportReplay* bug_report_replay;

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

#include <gtkmm/stock.h>
#include <gtkmm/notebook.h>
#include <gtkmm/alignment.h>
#include <gtkmm/radiobutton.h>
#include <gtkmm/table.h>
#include <gtkmm/main.h>
namespace UI_GTKMM_NS {

  /**
   ** Constructor
   **
   ** @param	table	the table
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.0
   **/
  Reservation::Reservation(Table* const table, Player const* const player) :
    HTIN(table, player),
  Gtk::StickyDialog("Reservation", *(parent->ui->main_window), false),
  announce_button(NULL),
  notebook(NULL),
  swines_button(NULL),
  hyperswines_button(NULL),
  gametype_buttons(),
  marriage_selector_buttons()
  {
    this->ui->add_window(*this);

    this->signal_realize().connect(sigc::mem_fun(*this,
					      &Reservation::init));

    return ;
  } // Reservation::Reservation(Table* const table, Player const& player)

  /**
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  Reservation::~Reservation()
  {
    return ;
  } // Reservation::~Reservation()

  /**
   ** create all subelements
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Reservation::init()
    {
      this->set_icon(this->ui->icon);
      if (this->player->game().humanno() <= 1)
	this->ui->translations->add(*this,
				      ::translation("~reservation"));
      else
	this->ui->translations->add(*this,
				      ::translation("~reservation (%sname%)",
						   this->player->name()));

      this->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);

      this->announce_button
	= Gtk::manage(new Gtk::StockButton(Gtk::Stock::OK,
					   "reservation announce"));
      this->ui->translations->add(*this->announce_button,
				    ::translation("reservation announce"));
      this->add_action_widget(*this->announce_button, Gtk::RESPONSE_ACCEPT);
      this->notebook = Gtk::manage(new Gtk::Notebook());
      this->notebook->set_tab_pos(Gtk::POS_LEFT);
      this->swines_button = Gtk::manage(new Gtk::CheckButton("swines"));
      this->ui->translations->add(*this->swines_button,
				    ::translation("swines"));
      this->hyperswines_button = Gtk::manage(new Gtk::CheckButton("hyperswines"));
      this->ui->translations->add(*this->hyperswines_button,
				    ::translation("hyperswines"));

      this->announce_button->grab_default();

      this->get_vbox()->add(*(this->notebook));

      { // create the buttons
	Gtk::RadioButton::Group gametype_group;
	for (int g = GAMETYPE::FIRST;
	     g <= GAMETYPE::LAST;
	     g++) {
	  this->gametype_buttons.push_back(Gtk::manage(new Gtk::RadioButton(gametype_group, "type")));
	  this->gametype_buttons.back()->set_data("gametype", new GameType(GameType(g)));
	  this->ui->translations->add(*this->gametype_buttons.back(),
					::translation(static_cast<GameType>(g)));
	  this->gametype_buttons.back()->signal_toggled().connect(sigc::bind<int const>(sigc::mem_fun(*this, &Reservation::gametype_changed), g));
	} // for (g \in GAMETYPE)

	Gtk::RadioButton::Group marriage_selector_group;
	for (int m = MARRIAGE_SELECTOR::FIRST;
	     m <= MARRIAGE_SELECTOR::LAST;
	     m++) {
	  this->marriage_selector_buttons.push_back(Gtk::manage(new Gtk::RadioButton(marriage_selector_group, "selector")));
	  this->marriage_selector_buttons.back()->set_data("selector", new MarriageSelector(MarriageSelector(m)));
	  this->ui->translations->add(*(this->marriage_selector_buttons.back()),
					::translation(static_cast<MarriageSelector>(m)));
	} // for (m \in MARRIAGE_SELECTOR)
      } // create the buttons

      { // set the pages of the notebook
	{ // General
	  Gtk::Alignment* alignment
	    = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					     Gtk::ALIGN_CENTER,
					     0, 0));
	  alignment->set_border_width(2 ex);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("general"));
	  this->ui->translations->add(*label,
				      ::translation("GameType::Group::general"));
	  this->notebook->append_page(*alignment, *label);

	  Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(false, 1 ex));
	  alignment->add(*hbox);

	  Gtk::VBox* vbox = NULL;
	  { // the swines
	    vbox = Gtk::manage(new Gtk::VBox(false, 10));
	    hbox->add(*vbox);

	    {
	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->add(*this->swines_button);
	      vbox->add(*alignment);
	    }
	    {
	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      vbox->add(*this->hyperswines_button);
	      vbox->add(*alignment);
	    }
	  } // the swines
	  { // gametypes
	    vbox = Gtk::manage(new Gtk::VBox(false, 10));
	    hbox->add(*vbox);

	    vbox->add(*this->gametype_buttons[GAMETYPE::NORMAL]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_NINES]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_KINGS]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::FOX_HIGHEST_TRUMP]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::POVERTY]);
	    vbox->add(*this->gametype_buttons[GAMETYPE::MARRIAGE]);
	  } // gametypes
	  { // marriage selectors
	    vbox = Gtk::manage(new Gtk::VBox(false, 10));
	    hbox->add(*vbox);

	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_FOREIGN]);
	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_TRUMP]);
	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_COLOR]);
	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_CLUB]);
	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_SPADE]);
	    vbox->add(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_HEART]);
	  } // marriage selectors
	} // General
	{ // Solo
	  Gtk::Alignment* alignment
	    = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					     Gtk::ALIGN_CENTER,
					     0, 0));
	  alignment->set_border_width(2 ex);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("solo"));
	  this->ui->translations->add(*label,
				      ::translation("GameType::Group::solo"));
	  this->notebook->append_page(*alignment, *label);

	  Gtk::Table* table = Gtk::manage(new Gtk::Table(4, 3));
	  table->set_row_spacings(10);
	  table->set_col_spacings(10);
	  alignment->add(*table);

	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_CLUB]),
			0, 1, 0, 1);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_SPADE]),
			0, 1, 1, 2);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_HEART]),
			0, 1, 2, 3);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_DIAMOND]),
			0, 1, 3, 4);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_MEATLESS]),
			1, 2, 0, 1);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_JACK]),
			1, 2, 1, 2);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_QUEEN]),
			1, 2, 2, 3);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING]),
			1, 2, 3, 4);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_QUEEN_JACK]),
			2, 3, 0, 1);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING_JACK]),
			2, 3, 1, 2);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING_QUEEN]),
			2, 3, 2, 3);
	  table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KOEHLER]),
			2, 3, 3, 4);
	} // Solo
      } // set the pages of the notebook

      { // signals
      this->announce_button->signal_clicked().connect(sigc::mem_fun(*this,
								 &Gtk::Widget::hide)
						     );
	  this->swines_button->signal_toggled().connect(sigc::mem_fun(*this, &Reservation::check_poverty));
      } // signals

      this->show_all_children();

      return ;
    } // void Reservation::init()

  /**
   ** gets a reservation
   **
   ** @param	-
   **
   ** @return	reservation
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.0
   **/
  ::Reservation
    Reservation::get()
    {
      this->realize();

      this->notebook->set_current_page(0);

      this->sensitivity_update();
      this->set_default();

      { // adjust some translations
      this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_NINES],
				     ::translation("GameType::%tnumber% nines",
						   ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_NINES)))));
      this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_KINGS],
				     ::translation("GameType::%tnumber% kings",
						   ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_KINGS)))));
      this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS],
				     ::translation("GameType::%tnumber% nines and kings",
						   ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_NINES_AND_KINGS)))));

      if (this->player->hand().numberofclubqueens()
	  == this->player->game().rule()(Rule::NUMBER_OF_SAME_CARDS))
	this->ui->translations->change(*this->gametype_buttons[GAMETYPE::NORMAL],
				       ::translation(::GAMETYPE::MARRIAGE_SILENT));
      else
	this->ui->translations->change(*this->gametype_buttons[GAMETYPE::NORMAL],
				       ::translation(::GAMETYPE::NORMAL));
      } // adjust some translations

      this->present();

      while (!this->ui->thrower
	     && this->is_visible())
	Gtk::Main::iteration();

      this->ui->game().set_type(GAMETYPE::NORMAL);

      ::Reservation reservation;
      { // set the reservation
	for (vector<Gtk::RadioButton*>::iterator widget
	     = this->gametype_buttons.begin();
	     widget != this->gametype_buttons.end();
	     widget++)
	  if ((*widget)->get_active())
	    reservation.game_type
	      = *(static_cast<GameType*>((*widget)->get_data("gametype")));

	if (reservation.game_type == GAMETYPE::MARRIAGE) {
	  for (vector<Gtk::RadioButton*>::iterator widget
	       = this->marriage_selector_buttons.begin();
	       widget != this->marriage_selector_buttons.end();
	       widget++)
	    if ((*widget)->get_active())
	      reservation.marriage_selector
		= *(static_cast<MarriageSelector*>((*widget)->get_data("selector")));
	} // if (reservation.game_type == GAMETYPE::MARRIAGE)
	reservation.swines = this->swines_button->get_active();
	reservation.hyperswines = this->hyperswines_button->get_active();
      } // set the reservation

      this->hide();

      return reservation;
    } // ::Reservation Reservation::get()

  /**
   ** set to default values
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.0
   **/
  void
    Reservation::set_default()
    {
      ::Reservation const reservation = this->player->reservation_get_default();
      COUT << reservation << endl;

      this->sensitivity_update();

      this->swines_button->set_active(reservation.swines);
      this->hyperswines_button->set_active(reservation.hyperswines);

      // special case: with swines announced the player does not have a poverty
      if (   (reservation.game_type == GAMETYPE::POVERTY)
	  && (this->player->hand().numberofpovertycards()
	      > Rule::MAX_NUMBER_OF_POVERTY_TRUMPS) )
	this->swines_button->set_active(false);

      this->gametype_buttons[reservation.game_type]->set_active();
      this->marriage_selector_buttons[reservation.marriage_selector]->set_active();

      this->name().draw(true);
      this->table().name(this->player->game().startplayer()).draw(true);

      { // switch to the game type from the bug report replay
	if (   ::bug_report_replay
	    && (::bug_report_replay->soloplayer_no() == this->player->no() )) {
	  this->gametype_buttons[::bug_report_replay->game_type()]->set_active();
	  if (GAMETYPE::is_solo(::bug_report_replay->game_type()))
	    this->notebook->set_current_page(1);
	  if (::bug_report_replay->game_type() == GAMETYPE::MARRIAGE)
	    this->marriage_selector_buttons[::bug_report_replay->marriage_selector()]->set_active();
	}
      } // switch to the game type from the bug report replay


      return ;
    } // void Reservation::set_default()

  /**
   ** update the sensitivity
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Reservation::sensitivity_update()
    {
      if (!this->is_realized())
	return ;

      if (::game_status != GAMESTATUS::GAME_RESERVATION)
	return ;

      ::Rule const& rule = this->player->game().rule();
      //::Player const& player = this->player->game().player_current();
      ::Player const& player = *(this->player);
      ::Hand const& hand = player.hand();

      if (rule(Rule::SWINES)
	  && !rule(Rule::SWINE_ONLY_SECOND))
	this->swines_button->show();
      else
	this->swines_button->hide();
      this->swines_button->set_sensitive(hand.has_swines());

      if (rule(Rule::HYPERSWINES))
	this->hyperswines_button->show();
      else
	this->hyperswines_button->hide();
      this->hyperswines_button->set_sensitive(hand.has_hyperswines());

      for (vector<Gtk::RadioButton*>::iterator widget
	   = this->gametype_buttons.begin();
	   widget != this->gametype_buttons.end();
	   widget++)
	if (rule(*(static_cast<GameType*>((*widget)->get_data("gametype")))))
	  (*widget)->show();
	else
	  (*widget)->hide();

      if (rule(Rule::SOLO))
	this->notebook->get_nth_page(1)->show();
      else
	this->notebook->get_nth_page(1)->hide();

      for (vector<Gtk::RadioButton*>::iterator widget
	   = this->marriage_selector_buttons.begin();
	   widget != this->marriage_selector_buttons.end();
	   widget++)
	if (rule(*(static_cast<MarriageSelector*>((*widget)->get_data("selector")))))
	  (*widget)->show();
	else
	  (*widget)->hide();

      this->gametype_buttons[GAMETYPE::THROWN_NINES]->set_sensitive((hand.numberofnines() >= rule(Rule::MIN_NUMBER_OF_THROWING_NINES))
								    && rule(GAMETYPE::THROWN_NINES));
      this->gametype_buttons[GAMETYPE::THROWN_KINGS]->set_sensitive((hand.numberofkings() >= rule(Rule::MIN_NUMBER_OF_THROWING_KINGS))
								    && rule(GAMETYPE::THROWN_KINGS));
      this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS]->set_sensitive((hand.numberofnines() + hand.numberofkings() >= rule(Rule::MIN_NUMBER_OF_THROWING_NINES_AND_KINGS))
									      && rule(GAMETYPE::THROWN_NINES_AND_KINGS));
      this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(hand.has_poverty());
      { // look, whether there is a card that is higher than the fox
	unsigned c;
	for (c = 0; c < player.hand().cardsnumber(); c++)
	  // check with diamond ten because of swines!
	  if (   Card(Card::DIAMOND, Card::TEN).less(player.hand().card(c))
	      && !player.hand().card(c).istrumpace())
	    break;
	this->gametype_buttons[GAMETYPE::FOX_HIGHEST_TRUMP]->set_sensitive((c == player.hand().cardsnumber())
									   && rule(GAMETYPE::POVERTY));
      } // look, whether there is a card that is higher than the fox
      this->gametype_buttons[GAMETYPE::MARRIAGE]->set_sensitive((hand.numberofclubqueens() == rule(Rule::NUMBER_OF_SAME_CARDS)));

      for (vector<Gtk::RadioButton*>::iterator widget
	   = this->marriage_selector_buttons.begin();
	   widget != this->marriage_selector_buttons.end();
	   widget++) {
	bool const selected = this->gametype_buttons[GAMETYPE::MARRIAGE]->get_active();
	(*widget)->set_sensitive(selected);
	//this->gametype_buttons[GAMETYPE::MARRIAGE]->sensitive());
      }

      this->check_poverty();

      return ;
    } // void Reservation::sensitivity_update()

  /**
   ** the gametype has changed
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.0
   **/
  void
    Reservation::gametype_changed(int const gametype)
    {
      if (gametype == GAMETYPE::MARRIAGE) {
	bool const selected = this->gametype_buttons[gametype]->get_active();
	for (vector<Gtk::RadioButton*>::iterator widget
	     = this->marriage_selector_buttons.begin();
	     widget != this->marriage_selector_buttons.end();
	     widget++)
	  (*widget)->set_sensitive(selected);
      } // if (gametype == GAMETYPE::MARRIAGE)

      // '::party.game()' here, because the game has to be changed,
      // 'this->player->game()' is a const game
      GameType const old_gametype = this->player->game().type();
      this->ui->game().set_type(static_cast<GameType>(gametype));
      this->ui->game().players_hands_sort();

      this->icongroup().draw_team(true);
      this->name().draw(true);
      this->table().name(this->player->game().startplayer()).draw(true);

      // update the swines
      if (   this->ui->game().rule()(Rule::SWINES)
	  && (old_gametype != gametype)
	  && (   GAMETYPE::is_color_solo(old_gametype)
	      || GAMETYPE::is_color_solo(static_cast<GameType>(gametype)))
	 ) {
	::Hand const& hand = this->player->hand();

	this->swines_button->set_sensitive(hand.has_swines());
	this->swines_button->set_active(hand.has_swines() && this->ui->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN));
	this->hyperswines_button->set_sensitive(hand.has_hyperswines());
	this->hyperswines_button->set_active(hand.has_hyperswines() && this->ui->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN));
      } // if (gametype has changed to/from color solo)

      return ;
    } // void Reservation::gametype_changed(int const gametype)

  /**
   ** nothing
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.0
   **/
  void
    Reservation::draw(bool const update)
    {
      return ;
    } // void Reservation::draw(bool const update = true)

  /**
   ** check, whether a poverty is valid
   ** (because of rules: poverty fox do not count, poverty fox shift extra)
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.7.3
   **/
  void
    Reservation::check_poverty()
    {
      // special case: with swines announced the player does not have a poverty
      if (!(this->player->hand().numberofpovertycards()
	    > Rule::MAX_NUMBER_OF_POVERTY_TRUMPS) )
	return ;

      if (this->swines_button->get_active()) {
	this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(false);
	if (this->gametype_buttons[GAMETYPE::POVERTY]->get_active())
	  this->gametype_buttons[GAMETYPE::NORMAL]->set_active();
      } else { // if (this->swines_button->active())
	this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(true);
      } // if (this->swines_button->active())

      return ;
    } // void Reservation::check_poverty()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
