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

#include "gamepointstable.h"

#include "../party/party.h"


/**********************************************************************
 *
 **    GamePointsTable::GamePointsTable(vector<string>names, int rp)
 *
 **    Parameters: names of players and remainingpoints
 *
 **    Result: Initizilized GamePointsTable
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/
GamePointsTable::GamePointsTable(vector<string> names,int rp,CountingType ct,PointsTableStyle st):
remainingpoints_p(rp)
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_INIT,"GamePointsTable::GamePointsTable()");
  unsigned i;
  names_p=vector<string>(party.playerno());
  if (!names.empty())
    for ( i = 0; i < ::party.playerno(); i++)
      names_p[i]=names[i];
  gamepoints_p=vector<GamePoints>();
  points_p=vector<int>(party.playerno());
  gameno_p=0;
  countingtype_p=ct;
  style_p=st;
  sum_p=0;
  DEBUG_RETURNING_N(INFO_GAMEPOINTSTABLE && INFO_INIT,"GamePointsTable::GamePointsTable()");
}


/**********************************************************************
 *
 **    GamePointsTable::~GamePointsTable()
 *
 **    Parameters:  
 *
 **    Result: detroyed GamePointsTabel
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

GamePointsTable::~GamePointsTable()
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_INIT,"GamePointsTable::~GamePointsTable()");
  DEBUG_RETURNING_N(INFO_GAMEPOINTSTABLE && INFO_INIT,"GamePointsTable::~GamePointsTable()");
}


/**********************************************************************
 *
 **    GamePointsTable& GamePointsTable::operator=(GamePointsTable const& g)
 *
 **    Parameters:  GamePointsTable to copy
 *
 **    Result: copy of g
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

GamePointsTable& GamePointsTable::operator=(GamePointsTable const& g)
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::operator=");
  unsigned i;

  gameno_p=g.gameno_p;
  remainingpoints_p=g.remainingpoints_p;

  this->gamepoints_p.clear();
  this->gamepoints_p.reserve(this->gameno_p);

  for (i = 0; i < gameno_p; i++)
    this->gamepoints_p.push_back(g.gamepoints_p[i]);


  points_p=vector<int>(party.playerno());

  names_p=vector<string>(party.playerno());

  for ( i = 0; i < party.playerno(); i++)
  {
    names_p[i]=g.names_p[i];
    points_p[i]=g.points_p[i];
  }

  countingtype_p=g.countingtype_p;
  style_p=g.style_p;
  sum_p=g.sum_p;

  DEBUG_RETURNING(*this,INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::operator=");
}


/**********************************************************************
 *
 **    GamePoints GamePointsTable::gamepoints(unsigned i)
 *
 **    Parameters: number of the game, which points should be
 **                result of this function
 *
 **    Result: GamePoints of game i if i is legal
 **            otherwise the points of the last game
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

GamePoints GamePointsTable::gamepoints(unsigned i) const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE,
		"GamePoints GamePointsTable::gamepoints(unsigned i)");

  DEBUG_ASSERTION((i < this->gamepoints_p.size()),
		  "GamePointsTable::gamepoints()\n"
		  << "  illegal value " << i
		  << ", max is " << this->gamepoints_p.size());

  DEBUG_RETURNING(this->gamepoints_p[i],
		  INFO_GAMEPOINTSTABLE && INFO_VALUE,
		  "GamePoints GamePointsTable::gamepoints(unsigned i)");
}

/**********************************************************************
 *
 **    void GamePointsTable::addgamepoints(GamePoints p)
 *
 **    Parameters: result of last game
 *
 **    Result: GamePointsTable with new value p at new last position
 *
 **    Version: Alpha
 *
 **    Description: 
 *
 *
 **********************************************************************/

void GamePointsTable::add(GamePoints const& p)
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_GAMEPLAY,"GamePointsTable::addgamepoints(GamePoints const& p)");
  unsigned i;

  unsigned los_mod = 1;

  gamepoints_p.push_back(p);

  if (GAMETYPE::is_solo(p.gametype()))
  {
    if (p.winnerteam() == TEAM::CONTRA) {
      los_mod=3;
    }
  }

  for ( i = 0; i<party.playerno(); i++)
  {

    if (p.winnerteam() == TEAM::NOTEAM) {
      switch(this->countingtype_p) {
      case COUNTINGTYPE::PLUS:
	if ( (p.points() > 0)
	     && (p.team(i) == TEAM::RE))
	  points_p[i] += p.points();
	if ( (p.points() < 0)
	     && (p.team(i) == TEAM::CONTRA))
	  points_p[i] += std::abs(p.points());

	break;
      case COUNTINGTYPE::MINUS:
	if ( (p.points() < 0)
	     && (p.team(i) != TEAM::RE))
	  points_p[i] -= p.points();
	if ( (p.points() > 0)
	     && (p.team(i) != TEAM::CONTRA))
	  points_p[i] -= std::abs(p.points());

	break;
      case COUNTINGTYPE::PLUSMINUS:
	if ( (p.points() > 0)
	     && (p.team(i) == TEAM::RE))
	  points_p[i] += p.points();
	if ( (p.points() > 0)
	     && (p.team(i) == TEAM::CONTRA))
	  points_p[i] -= std::abs(p.points());
	if ( (p.points() < 0)
	     && (p.team(i) == TEAM::CONTRA))
	  points_p[i] += std::abs(p.points());
	if ( (p.points() < 0)
	     && (p.team(i) == TEAM::RE))
	  points_p[i] -= std::abs(p.points());
	break;
      } // switch(countingtype)


    } else { // if !(p.winnerteam() == TEAM::NOTEAM)
      if (countingtype_p==COUNTINGTYPE::PLUS)
	if (p.winnerteam()==p.team(i))
	  (points_p[i])+=p.points();

      if (countingtype_p==COUNTINGTYPE::MINUS)
	if (p.winnerteam()!=p.team(i))
	  (points_p[i])-=los_mod*p.points();

      if (countingtype_p==COUNTINGTYPE::PLUSMINUS)
	if (p.winnerteam()!=p.team(i))
	{
	  (points_p[i])-=los_mod*p.points();
	} else
	{
	  (points_p[i])-=p.points();
	}
    } // if !(p.winnerteam() == TEAM::NOTEAM)
  }
  if (remainingpoints_p!=-1)
    remainingpoints_p-=(los_mod)*p.points();
  sum_p+=(los_mod)*p.points();

  gameno_p += 1;

  DEBUG_RETURNING_N(INFO_GAMEPOINTSTABLE && INFO_GAMEPLAY,"GamePointsTable::addgamepoints(GamePoints const& p)");
}

