#ifndef CGRID_H
#define CGRID_H
#include "hge.h"
#include "hgeresource.h"
#include "hgeanim.h"
#include "hgegui.h"
#include "hgeguictrls.h"
#include "hgedistort.h"
#include <vector>

const int GS_MMENU      = 0;
const int GS_OPTIONS    = 1;
const int GS_CHLVL      = 2;
const int GS_GAME       = 3;

typedef std::pair<int,int> tcellpos;

struct st_unitparam{
	int health;
	int dmg;
	int armor;
	float range;
};

struct st_global{
    st_unitparam aqua;
    st_unitparam torp;
    st_unitparam bati;
    st_unitparam medu;
    st_unitparam shark;
    st_unitparam paul;
};

class cGame;
class cInterface;
class cGrid;
class cCell;
class cUnit;
class cProjectile;
class guiButton;

extern hgeSprite *grid_sel1;
extern hgeSprite *grid_sel2;

class cGame {
    public:
        cGame();
        ~cGame();
        void render();
        bool update();
        static hgeResourceManager *resman;

        static cGame *Instance(){return instance;}
        tcellpos screenToCell(int x, int y);
        tcellpos cellToScreen(int x, int y); //return mid of hex
        cCell *GetCell(tcellpos pos);
        void NextTurn();
        void NextStep();

        static hgeFont *GetFont1(){return fnt1;}
        static void LockControl(){locklvl+=1;}
        static void UnlockControl(){locklvl > 0 ? locklvl-=1 : 0;}
        static bool IsControlLocked(){return locklvl <= 0? false:true;}
        static void SetProjectile(cProjectile *_proj) {proj = _proj;};

        static st_global global;
    protected:
    private:
        void render_mmenu();
        void render_game();
        void render_options();
        void render_chlvl();

        void update_mmenu(float dt);
        void update_game(float dt);
        void update_options(float dt);
        void update_chlvl(float dt);

        void Init();
        void LoadData();
        bool UnitToCell(cUnit *u, int x, int y);
        bool MoveToCell(int x1, int y1, int x2, int y2); //x1->x2...
        void ControlUpdate();
        void NotLockableControlUpdate();
        void AIMove();
        cUnit *AIFindPriorityTarget(cUnit *u);
        cCell *AIFindCellToMove(cUnit *u);
        float UnitDistance(cUnit *u1, cUnit *u2);
        float CellDistance(cCell *c1, cCell *c2);
        void SelectUnit(int num);
        void LoadLevel(int num);
        HTEXTURE drawgrid();

        std::vector<cUnit*> units;

        HGE *hge;
        hgeGUI *gui;
        hgeGUI *guioptions;
        hgeGUI *chlvlgui;

        hgeGUISlider *music_sld;
        hgeGUISlider *sound_sld;
        hgeGUISlider *speed_sld;
        hgeSprite *sliderbg1,*sliderbg2, *sliderbg3;

        static cGame *instance;
        static int locklvl;
        static int turn;
        UINT step;
        HSTREAM music;
        HCHANNEL muschan;
        int musicvolume;
        int maxlvl;

        static hgeFont *fnt1, *fnt2;
        tcellpos overcell;
        cInterface *iface;

        int gamestate, prevgamestate;

        std::vector<cCell> cells;
        cCell* selcell;
        cUnit* selunit;
        static cProjectile *proj;

        hgeSprite *spr;
        hgeSprite *cellglow_rose;
        hgeSprite *cellglow_rose_2x;
        hgeSprite *bgd;
        hgeSprite *grid;
        hgeSprite *cur;
        hgeSprite *aim;
        hgeSprite *mmenubg;
        hgeDistortionMesh *mmdistort;
        hgeSprite *chlvl;
        hgeSprite *glowspr;
        bool show_aim;

        int gridw, gridh, cellw, cellh;

        cUnit *unit;

        float mx, my;
        float dt;
        bool doQuit;
};

class cInterface{
    public:
        cInterface();
        ~cInterface();
        void render();
        void update(float dt);
    protected:
    private:
};

class cCell {
    public:
        cCell(int x, int y);
        virtual ~cCell();
        void render();
        void update(float dt);
        cUnit *GetUnit();
        bool NoUnit();
        bool AddUnit(cUnit *u);
        bool RemUnit();
        int GetX(){return x;};
        int GetY(){return y;};
        int GetScrX(){return scrx;};
        int GetScrY(){return scry;};
        void SetScr(tcellpos pos) {scrx = pos.first; scry = pos.second;};
    protected:
    private:
        int x; int y;
        int scrx; int scry;
        int terran;
        cUnit* unit;
};

const int state_idle = 0;
const int state_move = 1;
const int state_attack = 2;

const float move_time = 3.0;

class cUnit {
    public:
        cUnit();
        ~cUnit();
        virtual void render();
        virtual void update(float dt);
        virtual bool Move(cCell *dest);
        virtual void Shoot(cCell *dest);
        virtual void Stay();
        virtual void GetDamage(int dmg);
        virtual void NextTurn();
        virtual bool IsMedu(){return false;}

        void SetParent(cCell *p);
        cCell *GetParent() {return parent;};
        void Select();
        void Unselect(){selected = false;}
        bool IsSelect(){return selected;}
        int GetSize(){return cellsize;}
        bool IsPlayerControlled(){return plcontrolled;}
        bool IsDead(){return health <= 0 ? true : false;}
        int actionpoint;
        void SetPosition(int pos, int maxpos) {position = pos;maxposition = maxpos;}
        float GetRange(){return range;}
        int GetHealth(){return health;}
    protected:
        void SetParam(st_unitparam par);
        hgeAnimation *idle, *move, *attanim;
        hgeSprite *turn_on, *turn_off;
        HEFFECT snd_move, snd_attack;
        bool plcontrolled;
        bool selected;
        int cellsize;
        cCell *parent;
        bool melee;

        int state;
        float time;
        cCell *start_point;
        int ammotype;
        int position, maxposition;

        int health;
        int armor;
        int damage;
        float range;
    private:
};

class cAqua : public cUnit{
    public:
        cAqua();
        ~cAqua();
};

class cTorp : public cUnit{
    public:
        cTorp();
        ~cTorp();
};

class cBati : public cUnit{
    public:
        cBati();
        ~cBati();
};

class cPaul : public cUnit{
    public:
        cPaul();
        ~cPaul();
};

class cShark : public cUnit{
    public:
        cShark();
        ~cShark();
};

class cMedu : public cUnit{
    public:
        cMedu();
        ~cMedu();
        virtual bool IsMedu(){return true;}
};

class cProjectile {
    public:
        cProjectile(int type, tcellpos start, tcellpos dest, cUnit *target);
        ~cProjectile();
        void render();
        void update(float dt);
        bool IsDead();
    private:
        cUnit *target;
        int dmg;
        bool dead;
        float time, ftime;
        tcellpos start, dest;
        float angle;
        hgeSprite *spr;
};

class guiButton: public hgeGUIObject{
    public:
        guiButton(int id, float x, float y, float w, float h, hgeSprite *sprNormal, hgeSprite *sprOver);
        ~guiButton();
        virtual void MouseOver(bool bOver);
        virtual void Render();
        virtual bool MouseLButton(  bool bDown);
    private:
        hgeSprite *sprNorm, *sprOver;
        bool overed;
};
#endif // CGRID_H
