////////////////////////////////////////////////////////////////////////////////
// MechShell.h
// Mech shell window for MechVM
// Copyright by Bjoern Ganster
// Developed since 2008
////////////////////////////////////////////////////////////////////////////////

#ifndef MechShell__h
#define MechShell__h

#include "Font.h"
#include "GLTableView.h"
#include "GLWindowContainer.h"
#include "MWDate.h"
#include "Vehicles.h"
#include "XMLTree.h"

class MWArchive;

#ifdef MECHVM
#include "MechWarriorIIPRJ.h"
#include "SmackerView.h"
#endif

#include <vector>

struct MechShellRegion {
	Texture* img;
	int x1, y1, x2, y2;
	Font* font;
	BGCPString hint, command, go_to, condition, setvar, setstr, range, exec, text;

	MechShellRegion()
	: img(nullptr)
	{
	}
};

struct MechShellTextEdit {
	int x1, y1, x2, y2;

	// Any changes are immediately written to this variable
	BGCPString var;

	MechShellTextEdit()
	{
	}
};

struct MW2MercsContract {
	MWDate showDate;
	MWDate startDate;
	MWDate endDate;
	BGCPString contractName;
	BGCPString firstMission;
	BGCPString setVars;
};

class MechShell: public GLWindowContainer, public GLTableViewDataSource
{
public:
	// Constructor
	MechShell(int _left = 0, int _top = 0, int _width = 0, int _height = 0);

	// Destructor
	~MechShell() OVERRIDE;

	// Close archives
	void closeArchives();

	// Receive messages
	void receiveMessage (VirtualClass* sender, int MessageType, VirtualClass* data = nullptr) OVERRIDE;

	// Render
	void render(int x, int y, int w, int h) OVERRIDE;

	// Keyboard event handler
	void keypressed (BGKey /*key*/, bool /*shiftHeld*/, bool /*ctrlHeld*/, bool /*down*/, bool repeat) OVERRIDE;

	// Button state changed over a window: returns child that was clicked
	GLWindow* buttonStateChanged (int /*button*/, bool down, int /*x*/, int /*y*/) OVERRIDE;

	void mouseMoved (int /*x*/, int /*y*/) OVERRIDE;

	// Init
	bool startCampaign(const BGCPString& gameName);

	// Enter next room
	bool enterRoom(const BGCPString& newRoom);

	// Execute a command
	void execute(const BGCPString& cmd);

	// Set variables
	bool processAssignment (const BGCPString& assignment, bool doMath);
	bool setVar (const BGCPString& varName, const BGCPString& value);

	// Set variable, but only if it does not exist yet
	// (should be used with persistent variables, these have been loaded from MechVM.cfg)
	void initVar (BGCPString& assignment, bool doEvaluate);

	// Get variable value
	bool getVar(const BGCPString& varName, BGCPString& result) const;

	bool evaluate(BGCPString& str, bool opsAllowed = false) const;

	// Store variable in config
	#ifdef MECHVM
	void writeBackVar (const BGCPString& varName);
	#endif

	bool loadCampaign(const PathChar* path);

	// Load archive to access for pics and other things
	bool loadArchive (const PathChar* path);

	// Called by Mech Lab to indicate that user saved a new MEK file and intends to use it
	void useConfig(const PathChar* MEKFN);

	// GLTable implementation: get table dimensions
	void getDimensions (size_t /*senderID*/, size_t& rowCount, size_t& colCount) OVERRIDE;

	// GLTable implementation: Get string for a cell
	bool getString (size_t /*senderID*/, int row, int /*col*/, BGCPString& str) OVERRIDE;

	// Request context menu
	void showContextMenu(VirtualClass* /*sender*/, int /*x*/, int /*y*/) OVERRIDE;

	Vehicle* loadPlayerVehicle(const BGCPString& MEKname, const BGCPString& chassisName, 
		const BGCPString& textureFN = "");

	// Select a string from a comma-separated list where the first entry gives the index
	bool selectStr (const BGCPString& select, BGCPString& result) const;

	// Check for a cnd tag in the XML file and return the result of the evaluation
	// If there is no tag, the return value defaults to true ...
	bool checkCondition(const BGCPString& iter) const;

