/**********************************************************************
 *
 *   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_GTK

#include "trick.h"
#include "gtk_gui.h"
#include "card.h"
#include "table.h"

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

namespace GTK_DOKO {

  // margin of the cards of the trick
  // to the center of the trick (center of the hands)
#define TRICK_MARGIN_LEFT  int(-0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				       ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(1)) \
				       : this->gui().cards().width()))
#define TRICK_MARGIN_RIGHT int(-0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				       ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(3)) \
				       : this->gui().cards().width()))
#define TRICK_MARGIN_UP    int(-0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				       ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(2)) \
				       : this->gui().cards().width()))
#define TRICK_MARGIN_DOWN  int(-0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				       ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(0)) \
				       : this->gui().cards().width()))
// the cards of player 0,2 and 1,3 are not on the same colunm/row
#define TRICK_OFFSET_X int(0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				  ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(0)) \
				  : this->gui().cards().width()))
#define TRICK_OFFSET_Y int(0.1 * (::setting(Setting::ROTATE_TRICK_CARDS) \
				  ? this->gui().cards().width(const_cast<Game const&>(::party.game()).player(1)) \
				  : this->gui().cards().width()))

/*****************************************************************************
 *
 * Trick::Trick(Table const& table_a)
 *
 * Parameters:	table_a - the table, this trick belongs to
 *
 * Result:	none
 * 
 * Version:	0.3.6
 *
 * Description:	Inits the trick
 *
 ****************************************************************************/
Trick::Trick(Table* table_a) :
table_p(table_a)
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_INIT,
		"Trick::Trick()");

  DEBUG_RETURNING(VOID,
		  INFO_GTK_TRICK && INFO_GTK_INIT,
		  "Trick::Trick()");
} // Trick::Trick()

/*****************************************************************************
 *
 * void Trick::init()
 *
 * Parameters:	none
 *
 * Result:	none
 * 
 * Version:	0.3.7
 *
 * Description:	Inits the trick
 *
 ****************************************************************************/
void
Trick::init()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_INIT,
		"Trick::init()");

  DEBUG_RETURNING(VOID,
		  INFO_GTK_TRICK && INFO_GTK_INIT,
		  "Trick::init()");
} // void Trick::init()

/*****************************************************************************
 *
 * GTK_GUI& Trick::gui()
 *
 * Parameters:	none
 *
 * Result:	the gui
 *
 * Version:	0.3.7
 *
 * Description:	Result
 *
 ****************************************************************************/
GTK_GUI&
Trick::gui()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::gui()");

  DEBUG_RETURNING(table().gui(),
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::gui()");
} // GTK_GUI& Trick::gui()

