#ifndef NET_MINECRAFT_CLIENT__Minecraft_H__
#define NET_MINECRAFT_CLIENT__Minecraft_H__

#include "Options.h"
#ifndef STANDALONE_SERVER
#include "MouseHandler.h"
#endif
#include "Timer.h"
#include "player/input/ITurnInput.h"
#ifndef STANDALONE_SERVER
#include "gui/Gui.h"
#include "gui/screens/ScreenChooser.h"
#endif
//#include "../network/RakNetInstance.h"
#include "../world/phys/HitResult.h"

class User;
class Level;
class LocalPlayer;
class IInputHolder;
class Mob;
class Player;
class LevelRenderer;
class GameRenderer;
class ParticleEngine;
class Entity;
class ICreator;
class GameMode;
class Textures;
class CThread;
class SoundEngine;
class Screen;
class Font;
class LevelStorageSource;
class BuildActionIntention;
class PerfRenderer;
class LevelSettings;
class IRakNetInstance;
class NetEventCallback;
class CommandServer;
struct PingedCompatibleServer;
//class ExternalFileLevelStorageSource;


#include "../App.h"
#include "PixelCalc.h"
class AppPlatform;
class AppPlatform_android;

class Minecraft: public App
{
protected:
	Minecraft();
public:
	virtual ~Minecraft();

	void init();
	void setSize(int width, int height);
	void reloadOptions();

	bool supportNonTouchScreen();
	bool useTouchscreen();
	void grabMouse();
	void releaseMouse();

	void handleBuildAction(BuildActionIntention*);

	void toggleDimension(){}
	bool isCreativeMode();
	void setIsCreativeMode(bool isCreative);
	void setScreen(Screen*);

	virtual void selectLevel(const std::string& levelId, const std::string& levelName, const LevelSettings& settings);
	virtual void setLevel(Level* level, const std::string& message = "", LocalPlayer* forceInsertPlayer = NULL);

	void generateLevel( const std::string& message, Level* level );
	LevelStorageSource* getLevelSource();

	bool isLookingForMultiplayer;
	void locateMultiplayer();
	void cancelLocateMultiplayer();
	bool joinMultiplayer(const PingedCompatibleServer& server);
	bool joinMultiplayerFromString(const std::string& server);
	void hostMultiplayer(int port=19132);
	Player* respawnPlayer(int playerId);
	void respawnPlayer();
	void resetPlayer(Player* player);
	void doActuallyRespawnPlayer();

	void update();

	void tick(int nTick, int maxTick);
	void tickInput();

	bool isOnlineClient();
	bool isOnline();
	void pauseGame(bool isBackPaused);
	void gameLostFocus();

	void prepareLevel(const std::string& message);

	void leaveGame(bool renameLevel = false);

	int getProgressStatusId();
	const char* getProgressMessage();

	ICreator* getCreator();

	// void onGraphicsLost() {}
	void onGraphicsReset();

	bool isLevelGenerated();

    void audioEngineOn();
    void audioEngineOff();
    
	bool isPowerVR() { return _powerVr; }
	bool isKindleFire(int kindleVersion);
	bool transformResolution(int* w, int* h);
	void optionUpdated(const Options::Option* option, bool value);
	void optionUpdated(const Options::Option* option, float value);
	void optionUpdated(const Options::Option* option, int value);
#ifdef __APPLE__
    bool _isSuperFast;
    bool isSuperFast() { return _isSuperFast; }
#endif

protected:
	void _levelGenerated();

private:
	static void* prepareLevel_tspawn(void *p_param);

	void _reloadInput();
public:
	int width;
	int height;

	// Vars that the platform is allowed to use in the future
	int commandPort;
	int reserved_d1, reserved_d2;
	float reserved_f1, reserved_f2;

	Options options;

	static bool useAmbientOcclusion;
	//static bool threadInterrupt;

	volatile bool pause;

	LevelRenderer*  levelRenderer;
	GameRenderer*   gameRenderer;
	ParticleEngine* particleEngine;
	SoundEngine*    soundEngine;

	GameMode* gameMode;
#ifndef STANDALONE_SERVER
	Textures* textures;
	ScreenChooser screenChooser;
	Font* font;
#endif
	IRakNetInstance*  raknetInstance;
	NetEventCallback* netCallback;

	int lastTime;
	int lastTickTime;
	float ticksSinceLastUpdate;

	User*  user;
	Level* level;

	LocalPlayer*	player;
	IInputHolder*	inputHolder;
	Mob*			cameraTargetPlayer;
#ifndef STANDALONE_SERVER
	Gui gui;
#endif
	CThread* generateLevelThread;
	Screen* screen;
	static int customDebugId;

	static const int CDI_NONE = 0;
	static const int CDI_GRAPHICS = 1;
#ifndef STANDALONE_SERVER
	MouseHandler mouseHandler;
#endif
	bool mouseGrabbed;

    PixelCalc pixelCalc;
    PixelCalc pixelCalcUi;

	HitResult hitResult;
	volatile int progressStagePercentage;

	// This field is initialized in main()
	// It sets the base path to where worlds can be written (sdcard on android)
	std::string externalStoragePath;
	std::string externalCacheStoragePath;
protected:
	Timer timer;
    // @note @attn @warn: this is dangerous as fuck!
	volatile bool isGeneratingLevel;
	bool _hasSignaledGeneratingLevelFinished;

	LevelStorageSource* storageSource;
	bool _running;
	bool _powerVr;

private:
	volatile int progressStageStatusId;
	static const char* progressMessages[];

	int missTime;
	int ticks;
	bool screenMutex;
	bool hasScheduledScreen;
	Screen* scheduledScreen;

	int _licenseId;
	bool _supportsNonTouchscreen;

	bool _isCreativeMode;
	//int _respawnPlayerTicks;
	Player* _pendingRemovePlayer; // @attn @todo @fix: remove this shait and fix the respawn behaviour

	PerfRenderer* _perfRenderer;
	CommandServer* _commandServer;
};

#endif /*NET_MINECRAFT_CLIENT__Minecraft_H__*/
