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

#include "cards.h"
#include "icons.h"
#include "hand.h"
#include "name.h"

#include "../../game/game.h"
#include "../../party/rule.h"
#include "../../player/player.h"
#include "../../misc/setting.h"

namespace UI_GTKMM_NS {

  /**
   **
   ** Constructor
   **
   ** @param	table	the table
   ** @param	player	the player
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  Icongroup::Icongroup(Table* const table, Player const* const player) :
    HTIN(table, player)
  {
    return ;
  } // Icongroup::Icongroup(Table* const table, Player const* const player)

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

  /**
   **
   ** draws the icongroup
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  void
  Icongroup::draw(bool const update)
  {
    this->draw_swines(update);
    this->draw_team(update);
    this->draw_announcement(update);

    return ;
  } // void Icongroup::draw(bool const update = true)

  /**
   **
   ** draws the team/gametype icon
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.3
   **
   ** @todo	silent marriage
   **
   **/
  void
    Icongroup::draw_team(bool const update)
    {
      // the values for the icon of maximal size

      Gdk::Rectangle max_outline;
      // the possible icons (from before, needed for overwriting old icons)
      vector<Glib::RefPtr<Gdk::Pixbuf> > possible_icons;

      if( (::game_status & GAMESTATUS::GAME)
	  && ((::game_status > GAMESTATUS::GAME_RESERVATION)
	      || this->table().gametype_known()
	     )) {
	// draw the icon for the team
	Game const& game = this->player->game();

	// take the team of the game
	Team const team = game.teaminfo_for_humans(*(this->player));

	Glib::RefPtr<Gdk::Pixbuf> icon;
	if (game.is_finished()
	    || (game.rule()(Rule::SHOW_KNOWN_TEAMS_IN_GAME)
		&& ::setting(Setting::SHOW_KNOWN_TEAMS_IN_GAME))) {
	  icon = this->ui->icons->icon(team,
				       this->rotation());
	  possible_icons.push_back(this->ui->icons->icon(TEAM::RE,
							 this->rotation()));
	  possible_icons.push_back(this->ui->icons->icon(TEAM::CONTRA,
							 this->rotation()));
	  icon = this->ui->icons->icon(team, this->rotation());
	} // if (show teams)

	if (game.is_finished()
	    || (game.rule()(Rule::SHOW_SOLOPLAYER_IN_GAME)
		&& ::setting(Setting::SHOW_SOLOPLAYER_IN_GAME))) {
	  switch (game.type()) {
	  case GAMETYPE::NORMAL:
	    break;
	  case GAMETYPE::POVERTY:
	    // ToDo
	    if (this->player->is_same(game.soloplayer())) {
	      icon = this->ui->icons->icon(game.type(), this->rotation());
	      possible_icons.push_back(icon);
	      possible_icons.push_back(this->ui->icons->icon(Icons::POVERTY,
							     this->rotation()));
	      possible_icons.push_back(icon);
	    } // if (this->player->is_same(game.soloplayer()))
	    break;
	  case GAMETYPE::GENSCHER:
	    if (this->player->is_same(game.soloplayer()))
	      icon = this->ui->icons->icon(Icons::GENSCHER,
					   this->rotation());
	    else if (this->player->team() == TEAM::RE)
	      icon = this->ui->icons->icon(team, this->rotation());
	    break;
	  case GAMETYPE::MARRIAGE:
	  case GAMETYPE::MARRIAGE_SOLO:
	  case GAMETYPE::MARRIAGE_SILENT:
	    if (this->player->is_same(game.soloplayer())) {
	      icon = this->ui->icons->icon(game.marriage_selector(),
					   this->rotation());
	      for (int s = MARRIAGE_SELECTOR::FIRST;
		   s <= MARRIAGE_SELECTOR::LAST;
		   s++)
		possible_icons.push_back(this->ui->icons->icon(MarriageSelector(s),
							       this->rotation()));
	    } else if (this->player->team() == TEAM::RE) {
	      if (game.marriage_selector() == MARRIAGE_SELECTOR::TEAM_SET)
		icon = this->ui->icons->icon(team, this->rotation());
	    } // if !(this->player->is_same(game.soloplayer()))
	    break;
	  case GAMETYPE::FIVE_NINES:
	  case GAMETYPE::SIX_KINGS:
	  case GAMETYPE::FOX_HIGHEST_TRUMP:
	  case GAMETYPE::SOLO_DIAMOND:
	  case GAMETYPE::SOLO_JACK:
	  case GAMETYPE::SOLO_QUEEN:
	  case GAMETYPE::SOLO_KING:
	  case GAMETYPE::SOLO_QUEEN_JACK:
	  case GAMETYPE::SOLO_KING_JACK:
	  case GAMETYPE::SOLO_KING_QUEEN:
	  case GAMETYPE::SOLO_KOEHLER:
	  case GAMETYPE::SOLO_CLUB:
	  case GAMETYPE::SOLO_HEART:
	  case GAMETYPE::SOLO_SPADE:
	  case GAMETYPE::SOLO_MEATLESS:
	    if (this->player->is_same(game.soloplayer()))
	      icon = this->ui->icons->icon(game.type(), this->rotation());
	    break;
	  } // switch(game.type())
	} // if (icon shall be shown for soloplayer)

	if (icon)
	  possible_icons.push_back(icon);

	if (update) {
	  max_outline.set_width(this->ui->icons->max_width(possible_icons));
	  max_outline.set_height(this->ui->icons->max_height(possible_icons));
	  max_outline.set_x(this->team_start_x(max_outline.get_width()));
	  max_outline.set_y(this->team_start_y(max_outline.get_height()));

	  this->table().clear(max_outline);
	} // if (update)

	if (icon)
	  this->table().pixmap->draw_pixbuf(this->table().gc,
					    icon,
					    0, 0,
					    this->team_start_x(icon->get_width()),
					    this->team_start_y(icon->get_height()),
					    -1, -1,
					    Gdk::RGB_DITHER_NONE,
					    0, 0);

	if (update) {
	  // ToDo: remove
	  this->draw(false);
	  this->name().draw(false);

	  this->table().update(max_outline);
	} // if (update)

      } // if( (::game_status & GAMESTATUS::GAME) && (::game_status > GAMESTATUS::GAME_RESERVATION))


      return ;
    } // void Icongroup::draw_team(bool const update = true)