/*****************************************************************************
 *
 * Table& Trick::table()
 *
 * Parameters:	none
 *
 * Result:	the table, this trick belongs to
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
Table&
Trick::table()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::table()");

  DEBUG_ASSERTION((table_p != NULL),
		  "Trick::table()\n"
		  "  `table_p` == NULL");

  DEBUG_RETURNING(*table_p,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::table()");
} // Table& Trick::table()


/*****************************************************************************
 *
 * double Trick::card_start_x(Player const& player)
 *
 * Parameters:	playerno - the cardnumber
 *
 * Result:	position of the card of the given player
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
int
Trick::card_start_x(Player const& player)
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::card_start_x(playerno)");

  int value = 0; // return value

  switch(player.no()) {
  case 0:
    if (setting(Setting::ROTATE_TRICK_CARDS))
      value = (table().hands().start_x()
	       + table().hands().width() / 2
	       - gui().cards().width(const_cast<Game const&>(::party.game()).player(0)) / 2
	       + TRICK_OFFSET_X);
    else
      value = (table().hands().start_x()
	       + table().hands().width() / 2
	       - gui().cards().width() / 2
	       + TRICK_OFFSET_X);
    break;
  case 1:
    if (setting(Setting::ROTATE_TRICK_CARDS))
      value = (table().hands().start_x()
	       + table().hands().width() / 2
	       - TRICK_MARGIN_LEFT
	       - gui().cards().width(const_cast<Game const&>(::party.game()).player(1)));
    else
      value = (table().hands().start_x()
	       + table().hands().width() / 2
	       - TRICK_MARGIN_LEFT
	       - gui().cards().width());
    break;
  case 2:
    value = (table().hands().start_x()
	     + table().hands().width() / 2
	     - gui().cards().width() / 2
	     - TRICK_OFFSET_X);
    break;
  case 3:
    value = (table().hands().start_x()
	     + table().hands().width() / 2
	     + TRICK_MARGIN_RIGHT);
    break;
  default:
    DEBUG_ASSERTION(true,
		    "Trick::card_start_x(player):\n"
		    "Illegal Value for player number");
  } // switch(playerno)

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::card_start_x(player)");
} // double Trick::card_start_x(Player const& player)

/*****************************************************************************
 *
 * double Trick::card_start_y(Player const& player)
 *
 * Parameters:	playerno - the cardnumber
 *
 * Result:	position of the card of the given player
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
int
Trick::card_start_y(Player const& player)
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::card_start_y(playerno)");

  int value = 0; // return value

  switch(player.no()) {
  case 0:
    value = (table().hands().start_y()
	     + table().hands().height() / 2
	     + TRICK_MARGIN_DOWN);
    break;
  case 1:
    if (setting(Setting::ROTATE_TRICK_CARDS))
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height(const_cast<Game const&>(::party.game()).player(3)) / 2
	       + TRICK_OFFSET_Y);
    else
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height() / 2
	       + TRICK_OFFSET_Y);
    break;
  case 2:
    if (setting(Setting::ROTATE_TRICK_CARDS))
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height(const_cast<Game const&>(::party.game()).player(2))
	       - TRICK_MARGIN_UP);
    else
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height()
	       - TRICK_MARGIN_UP);
    break;
  case 3:
    if (setting(Setting::ROTATE_TRICK_CARDS))
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height(const_cast<Game const&>(::party.game()).player(3)) / 2
	       - TRICK_OFFSET_Y);
    else
      value = (table().hands().start_y()
	       + table().hands().height() / 2
	       - gui().cards().height() / 2
	       - TRICK_OFFSET_Y);
    break;
  default:
    DEBUG_ASSERTION(true,
		    "Trick::card_start_x(player):\n"
		    "Illegal Value for player number");
  } // switch(playerno)

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::card_start_y(player)");
} // double Trick::card_start_y(Player const& player)

/*****************************************************************************
 *
 * int Trick::start_x()
 *
 * Parameters:	none
 *
 * Result:	Starting x position of the trick
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
int
Trick::start_x()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::start_x()");

  int value = 0; // return value

  if (setting(Setting::ROTATE_TRICK_CARDS))
    value = (table().hands().start_x()
	     + table().hands().width() / 2
	     - TRICK_MARGIN_LEFT
	     - gui().cards().width(const_cast<Game const&>(::party.game()).player(1)));
  else
    value = (table().hands().start_x()
	     + table().hands().width() / 2
	     - TRICK_MARGIN_LEFT
	     - gui().cards().width());

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::start_x()");
} // int Trick::start_x()

/*****************************************************************************
 *
 * int Trick::start_y()
 *
 * Parameters:	none
 *
 * Result:	Starting y position of the trick
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
int
Trick::start_y()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::start_y()");

  int value = 0; // return value

  if (setting(Setting::ROTATE_TRICK_CARDS))
    value = (table().hands().start_y()
	     + table().hands().height() / 2
	     - TRICK_MARGIN_UP
	     - gui().cards().height(const_cast<Game const&>(::party.game()).player(2)));
  else
    value = (table().hands().start_y()
	     + table().hands().height() / 2
	     - TRICK_MARGIN_UP
	     - gui().cards().height());

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::start_y()");
} // int Trick::start_y()

/*****************************************************************************
 *
 * int Trick::width()
 *
 * Parameters:	none
 *
 * Result:	width of the trick
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
unsigned
Trick::width()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::width()");

  int value = 0; // return value

  if (setting(Setting::ROTATE_TRICK_CARDS))
    value = (gui().cards().width(const_cast<Game const&>(::party.game()).player(1))
	     + gui().cards().width(const_cast<Game const&>(::party.game()).player(3))
	     + TRICK_MARGIN_LEFT
	     + TRICK_MARGIN_RIGHT);
  else
    value = (gui().cards().width()
	     + gui().cards().width()
	     + TRICK_MARGIN_LEFT
	     + TRICK_MARGIN_RIGHT);

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::width()");
} // unsigned Trick::width()


/*****************************************************************************
 *
 * int Trick::height()
 *
 * Parameters:	none
 *
 * Result:	height of the trick
 * 
 * Version:	0.3.6
 *
 * Description:	Result
 *
 ****************************************************************************/