	// Return name of current room
	BGCPString getRoom() const;

	void enterPostMissionRoom(bool missionSuccessful);

	// Get complete list of installed mechs (used for instant action)
	void getMechList();

	// Set screen to return to when the shell is done
	void setReturnScreen(GLWindowContainer* returnScreen);

	// Check if this shell is executed for Mercs ...
	#ifdef MECHVM
	bool isMercs() const;
	#endif

	// Get a summary on a vehicle to display, e.g. for the MechLab
	void getVehicleSummary(const BGCPString& cmd);

private:
	MWArchive* archive, * archive2;
	XMLTree tree;
	std::vector<MechShellRegion> mRegions;
	std::vector<MechShellTextEdit> mTextEdits;
	int mLastMouseX, mLastMouseY;
	GLWindowContainer* mReturnScreen;
	XMLTreeNode* mCurrentRoom;

	std::vector<BGCPString> vars;
	std::vector<MW2MercsContract> mContracts;
	std::vector<Font*> mFonts;
	
	#ifdef MECHVM
	Palette mRoomPal;
	SmackerView* mSmkViewer;
	#endif

	// If we're playing back a SMK video, we really should know what the next room will be
	BGCPString mNextRoom;

	// Virtual screen size stores the geometry of the emulated screen. Physical coordinates are stored in the base class
	int mVirtualScreenSizeX, mVirtualScreenSizeY;

	// Mech shell may use a different font
	Font* mFont;

	// When calling the MechLab in Mercs, remember where to put the new config ...
	BGCPString mMercsChassisNum;

	// Functions carried out on enterRoom()
	bool loadImageFromArchive(const TCHAR* filePath, Texture& texture);
	void clearImages();
	void loadTexts();
	#ifdef MECHVM
	GLStringTableView* buildScrollableTextFromBWD (MemoryBlock* mb, int x1, int y1, int x2, int y2, const BGCPString& tagName);
	#endif

	// Return index of variable, or -1
	#ifdef MECHVM
	int findVar (const BGCPString& name) const;
	#endif

	#ifdef MECHVM
	BGCPString retrieveStr (const BGCPString& varName) const;
	#endif

	void renderTextButton(XMLTreeNode* child);
	void renderBar(int x, int y, int w, int h);

	// Call DosBox to start the sim
	bool runSim(const BGCPString& cmd);
	bool runInternalSim(const BGCPString& missionName, bool& missionSuccessful);

	// Get path where a game edition is installed
	#ifdef MECHVM
	void getDosBoxGameDir (BGCPString& gameDir);
	#endif

	// Show Mech Lab
	void showMechLab(const BGCPString& cmd);

	// Update title with model graph name and framerate
	void updateTitle ();

	// Build string list of mech configs for a chassis
	void fetchMEKs(const BGCPString& args);

	// Extract Mech comment from MEK
	void fetchMEKComment(const BGCPString& cmd);

	bool setChassisAndConfig (MemoryBlock& userStarBWD, size_t& offset, 
		const char* selChassisStr, const char* selMEKStr);

	// End Smacker playback
	void endSmk();

	// Update list of available contracts
	#ifdef MECHVM
	void updateMercsContracts();
	#endif

	// Get list of missions associated with a contract
	#ifdef MECHVM
	void getMercsContractMissions();
	#endif

	// Return XML tree iterator for a room, given its name
	XMLTreeNode* findRoom(const BGCPString& roomName);

	// Help function: add mission results to scrollable text
	void addMissionResults(int& row, int& col);

	// Remove an element from a comma-separated list
	void removeFromList(const BGCPString& cmd);

	// Append element to list
	void appendToList(const BGCPString& cmd);

	// Mercs: get a list of Mech that are available for purchase in a given year ...
	void getMechsForSale();

	// Help function to construct a scrollable text from "ScrollableText" tag
	GLStringTableView* buildScrollableText(const BGCPString& text, int x1, int y1, int x2, int y2);
	GLStringTableView* buildScrollableTextFromCSL(const BGCPString& text, int x1, int y1, int x2, int y2);

	// Sell all Mechs, adding money as calculated by calcVehiclePrice
	void sellOut();

	// Load font from archive
	void loadFontFromArchive(const BGCPString& fn, int divider);
};

#endif
