/* bzflag
 * Copyright (c) 1993-2017 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 COPYING 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"
#include "bzfsAPI.h"
#include "FlagInfo.h"
#include "ShotUpdate.h"

class ShotInfo {
public:
  ShotInfo() : salt(0), expireTime(0.0), present(false), running(false) {};

  FiringInfo firingInfo;
  int	salt;
  float      expireTime;
  bool       present;
  bool       running;
};



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 _playerIndex, NetHandler *handler, tcpCallback _clientCallback);
    Player(int _playerIndex, bz_ServerSidePlayerHandler *handler);
    ~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();

    // To handle Identify
    void	   setLastIdFlag(int _idFlag);
    int	    getLastIdFlag();

    // To handle shot
    static void    setMaxShots(int _maxShots);
    bool	   addShot(int id, int salt, FiringInfo &firingInfo);
    bool	   removeShot(int id, int salt);
    bool	   updateShot(int id, int salt);


    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;

    bool hasEntered;

    // logic class for server side players
    bz_ServerSidePlayerHandler*	playerHandler;

    bool addWasDelayed;
    bool hadEnter;
    double addDelayStartTime;

	int lastHeldFlagID;

  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;

    static int	     maxShots;
    std::vector<ShotInfo> shotsInfo;

    int	       idFlag;

  };

  class Flag {
  };
};

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

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