/* 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 "charpointer.hh"
#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 Machine_Char * 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 Machine_Char * 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 CardWords_Game::next_players_go(void);

  //  void broadcast_message (const Machine_Char * message);
  void broadcast_message (constCharPointer message);
  
  void broadcast_logged_players(void);
  void broadcast_cards_left(void);
  
  void start_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;
  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;

  // 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;

  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
