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

#include "setting.cardsorder.h"

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

#include "setting.h"
#include "translator.h"
#include "../party/party.h"

#include "../ui/ui.h"


/**********************************************************************
 *
 ** CardsOrder::CardsOrder()
 *
 ** Parameters:	none
 *
 ** Result:	none
 *
 ** Version:	0.3.7
 *
 ** Description:	Constructor
 **   
 **********************************************************************/
CardsOrder::CardsOrder() :
sorted_p(false),
  pos_p(Card::NUMBER_OF_TCOLORS, Card::NOCARDCOLOR),
direction_p(Card::NUMBER_OF_TCOLORS, DOWN)
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::CardsOrder()");

  this->pos_p[Card::TRUMP] = 0;
  this->pos_p[Card::CLUB] = 1;
  this->pos_p[Card::HEART] = 2;
  this->pos_p[Card::SPADE] = 3;
  this->pos_p[Card::DIAMOND] = 4;

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::CardsOrder()");
} // CardsOrder::CardsOrder()

/**********************************************************************
 *
 ** CardsOrder::CardsOrder()
 *
 ** Parameters:	tcolors (in order) and direction
 *
 ** Result:	none
 *
 ** Version:	0.3.7
 *
 ** Description:	Constructor
 **   
 **********************************************************************/
CardsOrder::CardsOrder(Card::TColor c0, Direction d0,
		       Card::TColor c1, Direction d1,
		       Card::TColor c2, Direction d2,
		       Card::TColor c3, Direction d3,
		       Card::TColor c4, Direction d4) :
sorted_p(true),
  pos_p(Card::NUMBER_OF_TCOLORS, Card::NOCARDCOLOR),
direction_p(Card::NUMBER_OF_TCOLORS, DOWN)
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::CardsOrder()");

  // the colors should be different
  this->pos_p[c0] = 0;
  this->pos_p[c1] = 1;
  this->pos_p[c2] = 2;
  this->pos_p[c3] = 3;
  this->pos_p[c4] = 4;

  this->direction_p[c0] = d0;
  this->direction_p[c1] = d1;
  this->direction_p[c2] = d2;
  this->direction_p[c3] = d3;
  this->direction_p[c4] = d4;

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::CardsOrder()");
} // CardsOrder::CardsOrder(TColoor, Direction, ...)

/**********************************************************************
 *
 ** CardsOrder::CardsOrder(string)
 *
 ** Parameters:	string with the order settings
 *
 ** Result:	none
 *
 ** Version:	0.4.2
 *
 ** Description:	Constructor
 **   
 **********************************************************************/
CardsOrder::CardsOrder(string const& value) :
sorted_p(true),
  pos_p(Card::NUMBER_OF_TCOLORS, Card::NOCARDCOLOR),
