/* 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_server.hh

#ifndef CARDWORDS_SERVER_HH
#define CARDWORDS_SERVER_HH

#include "cardwords_machinechar.hh"
#include "cardwords_selectiblechild.hh"
#include "cardwords_bonustable.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "charpointer.hh"

#ifndef SERVER_VERSION
#define SERVER_VERSION "cardwords_server version 0.0a"
#endif

#ifndef DICBOT_EXECUTABLE_FILE
#define DICBOT_EXECUTABLE_FILE ((constCharPointer)"cardwords_dicbot")
#endif
#ifndef DICBOT_TIMEOUT
#define DICBOT_TIMEOUT 60 /* seconds */
#endif

#ifndef OWNER_PASSWORD_LENGTH
#define OWNER_PASSWORD_LENGTH 10
#endif
#ifndef PORT_NUMBER
#define PORT_NUMBER DEFAULT_PORT
#endif
#ifndef NETWORK_TIMEOUT
#define NETWORK_TIMEOUT 30
#endif

#ifndef MESSAGE_NUMBER_DIGITS
#define MESSAGE_NUMBER_DIGITS 8
#endif
#ifndef MESSAGE_LENGTH_DIGITS
#define MESSAGE_LENGTH_DIGITS (MESSAGE_NUMBER_DIGITS)
#endif
#ifndef MESSAGE_HEADER_LENGTH
#define MESSAGE_HEADER_LENGTH (MESSAGE_NUMBER_DIGITS+MESSAGE_LENGTH_DIGITS+1)
#endif
#ifndef MESSAGE_ANSWER_INDICATOR
#define MESSAGE_ANSWER_INDICATOR ((Machine_Char)'A')
#endif
#ifndef MESSAGE_INFO_INDICATOR
#define MESSAGE_INFO_INDICATOR ((Machine_Char)'I')
#endif
#ifndef MESSAGE_PERSONAL_INFO_INDICATOR
#define MESSAGE_PERSONAL_INFO_INDICATOR ((Machine_Char)'P')
#endif
#ifndef MESSAGE_BYE
#define MESSAGE_BYE ((constCharPointer)"BYE")
#endif
#ifndef MESSAGE_2ND_OWNER_TRIED
// This message will be sent to the owner when a second attempt to log in as
// owner is made:
#define MESSAGE_2ND_OWNER_TRIED ((constCharPointer)"2ND_OWNER_TRIED")
#endif
#ifndef MESSAGE_LOG_AS
// This message is the permission to log on. It will be followed by at least
// one of STRING_PLAYER, STRING_WATCHER, STRING_OWNER_PLAYER,
// STRING_OWNER_WATCHER, separated by white space.
#define MESSAGE_LOG_AS ((constCharPointer)"LOG_AS")
#endif
#ifndef MESSAGE_LOG_AS_END
// And after this char the server will send:
// The Charset description, the card descriptions, the bonus descriptions,
// the table description.
#define MESSAGE_LOG_AS_END ((Machine_Char)';')
#endif
#ifndef MESSAGE_NON_UNIQUE_NAME
#define MESSAGE_NON_UNIQUE_NAME ((constCharPointer)"NON_UNIQUE_NAME")
#endif
#ifndef MESSAGE_FULL
#define MESSAGE_FULL ((constCharPointer)"FULL")
#endif
#ifndef MESSAGE_WELCOME
#define MESSAGE_WELCOME ((constCharPointer)"WELCOME")
#endif
#ifndef MESSAGE_GAME_ALREADY_RUNNING
#define MESSAGE_GAME_ALREADY_RUNNING \
                        ((constCharPointer)"GAME_ALREADY_RUNNING")
#endif
#ifndef MESSAGE_NEW_CARD
#define MESSAGE_NEW_CARD ((constCharPointer)"NEW_CARD")
#endif
#ifndef MESSAGE_NOT_OWNER
#define MESSAGE_NOT_OWNER ((constCharPointer)"NOT_OWNER")
#endif
#ifndef MESSAGE_GAME_STARTS
#define MESSAGE_GAME_STARTS ((constCharPointer)"GAME_STARTS")
#endif
#ifndef MESSAGE_GO_OF // It's xxx's go ...
#define MESSAGE_GO_OF ((constCharPointer)"GO_OF")
#endif
#ifndef MESSAGE_YOUR_GO
#define MESSAGE_YOUR_GO ((constCharPointer)"YOUR_GO")
#endif
#ifndef MESSAGE_GO_FINISHED
#define MESSAGE_GO_FINISHED ((constCharPointer)"GO_FINISHED")
#endif