unsigned
Trick::height()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_VALUE,
		"Trick::height()");

  int value = 0; // return value

  if (setting(Setting::ROTATE_TRICK_CARDS))
    value = (gui().cards().height(const_cast<Game const&>(::party.game()).player(0))
	     + gui().cards().height(const_cast<Game const&>(::party.game()).player(2))
	     + TRICK_MARGIN_UP
	     + TRICK_MARGIN_DOWN);
  else
    value = (gui().cards().height()
	     + gui().cards().height()
	     + TRICK_MARGIN_UP
	     + TRICK_MARGIN_DOWN);

  DEBUG_RETURNING(value,
		  INFO_GTK_TRICK && INFO_GTK_VALUE,
		  "Trick::height()");
} // unsigned Trick::height()

/*****************************************************************************
 *
 * void Trick::draw(Trick const& trick, bool const update)
 *
 * Parameters:	trick  - trick to draw
 * 		update - Whether the window should be updated (default: true)
 *
 * Result:	none
 * 
 * Version:	0.3.6
 *
 * Description:	Draws the trick in the table
 *
 ****************************************************************************/
void
Trick::draw(::Trick const& trick, bool const update)
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_DRAW,
		"Trick::draw(trick, update)");

  DEBUG_ASSERTION((table().pixmap() != NULL),
		  "Trick::draw:\n"
		  "'table().pixmap()' == NULL");

  // redraw the background
  table().background_draw(start_x(), start_y(),
			  width(), height());

  for (unsigned i = 0; i < trick.actcardno(); i++) {
    // draw the card
    if (setting(Setting::ROTATE_TRICK_CARDS))
      gui().cards().card(trick.card(i), trick.player_of_card(i)
			).draw(table().pixmap(),
			       card_start_x(trick.player_of_card(i)),
			       card_start_y(trick.player_of_card(i)));
    else
      gui().cards().card(trick.card(i)
			).draw(table().pixmap(),
			       card_start_x(trick.player_of_card(i)),
			       card_start_y(trick.player_of_card(i)));
  }

  // update the DrawingArea
  if (update) {
    table().update(start_x(), start_y(),
		   width(), height());
  }

  DEBUG_RETURNING(VOID,
		  INFO_GTK_TRICK && INFO_GTK_DRAW,
		  "Trick::draw(trick, update)");
} // Trick::draw(trick, update)


/*****************************************************************************
 *
 * void Trick::language_update()
 *
 * Parameters:	none
 *
 * Result:	none
 * 
 * Version:	0.3.6
 *
 * Description:	updates the language -- nothing to do
 *
 ****************************************************************************/
void
Trick::language_update()
{
  DEBUG_CALLING(INFO_GTK_TRICK && INFO_GTK_UPDATE,
		"Trick::language_update()");

  DEBUG_RETURNING(VOID,
		  INFO_GTK_TRICK && INFO_GTK_UPDATE,
		  "Trick::language_update()");
} // void Trick::language_update()

}
#endif