  /**
   **
   ** draws the announcement icon
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  void
    Icongroup::draw_announcement(bool const update)
    {
      if( (::game_status & GAMESTATUS::GAME)
	  && (::game_status > GAMESTATUS::GAME_RESERVATION)) {
	// the values for the icon of maximal size
	Gdk::Rectangle max_outline;

	if (update) {
	  vector<Glib::RefPtr<Gdk::Pixbuf> > possible_icons;
	  for (unsigned a = ANNOUNCEMENT::NO120; a <= ANNOUNCEMENT::NO0; a++)
	    possible_icons.push_back(this->ui->icons->icon(Announcement(a),
							   this->rotation()));
	  max_outline.set_width(this->ui->icons->max_width(possible_icons));
	  max_outline.set_height(this->ui->icons->max_height(possible_icons));
	  max_outline.set_x(this->announcement_start_x(max_outline.get_width()));
	  max_outline.set_y(this->announcement_start_y(max_outline.get_height()));


	  this->table().clear(max_outline);
	} // if (update)

	Announcement announcement = this->player->announcement();

	if (this->table().in_game_review()) {
	  announcement = ANNOUNCEMENT::NOANNOUNCEMENT;
	  for (vector<Game::AnnouncementWithTrickno>::const_reverse_iterator
	       a = this->player->game().announcements_of_player(*this->player
							       ).rbegin();
	       a != this->player->game().announcements_of_player(*this->player
								).rend();
	       ++a)
	    if (a->trickno <= this->table().game_review_trickno()) {
	      announcement = a->announcement;
	      break;
	    }
	} // if (this->table().in_game_review())

	if (announcement != ANNOUNCEMENT::NOANNOUNCEMENT) {
	  Glib::RefPtr<Gdk::Pixbuf> icon
	    = this->ui->icons->icon(announcement,
				    this->rotation());

	  this->table().pixmap->draw_pixbuf(this->table().gc,
					    icon,
					    0, 0,
					    this->announcement_start_x(icon->get_width()),
					    this->announcement_start_y(icon->get_height()),
					    -1, -1,
					    Gdk::RGB_DITHER_NONE,
					    0, 0);
	} // if (this->player->announcement() != ANNOUNCEMENT::NOANNOUNCEMENT)

	if (update) {
	  // ToDo: remove
	  this->draw(false);
	  this->name().draw(false);

	  this->table().update(max_outline);
	} // if (update)
      } // if( (::game_status & GAMESTATUS::GAME) && (::game_status > GAMESTATUS::GAME_RESERVATION))

      return ;
    } // void Icongroup::draw_announcement(bool const update = true)

  /**
   **
   ** draws the swines/hyperswines icon
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  void
    Icongroup::draw_swines(bool const update)
    {
      // no clearing necessary, since the icon can only get bigger
#if 0
      if (update)
	this->table().clear(this->swines_start_x(this->ui->icons->max_width()),
			    this->swines_start_y(this->ui->icons->max_height()),
			    this->ui->icons->max_width(),
			    this->ui->icons->max_height());
#endif

      Glib::RefPtr<Gdk::Pixbuf> icon;

      // setting the pixmap, if the player has swines/hyperswines
      if (this->player->swines_has()
	  && this->player->hyperswines_has()) {
	icon = this->ui->icons->swines_hyperswines(this->player->game().trumpcolor(),
						   this->rotation());
      } else if (this->player->swines_has()) {
	icon = this->ui->icons->swines(this->player->game().trumpcolor(),
				       this->rotation());
      } else if (this->player->hyperswines_has()) {
	icon = this->ui->icons->hyperswines(this->player->game().trumpcolor(),
					    this->rotation());
      } // if !(player has swines/hyperswines)

      if (!icon)
	return ;

      this->table().pixmap->draw_pixbuf(this->table().gc,
					icon,
					0, 0,
					this->swines_start_x(icon->get_width()),
					this->swines_start_y(icon->get_height()),
					-1, -1,
					Gdk::RGB_DITHER_NONE,
					0, 0);

      if (update) {
	// ToDo: remove
	this->draw(false);
	this->name().draw(false);

	this->table().update(Gdk::Rectangle(this->swines_start_x(icon->get_width()),
					    this->swines_start_y(icon->get_height()),
					    icon->get_width(),
					    icon->get_height()));
      } // if (update)

      return ;
    } // void Icongroup::draw_swines(bool const update = true)

  /**
   **
   ** -> result
   **
   ** @param	width	the width of the icon
   **
   ** @return	upper left x position of the team/gametype icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::team_start_x(int const width) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
      case SOUTH:
	value = (this->hand().start_x()
		 + this->hand().width() / 3);
	break;
      case WEST:
	value = (this->hand().start_x()
		 + this->hand().width()
		 + this->hand().margin_x());
	break;
      case EAST:
	value = (this->hand().start_x()
		 - this->hand().margin_x()
		 - width);
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::team_start_x(int const width)

  /**
   **
   ** -> result
   **
   ** @param	height	the height of the icon
   **
   ** @return	upper left y position of the team/gametype icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::team_start_y(int const height) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
	value = (this->hand().start_y()
		 + this->hand().height()
		 + this->hand().margin_y());
	break;
      case SOUTH:
	value = (this->hand().start_y()
		 - this->hand().margin_y()
		 - height);
	break;
      case WEST:
      case EAST:
	value = this->hand().start_y();
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::team_start_y(int const height)

  /**
   **
   ** -> result
   **
   ** @param	width	the width of the icon
   **
   ** @return	upper left x position of the announcement icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::announcement_start_x(int const width) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
      case SOUTH:
	value = (this->hand().start_x()
		 + this->hand().width() * 2 / 3
		 - width / 2);
	break;
      case WEST:
	value = (this->hand().start_x()
		 + this->hand().width()
		 + this->hand().margin_x());
	break;
      case EAST:
	value = (this->hand().start_x()
		 - this->hand().margin_x()
		 - width);
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::announcement_start_x(int const width)

  /**
   **
   ** -> result
   **
   ** @param	height	the height of the icon
   **
   ** @return	upper left y position of the announcement icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::announcement_start_y(int const height) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
	value = (this->hand().start_y()
		 + this->hand().height()
		 + this->hand().margin_y());
	break;
      case SOUTH:
	value = (this->hand().start_y()
		 - this->hand().margin_y()
		 - height);
	break;
      case WEST:
      case EAST:
	value = (this->hand().start_y()
		 + this->hand().height() / 2
		 - height / 2);
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::announcement_start_y(int const height)

  /**
   **
   ** -> result
   **
   ** @param	width	the width of the icon
   **
   ** @return	upper left x position of the team icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::swines_start_x(int const width) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
      case SOUTH:
	value = (this->hand().start_x()
		 + this->hand().width()
		 - width);
	break;
      case WEST:
	value = (this->hand().start_x()
		 + this->hand().width()
		 + this->hand().margin_x());
	break;
      case EAST:
	value = (this->hand().start_x()
		 - this->hand().margin_x()
		 - width);
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::swines_start_x(int const width)

  /**
   **
   ** -> result
   **
   ** @param	height	the height of the icon
   **
   ** @return	upper left y position of the swines icon
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::swines_start_y(int const height) const
    {
      int value = 0;

      switch(this->position()) {
      case NORTH:
	value = (this->hand().start_y()
		 + this->hand().height()
		 + this->hand().margin_y());
	break;
      case SOUTH:
	value = (this->hand().start_y()
		 - this->hand().margin_y()
		 - height);
	break;
      case WEST:
      case EAST:
	value = (this->hand().start_y()
		 + this->hand().height()
		 - height);
	break;
      } // switch(this->position())

      return value;
    } // int Icongroup::swines_start_y(int const height)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the icongroup
   **
   ** @return	width of the icongroup at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::width(Position const position) const
    {
      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	DEBUG_ASSERTION(false,
			"Icongroup::width(position):\n"
			"  'position' is 'NORTH' or 'SOUTH'");
	break;
      case WEST:
      case EAST:
	value = this->ui->icons->max_height();
	break;
      } // switch(position)

      return value;
    } // int Icongroup::width(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the icongroup
   **
   ** @return	height of the icongroup at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::height(Position const position) const
    {
      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	value = this->ui->icons->max_height();
	break;
      case WEST:
      case EAST:
	DEBUG_ASSERTION(false,
			"Icongroup::height(position):\n"
			"  'position' is 'WEST' or 'EAST'");
	break;
      } // switch(position)

      return value;
    } // int Icongroup::height(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the icongroup
   **
   ** @return	width of the icongroup at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::margin_x(Position const position) const
    {
      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	DEBUG_ASSERTION(false,
			"Icongroup::margin_x(position):\n"
			"  'position' is 'NORTH' or 'SOUTH'");
	break;
      case WEST:
      case EAST:
	value = (this->ui->cards->height() / 10);
	break;
      } // switch(position)

      return value;
    } // int Icongroup::margin_x(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the icongroup
   **
   ** @return	margin_y of the icongroup at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::margin_y(Position const position) const
    {
      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	value = (this->ui->cards->height() / 10);
	break;
      case WEST:
      case EAST:
	DEBUG_ASSERTION(false,
			"Icongroup::margin_y(position):\n"
			"  'position' is 'WEST' or 'EAST'");
	break;
      } // switch(position)

      return value;
    } // int Icongroup::margin_y(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	width of the icongroup
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::width() const
    {
      return this->width(this->position());
    } // int Icongroup::width()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	height of the icongroup
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::height() const
    {
      return this->height(this->position());
    } // int Icongroup::height()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	margin_x of the icongroup
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::margin_x() const
    {
      return this->margin_x(this->position());
    } // int Icongroup::margin_x()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	margin_y of the icongroup
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Icongroup::margin_y() const
    {
      return this->margin_y(this->position());
    } // int Icongroup::margin_y()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