#ifndef MESSAGE_LOGGED_PLAYERS // This message is followed by:
//                               - the number of robot players
//                                 and STRING_ROBOTS
//                               - the names and numbers of cards and the
//                                 points of each robot
//                               - the number of remote players
//                                 and STRING_REMOTE_PLAYERS
//                               - the names and numbers of cards and the
//                                 points of each remote player
#define MESSAGE_LOGGED_PLAYERS ((constCharPointer)"LOGGED_PLAYERS")
#endif

#ifndef MESSAGE_REMAINING_CARDS // The number of cards in the pile
#define MESSAGE_REMAINING_CARDS ((constCharPointer)"REMAINING_CARDS")
#endif

#ifndef MESSAGE_PLAYER_TRIES_MOVE // This message is folowed by:
//                                  - the name of the player who tries the
//                                    move
//                                  - the move that he tries.
#define MESSAGE_PLAYER_TRIES_MOVE ((constCharPointer)"PLAYER_TRIES_MOVE")
#endif

#ifndef MESSAGE_PLAYER_GETS_POINTS
#define MESSAGE_PLAYER_GETS_POINTS \
                          ((constCharPointer)"MESSAGE_PLAYER_GETS_POINTS")
#endif

#ifndef MESSAGE_MOVE_DONE
#define MESSAGE_MOVE_DONE ((constCharPointer)"MESSAGE_MOVE_DONE")
#endif

#ifndef MESSAGE_PLAYER_PASSES // This message is folowed by the name of the
#define MESSAGE_PLAYER_PASSES ((constCharPointer)"MESSAGE_PLAYER_PASSES")
#endif                        // passing player.

#ifndef MESSAGE_MOVE_NOT_ALLOWED
#define MESSAGE_MOVE_NOT_ALLOWED ((constCharPointer)"MOVE_NOT_ALLOWED")
#endif

#ifndef MESSAGE_MOVE_WOULD_CREATE_UNKNOWN_WORD
#define MESSAGE_MOVE_WOULD_CREATE_UNKNOWN_WORD \
((constCharPointer)"MOVE__WOULD_CREATE_UNKNOWN_WORD")
#endif // Two underscores^ to distinguish it from the next one easily.

#ifndef MESSAGE_MOVE_WOULD_CREATE_UNKNOWN_WORD_AT
#define MESSAGE_MOVE_WOULD_CREATE_UNKNOWN_WORD_AT \
((constCharPointer)"MOVE_WOULD_CREATE_UNKNOWN_WORD_AT")
#endif

#ifndef MESSAGE_PLAYER_MUST_PASS // As a reaction to an invalid move or
//                                  unknown word
#define MESSAGE_PLAYER_MUST_PASS ((constCharPointer)"PLAYER_MUST_PASS")
#endif


#ifndef MESSAGE_ACCEPTING_YOUR_TRADE
#define MESSAGE_ACCEPTING_YOUR_TRADE \
                             ((constCharPointer)"ACCEPTING_YOUR_TRADE")
#endif

#ifndef MESSAGE_NO_SUCH_CARD // Personal message in response to a move or
//       trade request that had a card that is not on the player's hand.
#define MESSAGE_NO_SUCH_CARD ((constCharPointer)"NO_SUCH_CARD")
#endif

#ifndef MESSAGE_PLAYER_TRADES_CARDS
#define MESSAGE_PLAYER_TRADES_CARDS ((constCharPointer)"PLAYER_TRADES_CARDS")
#endif

