/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef __GAMEKEEPER_H__
#define __GAMEKEEPER_H__

// bzflag global header
#include "common.h"

// system headers
#include <vector>
#include <string>

// common interface headers
#include "PlayerInfo.h"
#include "PlayerState.h"
#include "TimeKeeper.h"

// implementation-specific bzfs-specific headers
#include "CmdLineOptions.h"
#include "FlagHistory.h"
#include "Permissions.h"
#include "LagInfo.h"
#include "Score.h"
#include "RecordReplay.h"
#include "NetHandler.h"
#include "Authentication.h"
#include "messages.h"

const int PlayerSlot = MaxPlayers + ReplayObservers;

typedef void (*tcpCallback)(NetHandler &netPlayer, int i, const RxStatus e);

/** This class is meant to be the container of all the global entity that lives
    into the game and methods to act globally on those.
    Up to now it contain players. Flag class is only there as a TODO
*/
class GameKeeper {
public:
  class Player {
  public:
    Player(int _playerIndex, const struct sockaddr_in &clientAddr, int fd,
	   tcpCallback _clientCallback);
    ~Player();

    int	    getIndex();
    static int     getFreeIndex(int min, int max);
    static Player *getPlayerByIndex(int _playerIndex);
    static int     count();
    static void    updateLatency(float &waitTime);
    static void    dumpScore();
    static int     anointRabbit(int oldRabbit);
    static std::vector<int> allowed(PlayerAccessInfo::AccessPerm right,
				    int targetPlayer = -1);
    static int     getPlayerIDByName(const std::string &name);
    static void    reloadAccessDatabase();

    bool	   loadEnterData(uint16_t &rejectCode,
				 char *rejectMsg);
    void	  *packAdminInfo(void *buf);
    void	  *packPlayerInfo(void *buf);
    void	  *packPlayerUpdate(void *buf);

		void		setPlayerAddMessage ( PlayerAddMessage &msg );

    void	   signingOn(bool ctf);
    void	   close();
    static bool    clean();
    void	   handleTcpPacket(fd_set *set);

    // For hostban checking, to avoid check and check again
    static void    setAllNeedHostbanChecked(bool set);
    void	   setNeedThisHostbanChecked(bool set);
    bool	   needsHostbanChecked();

    // To handle player State
    void	   setPlayerState(float pos[3], float azimuth);
    void	   getPlayerState(float pos[3], float &azimuth);
    void	   setPlayerState(PlayerState state, float timestamp);

    void	   setBzIdentifier(const std::string& id);
    const std::string& getBzIdentifier() const;

    // When is the player's next GameTime?
    const TimeKeeper&	getNextGameTime() const;
    void		updateNextGameTime();

    enum LSAState
      {
	start,
	notRequired,
	required,
	requesting,
	checking,
	timedOut,
	failed,
	verified,
	done
      } _LSAState;

    // players
    PlayerInfo	      player;
    // Net Handler
    NetHandler       *netHandler;
    // player lag info
    LagInfo	      lagInfo;
    // player access
    PlayerAccessInfo  accessInfo;
    // Last known position, vel, etc
    PlayerState       lastState;
    float	      stateTimeStamp;
	float		  serverTimeStamp;
    // GameTime update
    float	      gameTimeRate;
    TimeKeeper	      gameTimeNext;
    // FlagHistory
    FlagHistory       flagHistory;
    // Score
    Score	      score;
    // Authentication
    Authentication    authentication;

    // flag to let us know the player is on it's way out
    bool  isParting;

  private:
    static Player    *playerList[PlayerSlot];
    int		      playerIndex;
    bool	      closed;
    tcpCallback       clientCallback;
    std::string	      bzIdentifier;
    bool	      needThisHostbanChecked;
    // In case you want recheck all condition on all players
    static bool       allNeedHostbanChecked;

  };

  class Flag {
  };
};

inline int GameKeeper::Player::getIndex()
{
  return playerIndex;
}

inline GameKeeper::Player *GameKeeper::Player::getPlayerByIndex(int
								_playerIndex)
{
  if (_playerIndex < 0 || _playerIndex >= PlayerSlot)
    return NULL;
  if (!playerList[_playerIndex])
    return NULL;
  if (playerList[_playerIndex]->closed)
    return NULL;
  return playerList[_playerIndex];
}

void *PackPlayerInfo(void *buf, int playerIndex, uint8_t properties );

// For hostban checking, to avoid check and check again
inline void GameKeeper::Player::setAllNeedHostbanChecked(bool set)
{
  allNeedHostbanChecked = set;
}

inline void GameKeeper::Player::setNeedThisHostbanChecked(bool set)
{
  needThisHostbanChecked = set;
}

inline bool GameKeeper::Player::needsHostbanChecked()
{
  return (allNeedHostbanChecked || needThisHostbanChecked);
}


inline void GameKeeper::Player::setBzIdentifier(const std::string& id)
{
  bzIdentifier = id;
}

inline const std::string& GameKeeper::Player::getBzIdentifier() const
{
  return bzIdentifier;
}


inline const TimeKeeper& GameKeeper::Player::getNextGameTime() const
{
  return gameTimeNext;
}


#endif

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
