/* This file is part of cardwords
   (c) 1999 Tobias Peters
   see file COPYING for the copyright terms.
   
   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 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
*/

// cardwords_game.hh

// This file defines the main game engin.
// It keeps track of the participants and handles moves, trades and passes.

#ifndef CARDWORDS_GAME_HH
#define CARDWORDS_GAME_HH

#include "cardwords_participant.hh"
#include <vector>
#include "config.hh"
#include "cardwords_move.hh"

class CardWords_CardTable;
class CardWords_Pile;
class CardWords_BonusTable;

class CardWords_Game :
  public CardWords_SelectibleChildLocker
{
public:
  // Every word a player lays in the game is forwarded to DicBot.
  // Here we receive DicBot's answer:
  virtual void
  child_answers(const string & answer);
  
  // Get told about a new Connection. Will send info about registering
  // possibilities and if there are none, will send "BYE".
  // the latter case is indicated by return value -1
  int
  new_connection(CardWords_Participant *);

  // called by the destructor of CardWords_Participant:
  void
  deregister(CardWords_Participant *);

  // called when a request was received completely:
  // returns 0 on normal operation. returns -1 if the request was invalid
  // or illegal for that participant. The participant has then already
  // been deleted or robotized. This means for the calling function:
  // if request_from returns -1, do not touch any data members, because
  // they may have been deleted, and return immediately.
  int
  request_from(const string & request, CardWords_Participant *);

  CardWords_Game(size_t set_max_remote_players,
                 size_t set_initial_no_of_robots,
                 size_t set_max_watchers,
                 CardWords_CardTable * set_table,
                 CardWords_Pile * set_pile,
                 const CardWords_BonusTable * set_bonus,
                 bool set_reserve_player_place_for_owner = true);

  // Who's the lazy one:
  CardWords_Participant *
  whose_turn(void);

  // the requests from the players:
  int
  pass(CardWords_Participant *); // will also be called from
  //                     CardWords_Participant::robotize()

  // After he logged successfully on, send the remaining info to
  // this CardWords_Participant:
  void
  send_after_log_info(CardWords_Participant *);

private:
  // the istream in these functions will be constructed by request_from()
  int
  registering(CardWords_Participant *, istream &);

  int
  trade(CardWords_Participant *, istream &);

public: // will be called dircectly by the robots:
  int
  move(CardWords_Participant *, istream &);

private:
  int
  quit(CardWords_Participant *);

  int
  kick(CardWords_Participant *, istream &);

  int
  add_word(CardWords_Participant *, istream &);

  int
  remove_word(CardWords_Participant *, istream &);

  int
  start(CardWords_Participant *);
  
  void
  next_players_go(void);

  void
  broadcast_message(const string & message);
  
  void
  broadcast_logged_players(void);

  void
  broadcast_cards_left(void);
  
  void
  start_game(void);

  void
  end_game(void);
  
public:
  // This player mutated into a robot:
  int
  robotized(CardWords_Participant *); // Result is an info to all
  //                                     remaining remote_patricipant-s.


  // info about the game:
  size_t
  get_hand_capacity(void) const;

  bool
  is_game_running(void) const;

  bool
  is_game_over(void) const;

  CardWords_Pile *
  get_pile(void);

  const CardWords_BonusTable *
  get_bonus(void) const;

  size_t
  get_no_of_robots(void) const;

  size_t
  get_no_of_remote_players(void) const;

  size_t
  get_no_of_players(void) const;
  
private:
  // every participant is in exactly one set:
  set<CardWords_Participant *> new_participants;
  set<CardWords_Participant *> players;
  set<CardWords_Participant *> watchers;

  // an enum to describe which set a participant is in:
  enum E_In_Set {new_set, play_set, watch_set};
  
  CardWords_Participant * owner;

  size_t max_players, max_watchers;

  bool owner_is_present;
  bool owner_is_player;
  bool reserve_player_place_for_owner;

  bool game_running;
  bool game_over;

  // The order of the participants in the game:
  vector<CardWords_Participant *> ordered_players;

  // The player whose turn it is:
  vector<CardWords_Participant *>::iterator active_player;

  size_t number_of_consecuting_passes;

  CardWords_CardTable *        table;
  CardWords_Pile *             pile;
  const CardWords_BonusTable * bonus;

  // Wether we expect an answer from DicBot regarding a move:
  bool asked_dicbot;
  size_t expect_ok_from_dicbot; // number of confirmation expected
  // This player's move has been asked:
  CardWords_Participant * asked_for_player;
  // This is the move that we ask:
  CardWords_Move current_move;
public:
  virtual ~CardWords_Game(){}
};


#endif
