/*
Copyright (C) 2015  E.J.M. Martens

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

////////////////////////////////////////////////////////////////////////



#ifndef _Engine
#define _Engine

#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <exception>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <list>
#include <math.h>
#include "types.h"
#include "CoolMath.h"
#include "KeyMapper.h"



using namespace std;


typedef struct
{
  ID m_ID;
  MEMBER m_Member;

  char m_szName [10];
  int m_nPlanetType;
  int m_nHealth [20];
  int m_nTorpedoes;
  int m_nZ;
  int m_AI;
  int m_nRepairItem;
  int m_nCrew;
  int m_nEnergy;
  int m_nShieldEnergy;
  int m_nPhaserEnergy;
  int m_nPreferedTarget;
  int m_nPhaserPower;
  int m_nPopulation;
  int m_nTarget;
  int m_nLife;
  int m_nCount;
  int m_nShieldTimer;
  int m_nPhotonTimer;
  int m_nCloakCounter;
  int m_nCloakCharge;
  int m_nTranslucency;
  int m_nTask;
  int m_nCloakState;
  int m_nSectorPositionX;
  int m_nSectorPositionY;

  double m_dX;
  double m_dY;
  double m_dSpeed;
  double m_dWaypointX;
  double m_dWaypointY;
  double m_dAngle;

  bool m_blDocked;
  bool m_blDocking;
  bool m_blReleasing;
  bool m_blMustBeDestroyed;
  bool m_blMustSurvive;
  bool m_blMustReachPosition;
  bool m_blDock;
  bool m_blNoRelease;
  bool m_blCanFind;
  bool m_blPhaserOn;
  bool m_blCanCloak;

} sGameObject;


class TEngine;
class TShip;


// Basic sprite object
class TSprite
{
private:

protected:
   TEngine * m_pEngine;
   ALLEGRO_BITMAP * m_pImage;
	int m_nZ;
	double m_dAngle,
		   m_dX,
		   m_dY,
	       m_dSpeed;
	int m_nBitmapWidth;
	int m_nBitmapHeight;
	int m_nBitmapMidX;
	int m_nBitmapMidY;

public:
bool m_blDestroyed,
	 m_blCanCollide,
	 m_blCanFind;

MEMBER m_Member;
ID     m_ID;

virtual void Draw(double a_dCamX,double a_dCamY);
virtual void Move(double a_dLagCount);
virtual void Do_ai();
virtual void DoCollision(TSprite * const a_pSprite);

void SetPosition(double a_dX, double a_dY, double a_dAngle);
void SetPosition(double a_dX, double a_dY);
void SetHeight(int a_nHeight);
void SetSpeed(double a_dSpeed);
void SetImage(ALLEGRO_BITMAP * a_pImage);
double GetX();
double GetY();

TSprite();
virtual ~TSprite();

friend class TEngine;
friend bool Comp(const TSprite * a_pV1, const TSprite * a_p_V2);
};



// Game engine
class TEngine
{
friend class TShip;

private:

std::list <TSprite *> m_lstItems;

int m_nCount;
int m_nGameOver;
double m_dPosx,
	   m_dPosy,
       m_dX,
	   m_dY;


public:

bool m_blSensorStatic;
int m_nScreenWidth;
int m_nScreenHeight;
int m_nScreenMidX;
int m_nScreenMidY;

ALLEGRO_COLOR m_clBLACK;
ALLEGRO_COLOR m_clWHITE;
ALLEGRO_COLOR m_clGREEN;
ALLEGRO_COLOR m_clYELLOW;
ALLEGRO_COLOR m_clBROWN;
ALLEGRO_COLOR m_clBLUE;
ALLEGRO_COLOR m_clRED;
ALLEGRO_COLOR m_clMAGENTA;
ALLEGRO_COLOR m_clAQUA;
ALLEGRO_COLOR m_clATHM;

bool m_blKeys[KEY_MAX];


void Move(double a_dLagCount);
void Do_ai();
void Add(TSprite * const a_pSprite);
void Draw_sensor(int a_nX,int a_nY, TShip * const a_pPlayer);
void DrawHud(TShip * const a_pPlayer);

void SetOrigin(double a_dX, double a_dY);
void Folow(TSprite * const a_pSprite);
void Draw();
void Kill();
void Clear(bool a_blKeepPlayer);
double GetDx();
double GetDy();

TSprite * Seek(int a_nID, double a_dViewDistance, double a_dX, double a_dY);
TSprite * Seek(int a_nMember, bool a_blEnemy,double a_dViewDistance, double a_dX, double a_dY);
TSprite * Seekstarbase(int a_nMember, bool a_blEnemy,double a_dViewDistance, double a_dX, double a_dY);

virtual bool Detect_collision(TSprite * a_pSprite1, TSprite * a_pSprite2);

TEngine(int a_nWidth,int a_nHeight);
virtual ~TEngine();

bool Save(ofstream & a_SaveStream);
bool Load(ifstream & a_LoadStream);

friend class Sector;

};

class A5Exception: public exception
{
  private:
  string m_strError;

  public:

  A5Exception(string a_strError)
  {
     m_strError = a_strError;
  }

  virtual const char* what() const throw()
  {
    return m_strError.c_str();
  }

  virtual ~A5Exception() throw() { }
};

bool Comp(const TSprite * a_pV1, const TSprite * a_p_V2);


#endif
