////////////////////////////////////////////////////////////////////////////////
// MechLab.h
// Mech Configuration window for MechVM
// Copyright Bjoern Ganster 
// Developed since 2007
////////////////////////////////////////////////////////////////////////////////

#ifndef MechLab__h
#define MechLab__h

#include "GLButton.h"
#include "GLLabel.h"
#include "GLWindowContainer.h"
#include "GLSlider.h"
#include "RenderableObject.h"
#include "Vehicles.h"
#include "Mesh.h"
#include "intersections.h"
#include "GLTableView.h"
#include "GLComboBox.h"

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

const int MechLab_selectChassisButtonID = 1;
//const int MechLab_createTextureButtonID = 2;
const int MechLab_animateMechButtonID = 4;
const int MechLab_outfitMechButtonID = 8;
const int MechLab_equipmentButtonID = 16;
const int MechLab_weaponGroupsID = 32;
const int MechLab_exitButtonID = 64;
const int MechLab_AllButtonsID = 
   MechLab_selectChassisButtonID | 
#ifdef _DEBUG
   MechLab_animateMechButtonID |
#endif
   MechLab_outfitMechButtonID |
   MechLab_equipmentButtonID | MechLab_weaponGroupsID | MechLab_exitButtonID;

////////////////////////////////////////////////////////////////////////////////
// Weapons that can be mounted on mechs

struct WeaponInStock {
    WeaponType type;
    int count;
};

class WeaponsLocker: public VirtualClass {
public:
   // Constructor, destructor
   WeaponsLocker()
   : VirtualClass("WeaponsLocker", WeaponsLockerID)
   {}
   ~WeaponsLocker() OVERRIDE
   {}

   // Get total number of different weapons in the locker
   size_t getWeaponCount()
   { return weaponsInStock.size() + 1; }

   // Get weapons count by index
   WeaponType getWeaponType(int index)
   {
       if (index >= 0 && index < (int) weaponsInStock.size()) {
          return weaponsInStock[index].type; 
       } else {
           return WeaponType::Unused_Critical_Slot;
       }
   }

   // Get number of a specific weapon by index
   int getWeaponCount (size_t index)
   {
       if (index < weaponsInStock.size()) {
           return weaponsInStock[index].count;
       } else {
           return 0;
       }
   }

   // Find weapon - returns index if found, or -1 otherwise
   int findWeapon (WeaponType weaponNo);

   // Add weapons to locker
   void addWeaponToStock (WeaponType weaponNo, int count);
   void addWeaponsToStock (WeaponType weaponStartNo, WeaponType weaponEndNo, int count);

   // Remove weapons from locker
   bool removeWeapon (WeaponType weaponNo, int count);

   // Fill locker with standard layouts
   void addISWeapons(size_t weaponCount, size_t ammoCount, int year);
   void addClanWeapons(size_t energyWeaponCount, 
      size_t ballisticWeaponCount, size_t ballisticAmmoCount,
      size_t GaussAndMachineGuns,
      size_t missileWeaponCount, size_t missileAmmoCount,
      size_t equipmentCount, bool GBL);
   void addGBLUnderwaterWeapons(size_t weaponCount, size_t ammoCount);
private:
   std::vector<WeaponInStock> weaponsInStock;
};

struct MechData {
    BGCPString mechName;
    BGCPString mechXML;
    BGCPString mechCFG;
    BGCPString mechTexture;
	BGCPString mechDir;
};

////////////////////////////////////////////////////////////////////////////////
// Class to list the mech library

class MechList: public VirtualClass {
public:
	// Constructor
	MechList(const char* className)
	: VirtualClass(className, MechListID)
	{
	}

	// Destructor
	~MechList() OVERRIDE
	{
	}

	void buildMechList(const PathChar * mechDir);

	void addMVMK(const PathChar * mechDir, const PathChar * MVMKfile);

	void addMech(const BGCPString & name, const BGCPString & xml,
		const BGCPString & mek, const BGCPString & textFN, const PathChar* mechDir);

