#ifndef _MODEL_H
#define _MODEL_H

#include "ModelBase.h"
#include "AsteroidsEnums.h"

namespace asteroids {

class Model : public Engine::ModelBase {
	public:
		virtual ~Model() {};
		virtual void Process();
		virtual void SetGameState (const unsigned int &state);
		float GetWorldWidth ();
		float GetWorldHeight ();

		/* Event handler */
		bool OnGameOver();
		/** \brief Resets values from a previous game */
		void OnNewGame ();
		void OnShipExplode ();
		void OnLevelComplete ();

		/* Level loading etc. */
		int DoLoadLevel (const char* filename);
		int DoSaveLevel (const char* filename);
		void LoadLevelFromIndex (unsigned int level_index);
		void ResetLevel ();

		void ReloadLevel();
		void ProceedToNextLevel ();
		int GetPlayerLives () { return mPlayerLives; };
		void SetPlayerLives (int lives) { mPlayerLives = lives; };
		unsigned int GetPoints () { return mPoints; };
		unsigned int GetLevelPoints () { return mLevelPoints; };
		unsigned int GetLevelTimeBonusPoints () { return mLevelTimeBonusPoints; };
		std::string GetPlayerName() { return mPlayerName; };
		void SetPlayerName(const std::string &name) {
			Engine::LogDebug("new player name: %s", name.c_str());
			mPlayerName = name;
		};

		std::string GetLevelName() { return mLevelName; };
		void SetLevelName(const std::string &name) {
			Engine::LogDebug("new level name: %s", name.c_str());
			mLevelName = name;
		}

		std::string GetLevelAuthor() { return mLevelAuthor; };
		void SetLevelAuthor(const std::string &author) {
			Engine::LogDebug("new level author: %s", author.c_str());
			mLevelAuthor = author;
		}

		std::string GetLevelTitle() { return mLevelTitle; };
		void SetLevelTitle(const std::string &title) {
			Engine::LogDebug("new level title: %s", title.c_str());
			mLevelTitle = title;
		}

		float GetLevelTimeSeconds() { return mLevelTimeSeconds; };
		float GetLevelParTimeSeconds() { return mLevelParTimeSeconds; };

		/* Highscore */
		struct HighscoreEntry {
			HighscoreEntry(): name ("unknown"), points (0) {	};
			HighscoreEntry (const char *e_name, const unsigned int e_points):
				name (e_name), points (e_points) { };

			std::string name;
			unsigned int points;
		};

		void ParseHighscoreStream (std::istream &highscore_stream);
		void LoadHighscoreList ();
		bool PullGlobalHighscore (std::stringstream &highscore_stream);
		bool SubmitGlobalHigscoreEntry (std::string name, const unsigned int points);
		void SubmitHighscoreEntry (const std::string &name, const unsigned int points);
		unsigned int AddLocalHighscoreEntry(const std::string &name, const unsigned int points);
		void LoadLocalHighscoreList ();
		void SaveLocalHighscoreList ();
		bool GetHighscoreIsOnline() { return mHighscoreIsOnline; };
		
		std::list<HighscoreEntry> mHighscoreList;
		unsigned int mNewestHighscoreEntryIndex;

		unsigned int GetCurrentLevelIndex () {
			return mCurrentLevelIndex;
		}

		bool GetGameModified() { return mGameModified; }
	protected:
		/** \brief Initializes the system */
		virtual int OnInit (int argc, char* argv[]);
		virtual void OnDestroy();
		virtual void OnRegisterCommands ();

		virtual void OnCreateEntity (const int type, const unsigned int id);
		virtual void OnKillEntity (const Engine::EntityBase *entity); 

	private:
		unsigned int InitLevelList ();

		/** \brief Keeps a list of all asteroids */
		std::vector<unsigned int> mAsteroids;
		std::map<std::string, std::string> mLevelHashes;
		bool mGameModified;
		bool mCurrentLevelModified;

		int mPlayerLives;
		unsigned int mPoints;
		unsigned int mCurrentLevelIndex;

		std::string mPlayerName;
		std::vector<std::string> mLevelList;
		std::string mLevelName;
		std::string mLevelAuthor;
		std::string mLevelTitle;
		unsigned int mLevelPoints;
		float mLevelTimeSeconds;
		// par time (= my run through, rounded down + 30 seconds
		float mLevelParTimeSeconds;
		unsigned int mLevelTimeBonusPoints;

		static Engine::Variable HighscoreServerName;
		static Engine::Variable HighscoreServerPath;
		static Engine::Variable UseServerHighscore;
		static Engine::Variable UseServerHighscoreAsked;

		bool mHighscoreIsOnline;

		virtual bool OnReceiveEvent (const Engine::EventBasePtr &event);

	friend class View;
	friend class Controller;
};

}

#endif // _MODEL_H