direction_p(Card::NUMBER_OF_TCOLORS, DOWN)
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::CardsOrder(string)");

  // *** should work better, when you can get words of the string
  // *** (expand the string-class)
  string remain_string = value;
  string word; // the word of the string
  Card::TColor tcolor = Card::NOCARDCOLOR;

  DK::Utils::String::remove_blanks(remain_string);
  for (unsigned i = 0; i < Card::NUMBER_OF_TCOLORS; i++) {
    if (remain_string.size() == 0)
      break;
    // get the color
    word = string(remain_string, 0, remain_string.find(' '));
    if (remain_string.find(' ') == string::npos)
      word = remain_string;
    if ((word == name(Card::TRUMP))
	|| (word == ::translator("trump")))
      tcolor = Card::TRUMP;
    else if ((word == name(Card::CLUB))
	     || (word == ::translator(Card::CLUB)))
      tcolor = Card::CLUB;
    else if ((word == name(Card::SPADE))
	     || (word == ::translator(Card::SPADE)))
      tcolor = Card::SPADE;
    else if ((word == name(Card::HEART))
	     || (word == ::translator(Card::HEART)))
      tcolor = Card::HEART;
    else if ((word == name(Card::DIAMOND))
	     || (word == ::translator(Card::DIAMOND)))
      tcolor = Card::DIAMOND;
    else if ((i == 0)
	     && ((word == "unsorted") || (word == ::translator("unsorted"))
		 || (word == "random") || (word == ::translator("random"))
		 || (word == "mixed") || (word == ::translator("mixed"))
		)
	    ) {
      // random order
      this->sorted_p = false;
      break;
    } else {
      cerr << "Unknown TColor \"" << word << "\"" << endl;
      break ;
    }

    if (!this->sorted())
      break;

    Direction direction;

    // remove the used word from the string
    if (remain_string.length() == 0)
      break;
    remain_string = string(remain_string, word.length(), std::string::npos);
    DK::Utils::String::remove_blanks(remain_string);

    // get the direction
    word = string(remain_string, 0, remain_string.find(' '));
    if (remain_string.find(' ') == string::npos)
      word = remain_string;
    if ((word == name(CardsOrder::UP))
	|| (word == ::translator(name(CardsOrder::UP)))
	|| (word == name(CardsOrder::UP) + ",")
	|| (word == ::translator(name(CardsOrder::UP)) + ","))
      direction = UP;
    else if ((word == name(CardsOrder::DOWN))
	     || (word == ::translator(name(CardsOrder::DOWN)))
	     || (word == name(CardsOrder::DOWN) + ",")
	     || (word == ::translator(name(CardsOrder::DOWN)) + ","))
      direction = DOWN;
    else {
      cerr << "Unknown direction \"" << word << "\"" << endl;
      break ;
    }

    // removed the used word from the string
    remain_string = string(remain_string, word.length(), std::string::npos);
    DK::Utils::String::remove_blanks(remain_string);

    // set the position of the tcolor and the direction
    this->pos_p[tcolor] = i;
    this->direction_p[tcolor] = direction;
  } // for (i < Card::NUMBER_OF_TCOLORS)

  // *** ToDo DK
  // test, whether all colors are used

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::CardsOrder(string)");
} // CardsOrder::CardsOrder(string)

/**********************************************************************
 *
 ** CardsOrder::CardsOrder(CardsOrder const& order)
 *
 ** Parameters:	order - new order
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description:	constructor
 **   
 **********************************************************************/
CardsOrder::CardsOrder(CardsOrder const& order) :
sorted_p(order.sorted_p),
  pos_p(order.pos_p),
direction_p(order.direction_p)
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::CardsOrder(CardsOrder)");

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::CardsOrder(CardsOrder)");
} // CardsOrder::CardsOrder(CardsOrder const& order)

/**********************************************************************
 *
 ** CardsOrder& CardsOrder::operator=(CardsOrder const& order)
 *
 ** Parameters:	order - new order
 *
 ** Result:	order
 *
 ** Version:	0.3.7
 *
 ** Description:	setting equal
 **   
 **********************************************************************/
CardsOrder&
CardsOrder::operator=(CardsOrder const& order)
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::operator=(CardsOrder)");

  this->pos_p = order.pos_p;
  this->direction_p = order.direction_p;
  this->sorted_p = order.sorted_p;

  DEBUG_RETURNING(*this,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::operator=(CardsOrder)");
} // CardsORder& CardsOrder::operator=(CardsOrder const& order)

/**********************************************************************
 *
 ** CardsOrder::~CardsOrder()
 *
 ** Parameters:	none
 *
 ** Result:	none
 *
 ** Version:	0.3.7
 *
 ** Description:	Destructor (nothing to do)
 **   
 **********************************************************************/
CardsOrder::~CardsOrder()
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"CardsOrder::~CardsOrder()");

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "CardsOrder::~CardsOrder()");
} // CardsORder::~CardsOrder()

/**********************************************************************
 *
 ** CardsOrder::operator bool() const
 *
 ** Parameters:	none
 *
 ** Result:	whether the cards are sorted
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
CardsOrder::operator bool() const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::operator bool()");

  DEBUG_RETURNING(this->sorted(),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::operator bool()");
} // CardsOrder::operator bool()

/**********************************************************************
 *
 ** CardsOrder::operator string() const
 *
 ** Parameters:	-
 *
 ** Result:	the order as string
 *
 ** Version:	0.4.2
 *
 ** Description:	-> result
 **   
 **********************************************************************/