	size_t getMechCount() const
	{
		return mechData.size();
	}

	bool getMechName(size_t index, BGCPString & result) const;
	BGCPString getMVMKFN(size_t index) const;
	BGCPString getTextureFN(size_t index) const;
	BGCPString getConfigFN(size_t index) const;

	Vehicle* loadMech(size_t index);

private:
	std::vector<MechData> mechData;
};

////////////////////////////////////////////////////////////////////////////////
// Mech lab class

class MechLab: public GLWindowContainer, GLTableViewDataSource
{
public:
	// Constructor
	MechLab(int buttons, GLWindow* mainWin);

	// Destructor
	~MechLab() OVERRIDE;

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

	// 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;

	// Set MechLab weapons type
	void addWeapons(const BGCPString& description, int year);

	// 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;

	// If the ray given by origin, dir intersects the Triangle, this function
	// returns the distance of the intersection, otherwise, it returns -1
	void testProximity (const Triangle& T, const Point3D& origin, 
		const Point3D& dir, MeshPolygon* poly, double& minDistSoFar,
		MeshPolygon*& nearestPolySoFar);

	// Implementation of GLTableViewDataSource
	virtual void getDimensions (size_t senderID, size_t& rowCount, size_t& colCount);
	virtual bool getString (size_t senderID, int row, int col, BGCPString& str);

	// Load and display mech given by number from list of mechs
	bool showMech(size_t num);
	void showMech(Vehicle* vehicle);

	void showChassisTable();
	GLWindow* createControls (int ID, const char* name, double value, double min, double max);
	void showAnimControls();
	void showOutfitMechControls();
	void showWeaponGroups();

	void initDialog();

   // Set the window that will be displayed if the user clicks exit
   void setReturnVis (GLWindow* returnWin);

   // Select file name to store MEK file from given directory
   BGCPString selectMEKFNInDirectory (const PathChar* dir);

   void setMechDir(const BGCPString& mechDir);

   void setBackground(const Texture& texture);

private:
   Vehicle* vehicle;
   double viewDist;
   int m_buttons;
   GLButton * importGeometryButton, * assignPoliesButton, *createTextureButton,
      * animateMechButton, * repairMechButton, *configureMechButton,
      * equipmentButton, * weaponGroupsButton, * exitButton;
   GLLabel * label;
   MechList mechList;
   GLWindow* mReturnWin;
   std::vector<GLLabel*> mArmorSumLabels;

   double torsoTilt;
   double torsoTwist;

   // Directory for the current vehicle/Mech
   BGCPString vehicleDir;

   bool leftButtonDown, rightButtonDown, renderMech, LimitedStock, changed;
   int lastMouseX, lastMouseY, currSection;
   Point3D eye, center, xDir, yDir, zDir;
   GLTableView * mechTable, * weaponsTable, * sectionTable, * sectionSelectionTable;
   WeaponsLocker* weaponsLocker;
   Texture mBackground;

   void addContextButton(const BGCPString& bname, int ID, int BaseID);
   GLButton* addToolbarButton(const BGCPString& buttonName, int ID);

   // Load mech from obj and bmp
   void assignPolies();

   void showEquipmentControls();
   void addCheckbox (const char* labelTitle, int& y, bool initialState, int ID);
   GLSlider* addSlider (const BGCPString& labelTitle, int min, int pos, int max, int& y, int ID);
   GLComboBox* addComboBox (const BGCPString& labelTitle, const BGCPString& cbTitle, int& y, int ID);
   GLSlider* addArmorSlider (int section, bool front, int& y);
   GLLabel* findLabel (int ID);

   // Update controls with the latest values
   void updateEquipmentLabels();

	// Get number of Mechs in the MechList
	size_t getMechCount() const;

	// Update label showing the mech tonnage - adds warnings if necessary
	void showMechTonnage();

   void setCurrMechName (const BGCPString& name);
};

#endif
