/*
   Copyright (C) 2004 by James Gregory
   Part of the GalaxyHack project
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.
 
   See the COPYING file for more details.
*/


#ifndef GUARD_RTSUnit_Base
#define GUARD_RTSUnit_Base

#include "Enums.h"
#include "Stuff.h"
#include "RTSStructs.h"

#include <vector>
#include <string>
#include <iterator>

using std::vector;
using std::string;
using std::istream_iterator;

//foward declaration
class Group;

class RTSUnit_Base {
public:
	RTSUnit_Base(const string& iName, int iMySide, int iMyGroup);
	virtual ~RTSUnit_Base();	

	void SetPos(float ix, float iy);

	//blank version for small ships
	virtual void SelectSmallTargets() {}
	//blank version for everyone else
	virtual void SelectSmallTargets(AICommands& theCommands) {}

	virtual void Move(float distx, float disty);
	void AddExtraMoveFrames();
	void Fire(AICommands& theCommands);

	void BeenHit(int power);

	virtual void Upkeep();
	void DeadUpkeep();

	void DrawSelf();
	virtual void DrawSelfPixels() {}

	void DrawUnitPic(int x, int y);

	int GetPointsValue() const;
	int GetMaxPoints() const;
	CoordsInt GetCenter() const {CoordsInt tmp = {static_cast<int>(myx + width / 2), static_cast<int>(myy + height / 2)}; return tmp;}

	//base version throws error
	virtual int GetCapacity() const;
	//base version just returns 0
	virtual int GetFrCapacity() const {return 0;}

	//standard is just width >> 1 height >> 1
	virtual CoordsInt GetWeakSpot() const;
	virtual void GetWeapCoords(vector<CoordsInt>& giveSmall, CoordsInt& giveBig) const = 0;

	//Change:
	void ChangeUnitPic(const string& newPic);
	void ChangeSmallType(WeaponType newType, bool ignorePoints = 0);
	void ChangeBigType(WeaponType newType, bool ignorePoints = 0);
	void ChangeEngine(const string& newType, bool ignorePoints = 0);
	void ChangeArmour(const string& newStat, bool ignorePoints = 0);
	void ChangeShield(const string& newStat, bool ignorePoints = 0);
	virtual void ChangeCSType(CapShipType newType);

	//Static
	static string UTypeToPicDir(UnitType uType);

	string name;
	UnitType myType;
	CapShipType myCSType;
	string picName;

	float speed;
	int armourCurrent;
	int armourMax;
	int shieldCurrent;
	int shieldMax;
	int shieldRecharge;
	unsigned int shieldTimer;

	int smallNumber;
	WeaponType smallType;
	WeaponType bigType;

	int bigAmmo;

	string engineName;
	string shieldName;
	string armourName;

	float myx;
    float myy;
	int width;
	int height;

	SDL_Rect USRect;

	int extraMoveFrames;
	float extraMovex;
	float extraMovey;
	int doExtraMove;

	int mySide;
	int myGroup;

	int alive;

protected:
	void LoadData();
	void LoadPicture();
	void FreePicture();
	virtual void DefaultTypeDepStats();
	void SetSpeed();

	virtual void FireSmall(AICommands& theCommands)= 0;
	void FireBig(AICommands& theCommands);
	void FireSpecial(AICommands& theCommands);

	virtual void InitSmall() = 0;

	virtual void Explode() = 0;

	virtual void SetSmallNumber() = 0;

	WeaponStage bigStage;
	unsigned int bigTimer;
	int bigAiming;
	CoordsInt bigTarget;
	int bigTargetUnit;
	CoordsInt targetWeakSpot;
	bool weHitWithBig;

	unsigned int explodeTimer;

	bool bFlip;
	SDL_Surface* pic;
	SDL_Surface* picFlip;
};

class AutoFireUnit: public RTSUnit_Base {
public:
	AutoFireUnit(const string& iName, int iMySide, int iMyGroup);

	void LoadWeapCoords(istream_iterator<char>& iter, istream_iterator<char>& fileEnd);
	void SelectSmallTargets();
	virtual void Upkeep();

	void GetWeapCoords(vector<CoordsInt>& giveSmall, CoordsInt& giveBig) const;

protected:
	void InitSmall();
	void FindInRange(vector<CoordsInt>& inRange, int range);
	void SetupSmallForFiring(int nSmall, vector<CoordsInt>& inRange);
	void FireSmall(AICommands& theCommands);

	CoordsInt GetWeakSpot() const;

	vector<WeaponStage> smallStage;
	vector<unsigned int> smallTimer;
	vector<int> smallAiming;
	vector<CoordsInt> smallTargets;

	vector<CoordsInt> smallPositions;
	CoordsInt bigPosition;
};

class CapitalShip: public AutoFireUnit {
public:
	CapitalShip(int iMySide, int iMyGroup, const string& iName, CapShipType iCSType);

	void DefaultTypeDepStats();

	void Upkeep();

	int GetCapacity() const {return capacity;}
	int GetFrCapacity() const;

	void ChangeCSType(CapShipType newType);

	int capacity;

protected:
	void Explode();
	void SetSmallNumber();
};

class Frigate: public AutoFireUnit {
public:
	Frigate(int iMySide, int iMyGroup, const string& iName);

	void DefaultTypeDepStats();

	void Upkeep();

	void DrawSelfPixels();

protected:
	void Explode();
	void SetSmallNumber();
};

class SmallShip: public RTSUnit_Base {
public:
	SmallShip(int iMySide, int iMyGroup, const string& iName);

	void DefaultTypeDepStats();

	void SelectSmallTargets(AICommands& theCommands);

	void Move(float distx, float disty);

	void Upkeep();

	void GetWeapCoords(vector<CoordsInt>& giveSmall, CoordsInt& giveBig) const;

protected:
	void InitSmall();
	void FireSmall(AICommands& theCommands);

	void Explode();
	void SetSmallNumber();

	WeaponStage smallStage;
	unsigned int smallTimer;
	int smallAiming;
	CoordsInt smallTarget;
};


#endif