CardsOrder::operator string() const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::operator string()");

  string value;

  if (this->sorted()) {
    for (unsigned c = 0; c < Card::NUMBER_OF_TCOLORS; c++) {
      value += name(this->tcolor(c)) + " " + name(this->direction(c));
      if (c + 1 < Card::NUMBER_OF_TCOLORS)
	value += ", ";
    } // for (c < Card::NUMBER_OF_TCOLORS))
  } else { // if !(this->sorted())
    value = "mixed";
  } // if !(this->sorted())

  DEBUG_RETURNING(value,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::operator string()");
} // CardsOrder::operator string()

/**********************************************************************
 *
 ** bool CardsOrder::operator==(CardsOrder const& order)
 *
 ** Parameters:	order - order to compare with
 *
 ** Result:	whether the orders are equal
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
bool
CardsOrder::operator==(CardsOrder const& order) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::operator==(CardsOrder)");

  if (this->sorted() != order.sorted()) {
    DEBUG_RETURNING(false,
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::operator==(CardsOrder)");
  }

  for(unsigned i = 0; i < Card::NUMBER_OF_TCOLORS; i++)
    if ( (this->tcolor(i) != order.tcolor(i))
	 || (this->direction(i) != order.direction(i)) ) {
      DEBUG_RETURNING(false,
		      INFO_SETTING && INFO_VALUE,
		      "CardsOrder::operator==(CardsOrder)");
    }

  DEBUG_RETURNING(true,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::operator==(CardsOrder)");
} // bool CardsOrder::operator==(CardsOrder const& order) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the cards are sorted
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **   
 **/
bool
CardsOrder::sorted() const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::sorted()");

  DEBUG_RETURNING(this->sorted_p,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::sorted()");
} // bool CardsOrder::sorted() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the cards are mixed
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **   
 **/
bool
CardsOrder::mixed() const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::mixed()");

  DEBUG_RETURNING(!(this->sorted()),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::mixed()");
} // bool CardsOrder::mixed() const

/**
 ** -> result
 **
 ** @param	a	first card
 ** @param	b	second card
 **
 ** @return	the relative position of b to a,
 **		t.i. -1, if a < b, 0 if a == b, 1, if a > b
 **
 ** @author	Diether Knof
 **
 ** @version 0.6.8
 **
 **/