#ifndef STRING_OWNER_PLAYER
#define STRING_OWNER_PLAYER ((constCharPointer)"OWNER_PLAYER")
#endif
#ifndef STRING_PLAYER
#define STRING_PLAYER ((constCharPointer)"PLAYER")
#endif
#ifndef STRING_WATCHER
#define STRING_WATCHER ((constCharPointer)"WATCHER")
#endif
#ifndef STRING_OWNER_WATCHER
#define STRING_OWNER_WATCHER ((constCharPointer)"OWNER_WATCHER")
#endif
#ifndef STRING_ROBOTS
#define STRING_ROBOTS ((constCharPointer)"ROBOTS:")
#endif
#ifndef STRING_REMOTE_PLAYERS
#define STRING_REMOTE_PLAYERS ((constCharPointer)"REMOTE_PLAYERS:")
#endif
#ifndef STRING_CARDS
#define STRING_CARDS ((constCharPointer)"CARDS")
#endif
#ifndef STRING_POINTS
#define STRING_POINTS ((constCharPointer)"POINTS")
#endif

#ifndef REQUEST_REGISTER
#define REQUEST_REGISTER ((constCharPointer)"REGISTER")
#endif
#ifndef REQUEST_START
#define REQUEST_START ((constCharPointer)"START")
#endif
#ifndef REQUEST_MOVE
#define REQUEST_MOVE ((constCharPointer)"MOVE")
#endif
#ifndef REQUEST_TRADE
#define REQUEST_TRADE ((constCharPointer)"TRADE")
#endif
#ifndef REQUEST_PASS
#define REQUEST_PASS ((constCharPointer)"PASS")
#endif
#ifndef REQUEST_ADD_WORD
#define REQUEST_ADD_WORD ((constCharPointer)"ADD_WORD")
#endif


#ifndef REQUEST_HEADER_DIGITS
#define REQUEST_HEADER_DIGITS (MESSAGE_NUMBER_DIGITS)
#endif
#ifndef REQUEST_MAX_LEN
#define REQUEST_MAX_LEN 10000
#endif
#ifndef REQUEST_MAX_NAME_LEN
#define REQUEST_MAX_NAME_LEN 30
#endif

class CardWords_Game;
class CardWords_CardTable;
class CardWords_Pile;

struct CardWords_Server_Global {
  const Machine_Char * charset_file;
  const Machine_Char * table_file;
  const Machine_Char * card_file;
  const Machine_Char * load_file;
  const Machine_Char * home_directory;

  const Machine_Char * version;
  
  const CardWords_BonusTable * bonus_table;
  
  CardWords_Selector        selector;
  CardWords_SelectibleChild dicbot;

  // these will be specified via command line options:
  size_t no_of_players_planned;
  size_t no_of_robots_planned;
  size_t no_of_watchers_planned;
  int port_number;
  bool reserve_player_place_for_owner;
  Machine_Char owner_password[OWNER_PASSWORD_LENGTH + 1];


  CardWords_Game * engin;
  CardWords_CardTable * table;
  CardWords_Pile * pile;
  
  CardWords_Server_Global() :
    charset_file(0), table_file(0),card_file(0), load_file(0),
    version((constCharPointer)SERVER_VERSION),
    bonus_table(0),
    dicbot(&selector, DICBOT_EXECUTABLE_FILE),
    no_of_players_planned(1),
    no_of_robots_planned(1),
    no_of_watchers_planned(0),
    
    port_number(PORT_NUMBER),
    reserve_player_place_for_owner(true),
    engin(0), table(0), pile(0)
    {
      // Produce the owner_password from /dev/urandom.
      // Yes, this is overkill.
      Machine_Char random_bytes[(OWNER_PASSWORD_LENGTH + 1)/2];
      int fd = open("/dev/urandom",O_RDONLY);
      if (fd != -1) {
        read(fd, random_bytes, (OWNER_PASSWORD_LENGTH + 1)/2);
        close (fd);
      }
      for (size_t index = 0; index < (OWNER_PASSWORD_LENGTH + 1)/2; ++index) {
        owner_password[2*index] = 'A' + random_bytes[index] % 26;
        owner_password[2*index+1]= 'A' + random_bytes[index] / 26;
      }
      owner_password[OWNER_PASSWORD_LENGTH] = '\0';
    }
};

extern struct CardWords_Server_Global server_global;

#endif