/**********************************************************************
 *
 **    string GamePointsTable::name(unsigned i)
 *
 **    Parameters: number of the player, which name should be the result
 **                of this function
 *
 **    Result: name of player i, if i is legal
 **            otherwise NULL
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

string const
GamePointsTable::name(unsigned const i) const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::name(unsigned const i)");
  if (i<party.playerno())
  {
    DEBUG_RETURNING(names_p[i],INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::name(unsigned const i)");
  } else
  {
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function GamePointsTable::name()\n"
		    << "  illegal value " << i);

    DEBUG_RETURNING(string(),INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::name(unsigned const i)");
  }
}

/**********************************************************************
 *
 **    int GamePointsTable::remainingpoints()
 *
 **    Parameters:  
 *
 **    Result: remainingpoints
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

int
GamePointsTable::remainingpoints() const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::remainingpoints()");
  DEBUG_RETURNING(remainingpoints_p,INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::remainingpoints()");
}


/**********************************************************************
 *
 **    unsigned GamePointsTable::gameno()
 *
 **    Parameters:  
 *
 **    Result: number of games in table
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/
unsigned
GamePointsTable::gameno() const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::gameno()");
  DEBUG_RETURNING(gameno_p,INFO_GAMEPOINTSTABLE && INFO_VALUE,"GamePointsTable::gameno()");
}


/**********************************************************************
 *
 **    GamePointsTable::points(unsigned i)
 *
 **    Parameters: number of player, which should be result f this function 
 *
 **    Result: points of player i if i is legal
 **            otherwise -1
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

int GamePointsTable::points(unsigned const i) const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::points(unsigned const i)");
  if (i<party.playerno() && !points_p.empty())
  {  
    DEBUG_RETURNING(points_p[i],INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::points(unsigned const i)");
  }else
  {
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function GamePointsTable::points()\n"
		    << "  illegal value " << i);

    DEBUG_RETURNING(-1,INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::points(unsigned const i)");
  }      
}

/**********************************************************************
 *
 **    GamePointsTable::SumOfPoints()
 *
 **    Parameters: 
 *
 **    Result: played points
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

int GamePointsTable::SumOfPoints() const
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::points(unsigned const i)");

  DEBUG_RETURNING(sum_p,INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::points(unsigned const i)");       
}

/**********************************************************************
 *
 **    CountingType  GamePointsTable::countingtype()
 *
 **    Parameters: 
 *
 **    Result: counting type (plus, minus, plus-minus)
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/
CountingType  GamePointsTable::countingtype()
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::countingtype()");
  DEBUG_RETURNING(countingtype_p,INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::countingtype()");
}

/**********************************************************************
 *
 **    PointsTableStyle GamePointsTable::style()
 *
 **    Parameters:  
 *
 **    Result: table style (suming or single points)
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/   

PointsTableStyle GamePointsTable::style()
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::style()");
  DEBUG_RETURNING(style_p,INFO_GAMEPOINTSTABLE && INFO_VALUE," GamePointsTable::style()");
}

/**********************************************************************
 *
 **    ostream& operator<<(ostream& ostr, GamePointsTable const& g)
 *
 **    Parameters:  output stream, and gamepoitnstable to be printed
 *
 **    Result: printed g
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

ostream& operator<<(ostream& ostr, GamePointsTable const& g)
{
  DEBUG_CALLING(INFO_GAMEPOINTSTABLE && INFO_OTHER_FUNCTION,"operator<<(ostream& ostr, GamePointsTable const& g)");

  unsigned i,n,x;

  ostr<<"score:\n";
  for ( i = 0; i < party.playerno(); i++)
  {
    ostr<<"|";
    ostr<<g.name(i);
    for ( n=g.name(i).length(); n<11;n++)
      ostr<<" ";
  }
  ostr<<"|\n";

  for( x = 0; x < g.gameno(); x++) {
    GamePoints const& gp=g.gamepoints(x);
    for ( i = 0; i < party.playerno(); i++) {
      ostr << "|";
      if (gp.winnerteam()==gp.team(i))
	ostr << setw(11) << gp.points();
      else
	ostr << setw(11) << "0";
    }
    ostr<<"|\n";
  }
  ostr << "\n";

  for ( i = 0; i < party.playerno(); i++) {
    ostr << "|"
      << setw(11) << g.points(i);
  }
  ostr<<"|\n";

  if (g.remainingpoints()>-1) {
    ostr<<"points to play:" <<g.remainingpoints()<<"\n";
  }

  DEBUG_RETURNING(ostr,INFO_GAMEPOINTSTABLE && INFO_OTHER_FUNCTION,"operator<<(ostream& ostr, GamePointsTable const& g)");
}