int
CardsOrder::relative_position(HandCard const& a, HandCard const& b) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::relative_position(Card, Card)");

  if ((this->pos(a.tcolor()) < this->pos(b.tcolor()))) {
    DEBUG_RETURNING(-1,
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::operator(Card, Card)");
  }
  if ((this->pos(a.tcolor())) > this->pos(b.tcolor())) {
    DEBUG_RETURNING(1,
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::operator(Card, Card)");
  }

  // the two cards are the same color
  if (a == b) {
    DEBUG_RETURNING(0,
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::relative_position(Card, Card)");
  }
  if (a.less(b)) {
    DEBUG_RETURNING(((this->direction(a.tcolor()) == UP) ? -1 : 1),
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::relative_position(Card, Card)");
  } else {
    DEBUG_RETURNING(((this->direction(a.tcolor()) == UP) ? 1 : -1),
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::relative_position(Card, Card)");
  }
} // int CardsOrder::relative_position(HandCard a, HandCard b)

/**********************************************************************
 *
 ** Direction CardsOrder::direction(const Card::TColor tcolor)
 *
 ** Parameters:	tcolor - color
 *
 ** Result:	direction of the color (UP or DOWN)
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
CardsOrder::Direction
CardsOrder::direction(const Card::TColor tcolor) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction(Card::TColor)");

  DEBUG_RETURNING(this->direction_p[tcolor],
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction(Card::TColor)");
} // CardsOrder::Direction CardsOrder::direction(const Card::TColor tcolor) const

/**********************************************************************
 *
 ** Direction CardsOrder::direction(unsigned const pos) const
 *
 ** Parameters:	position
 *
 ** Result:	direction of the color on the given position
 *
 ** Version:	0.3.7
 *
 ** Description:	Result
 **   
 **********************************************************************/
CardsOrder::Direction
CardsOrder::direction(unsigned const pos_a) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction(pos)");

  for (unsigned tcolor = 0; tcolor < Card::NUMBER_OF_TCOLORS; tcolor++)
    if (this->pos_p[tcolor] == pos_a) {
      DEBUG_RETURNING(this->direction_p[tcolor],
		      INFO_SETTING && INFO_VALUE,
		      "CardsOrder::direction(pos)");
    }

  DEBUG_RETURNING(NONE,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction(pos)");
} // CardsOrder::Direction CardsOrder::direction(unsigned const pos_a) const

/**********************************************************************
 *
 ** CardTColor CardsOrder::pos(Card constTColor)
 *
 ** Parameters:	tcolor - color
 *
 ** Result:	position of the tcolor
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
unsigned
CardsOrder::pos(const Card::TColor tcolor) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::pos(Card::TColor)");

  DEBUG_RETURNING(this->pos_p[tcolor],
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::pos(Card::TColor)");
} // unsigned CardsOrder::pos(const Card::TColor tcolor) const

/**********************************************************************
 *
 ** CardTColor CardsOrder::tcolor(unsigned const pos)
 *
 ** Parameters:	pos - position
 *
 ** Result:	tcolor on the given position
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
Card::TColor
CardsOrder::tcolor(unsigned const pos_a) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::pos(Card::TColor)");

  for (unsigned tcolor = 0; tcolor < 5; tcolor++)
    if (this->pos_p[tcolor] == pos_a) {
      DEBUG_RETURNING(Card::TColor(tcolor),
		      INFO_SETTING && INFO_VALUE,
		      "CardsOrder::pos(Card::TColor)");
    }

  DEBUG_RETURNING(Card::NOCARDCOLOR,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::pos(Card::TColor)");
} // Card::TColor CardsOrder::tcolor(unsigned const pos_a) const

/**********************************************************************
 *
 ** Direction CardsOrder::direction_toggle(const Card::TColor tcolor)
 *
 ** Parameters:	tcolor - color
 *
 ** Result:	direction of the color on the given position
 *
 ** Version:	0.3.7
 *
 ** Description:	toggles the direction
 **   
 **********************************************************************/
CardsOrder::Direction
CardsOrder::direction_toggle(const Card::TColor tcolor)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction_toggle(Card::TColor)");

  CardsOrder const old_value = *this;

  this->direction_p[tcolor] = ( (direction(tcolor) == CardsOrder::UP)
				? CardsOrder::DOWN
				: CardsOrder::UP);

  // resort the hands
  if (game_status & GAMESTATUS::GAME)
    ::party.game().players_hands_sort();

  if ((this == &(::setting(Setting::CARDS_ORDER)))
      && (ui != NULL))
    ui->setting_update(Setting::CARDS_ORDER, &old_value);

  DEBUG_RETURNING(this->direction(tcolor),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction_toggle(Card::TColor)");
} // CardsOrder::Direction CardsOrder::direction_toggle(const Card::TColor tcolor)

/**********************************************************************
 *
 ** Direction CardsOrder::direction_toggle(unsigned const pos)
 *
 ** Parameters:	pos - position
 *
 ** Result:	direction of the color on the given position
 *
 ** Version:	0.3.7
 *
 ** Description:	toggles the direction
 **   
 **********************************************************************/
CardsOrder::Direction
CardsOrder::direction_toggle(unsigned const pos_a)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction_toggle(pos)");

  CardsOrder const old_value = *this;

  for (unsigned tcolor = 0; tcolor < 5; tcolor++)
    if (this->pos_p[tcolor] == pos_a)
      this->direction_p[tcolor] = ( (direction(pos_a) == CardsOrder::UP)
				    ? CardsOrder::DOWN
				    : CardsOrder::UP);

  // resort the hands
  if (game_status & GAMESTATUS::GAME)
    ::party.game().players_hands_sort();

  if ((this == &(::setting(Setting::CARDS_ORDER)))
      && (ui != NULL))
    ui->setting_update(Setting::CARDS_ORDER, &old_value);

  DEBUG_RETURNING(this->direction(pos_a),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction_toggle(pos)");
} // CardsOrder::Direction CardsOrder::direction_toggle(unsigned const pos_a)

/**
 **
 ** sets the direction of the given color
 **
 ** @param	tcolor		color
 ** @param	direction	new direction
 **
 ** @return	direction of the color on the given position
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **   
 **/
CardsOrder::Direction
CardsOrder::direction_set(Card::TColor const tcolor, Direction const direction)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction_set(tcolor, direction)");

  CardsOrder const old_value = *this;

  if (this->direction(tcolor) == direction)
    // nothing to do
    DEBUG_RETURNING(this->direction(tcolor),
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::direction_set(tcolor, direction)");

  this->direction_p[tcolor] = direction;

  // resort the hands
  if (game_status & GAMESTATUS::GAME)
    ::party.game().players_hands_sort();

  if ((this == &(::setting(Setting::CARDS_ORDER)))
      && (ui != NULL))
    ui->setting_update(Setting::CARDS_ORDER, &old_value);

  DEBUG_RETURNING(this->direction(tcolor),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction_set(tcolor, direction)");
} // CardsOrder::Direction CardsOrder::direction_set(Card::TColor const tcolor, Direction const direction)

/**
 **
 ** sets the direction at the given position
 **
 ** @param	pos		position
 ** @param	direction	new direction
 **
 ** @return	new direction
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **   
 **/
CardsOrder::Direction
CardsOrder::direction_set(unsigned const pos, Direction const direction)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::direction_set(pos, direction)");

  DEBUG_RETURNING(this->direction_set(this->tcolor(pos), direction),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::direction_set(pos, direction)");
} // CardsOrder::Direction CardsOrder::direction_set(unsigned const pos, Direction const direction)

/**********************************************************************
 *
 ** Card::TColor CardsOrder::pos_to_left(unsigned const p)
 *
 ** Parameters:	p - position
 *
 ** Result:	the moved color
 *
 ** Version:	0.3.7
 *
 ** Description:	pushes the color on 'p' one position to the left
 **   
 **********************************************************************/
Card::TColor
CardsOrder::pos_to_left(unsigned const p)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::pos_to_left()");

  CardsOrder const old_value = *this;

  unsigned c;
  for (c = 0; c < Card::NUMBER_OF_TCOLORS; c++) {
    if (this->pos(Card::TColor(c)) == p)
      this->pos_p[c] = (p - 1 + Card::NUMBER_OF_TCOLORS) % Card::NUMBER_OF_TCOLORS;
    else if ( ((pos(Card::TColor(c)) + Card::NUMBER_OF_TCOLORS)
	       % Card::NUMBER_OF_TCOLORS)
	      == (p - 1 + Card::NUMBER_OF_TCOLORS) % Card::NUMBER_OF_TCOLORS)
      this->pos_p[c] = p;
  }

  // resort the hands
  if (game_status & GAMESTATUS::GAME)
    ::party.game().players_hands_sort();

  if ((this == &(::setting(Setting::CARDS_ORDER)))
      && (ui != NULL))
    ui->setting_update(Setting::CARDS_ORDER, &old_value);

  for (c = 0; c < Card::NUMBER_OF_TCOLORS; c++) {
    if (this->pos(Card::TColor(c))
	== (p - 1 + Card::NUMBER_OF_TCOLORS) % Card::NUMBER_OF_TCOLORS) {
      DEBUG_RETURNING(Card::TColor(c),
		      INFO_SETTING && INFO_VALUE,
		      "CardsOrder::pos_to_left()");
    }
  }

  DEBUG_RETURNING(Card::NOCARDCOLOR,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::pos_to_left()");
} // Card::TColor CardsOrder::pos_to_left(unsigned const p)

/**********************************************************************
 *
 ** Card::TColor CardsOrder::pos_to_right(unsigned const p)
 *
 ** Parameters:	p - position
 *
 ** Result:	the moved color
 *
 ** Version:	0.3.7
 *
 ** Description:	pushes the color on 'p' one position to the right
 **   
 **********************************************************************/
Card::TColor
CardsOrder::pos_to_right(unsigned const p)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::pos_to_left()");

  this->pos_to_left(p + 1);

  for (unsigned c = 0; c < Card::NUMBER_OF_TCOLORS; c++)
    if (this->pos(Card::TColor(c)) == (p + 1) % Card::NUMBER_OF_TCOLORS)
      DEBUG_RETURNING(Card::TColor(c),
		      INFO_SETTING && INFO_VALUE,
		      "CardsOrder::pos_to_right()");

  DEBUG_RETURNING(Card::NOCARDCOLOR,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::pos_to_right()");
} // Card::TColor CardsOrder::pos_to_right(unsigned const p)

/**
 **
 ** set whether the cards are to be sorted
 **
 ** @param	s	whether the cards are to be sorted
 **
 ** @return	whether the cards are sorted
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **   
 **/
bool
CardsOrder::sorted_set(bool const s)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::sorted_set()");

  if (this->sorted() == s)
    DEBUG_RETURNING(this->sorted(),
		    INFO_SETTING && INFO_VALUE,
		    "CardsOrder::sorted_set()");

  CardsOrder const old_value = *this;

  this->sorted_p = s;

  if (this == &(::setting(Setting::CARDS_ORDER))) {
    // resort the hands
    if (game_status & GAMESTATUS::GAME)
      if (this->sorted())
	::party.game().players_hands_sort();
      else
	::party.game().players_hands_mix();

    if (ui != NULL)
      ui->setting_update(Setting::CARDS_ORDER, &old_value);
  } // if (this == &(::setting(Setting::CARDS_ORDER)))

  DEBUG_RETURNING(this->sorted(),
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::sorted_set()");
} // bool CardsOrder::sorted_set(bool const s)

/**
 **
 ** mix the cards
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **   
 **/
void
CardsOrder::mix()
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"CardsOrder::mix()");


  CardsOrder const old_value = *this;

  this->sorted_p = false;

  if (this == &(::setting(Setting::CARDS_ORDER))) {
    // resort the hands
    if (game_status & GAMESTATUS::GAME)
      if (!this->sorted())
	::party.game().players_hands_mix();

    if (::ui != NULL)
      ::ui->setting_update(Setting::CARDS_ORDER, &old_value);
  } // if (this == &(::setting(Setting::CARDS_ORDER)))

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_VALUE,
		  "CardsOrder::mix()");
} // void CardsOrder::mix()

/**********************************************************************
 *
 ** string name(CardsOrder::Direction const& direction)
 *
 ** Parameters:	direction - the direction
 *
 ** Result:	name of the direction
 *
 ** Version:	0.4.2
 *
 ** Description:	-> result
 *
 **********************************************************************/
string
name(CardsOrder::Direction const& direction)
{
  DEBUG_CALLING(INFO_GAMESTATUS && INFO_NAME,
		"string name(CardsOrder::Direction)");

  string name;

  switch(direction) {
  case CardsOrder::NONE:
    name = "none";
    break;
  case CardsOrder::UP:
    name = "up";
    break;
  case CardsOrder::DOWN:
    name = "down";
    break;
  default:
    DEBUG_ASSERTION(false,
		    "name(CardsOrder::Direction):\n"
		    "  unknown direction");
    break;
  } // switch(direction)

  DEBUG_RETURNING(name,
		  INFO_GAMESTATUS && INFO_NAME,
		  "string name(CardsOrder::Direction)");
} // string name(CardsOrder::Direction const& direction)


/**********************************************************************
 *
 ** ostream& CardsOrder::out(ostream& ostr) const
 *
 ** Parameters:	ostr - ouput stream
 *
 ** Result:	output stream
 *
 ** Version:	0.4.2
 *
 ** Description:	prints the cards order in the ouput stream
 *
 **********************************************************************/
ostream&
CardsOrder::out(ostream& ostr) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"CardsOrder::out(ostream)");

  if (this->sorted()) {
    ostr << this->tcolor(0) << " " << name(this->direction(0));
    for (unsigned i = 1; i < Card::NUMBER_OF_TCOLORS; i++)
      ostr << ", " << this->tcolor(i) << " " << name(this->direction(i));
  } else { // if !(this->sorted())
    ostr << "mixed";
  } // if !(this->sorted())

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "CardsOrder::out(ostream)");
} // ostream& CardsOrder::out(ostream& ostr) const

/**********************************************************************
 *
 ** operator<<(ostream& ostr, CardsOrder const& cards_order)
 *
 ** Parameters:	ostr - ouput stream
 *		cards_order - CardsOrder
 *
 ** Result:	output stream
 *
 ** Version:	0.4.1
 *
 ** Description:	prints the cards_order in the ouput stream
 *
 **********************************************************************/

ostream&
operator<<(ostream& ostr, CardsOrder const& cards_order)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, cards_order)");

  cards_order.out(ostr);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, cards_order)");
} // ostream& operator<<(ostream& ostr, CardsOrder const& cards_order)
