/*
   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_Group_Base
#define GUARD_Group_Base

#include "Globals.h"
#include "RTSUnit.h"
#include "AIInterpreter.h"

class Group_Base
{
public:
	Group_Base(const string& iDataFilename, const string& iAIFilename, int iMySide, int iMyGroup, const vector<int>& savedGroupsVec, CoordsInt iStartingCoords);
	virtual ~Group_Base() {}

	void ToggleDrawBound();
	void ToggleDrawNumber();
	void ResetForBattle();
	//blank for non small ships
	virtual void SetLaunchWait() {}
	bool SetPos(float ix, float iy);
	virtual bool GoToStartCoords();
	void InitAI(int iAIStagger);

	void GroupAddDelInform(int groupNumber, int addOrDelete);

	void MouseD(Uint8 button, Uint16 x, Uint16 y);
	void MouseU(Uint8 button, Uint16 x, Uint16 y);
	virtual void Drag(int state, int x, int y);
	void Select(WindowChoice infoType);
	
	virtual void RunGroupAI();
	void RunFireCommands();
	void Move();

	void FiredAt(TargetDesc& targetInfo);
	void Upkeep();
	void DeadUpkeep();

	void SetUSRect();

	//called by individual units for cap ship + frigate groups
	void FindInRange(vector<CoordsInt>& inRange, CoordsInt& myCoords, int range);

	virtual void DrawSelfBackBack() {};
	virtual void DrawSelfBack() {};
	virtual void DrawSelfMiddle() {};
	virtual void DrawSelfFront() {};
	virtual void DrawSelfPixels();

	//called from handle
	virtual void DrawBound();
	
	void PointsValueCheck();	
	void ReportOnScriptError(const char* error, int lineNumber = 0);

	int GetPointsValue() const;
	CoordsInt GetClosestPoint(const CoordsInt you) const;
	
	int GetHealth() const;
	int GetShield() const;
	int GetArmour() const;
	int GetMaxHealth() const;
	int GetMaxShield() const;
	int GetMaxArmour() const;
	virtual UnitType GetType() const = 0;
	
	int GetSmallPower() const;
	int GetBigPower() const;
	WeaponCat GetBigCat() const;
	int GetBigAmmo() const;
	int GetCmAmmo() const;
	int GetScriptVar(int which) const {return aiInterpreter.scriptVars[which];}
	CoordsInt GetSaveGroup(int which) const {return aiInterpreter.saveGroups[which];}
	unsigned int GetScriptTimer(int which) const {return frameCounter - aiInterpreter.scriptTimers[which];}
	int GetHowFull() const;
	CoordsInt GetCenter() const {CoordsInt tmp = {static_cast<int>(myx + width / 2), static_cast<int>(myy + height / 2)}; return tmp;}

	//Change
	void ChangeSize(int newSize);
	
	void ChangeStartCoords(int x, int y);
	void ChangeUnitPic(const string& newPic);
	void ChangeSmallType(WeaponType newType);
	void ChangeBigType(WeaponType newType);
	void ChangeEngine(const string& newStat);
	void ChangeArmour(const string& newStat);
	void ChangeShield(const string& newStat);
	void ChangeCSType(CapShipType newStat);
	
	void ChangeSaveGroup(int which, const CoordsInt& newSavedGroup) {aiInterpreter.saveGroups[which] = newSavedGroup;}
	
	void ChangeMySide(int newMySide);
	
	int FindDistanceTo(int nSide, int nGroup) const;
	bool CheckForCollision(int nSide, int nGroup) const;

	int width;
	int height;
	float myx, myy;
	float remSpeedx, remSpeedy;
	float speed;
	vector<RTSUnit> units;

	string dataFilename;
	string aiFilename;
	CoordsInt startingCoords;

	AICommands theCommands;

	int mySide;
	int myGroup;

	SDL_Rect USRect;
	bool onScreen;
	bool drawBound;
	bool drawNumber;
	bool selected;

	int alive;
	int unitsLeft;
	int unitsRemembered;

	//-1 means none
	int myParentCaSh;

	bool speedPlaneMatchesTarget;
	bool invertPatrol;
	
	int aiStagger;

protected:	
	void SetInitialVars();
	void SetBoundingRect();

	void RandomPlaceUnits();

	//if you don't care who hit
	bool CheckForCSFrCollision() const;
	bool CheckForCSFrCollision(CoordsInt& whoHit) const;

	virtual void ConvertFireTarget() {}
	virtual void ConvertCollisions();
	void ConvertPatrolTarget();
	//0 is normal, 1 means invert movement (i.e move away from)
	void ConvertMoveTarget(bool inverse = 0);
	
	void ConvertMaxChange(float& dx, float& dy);
	void PixelShuffle(float& dx, float& dy);
	void Relocate(float dx, float dy);

	//small ships work on per group, frigates work on per unit, capital ships work on per weapon
	virtual void SelectSmallTargets() = 0;
	
	CoordsInt GetDxDyClose(int side, int group) const;
	CoordsInt GetDxDyCenter(int side, int group) const;
	
	float maxSpeedChange;
	
	AIInterpreter aiInterpreter;
	
	CoordsInt whereClicked;
	bool alreadyDragging;
	bool alreadyAIError;
	//a hack so that if the whole group is dead when someone fires at us, they are given last
	//alive unit's last known position rather than the position of a unit which died ages ago
	int lastAlive;
};


///

class SmShGroup: public Group_Base
{
public:
	SmShGroup(int iMySide, int iMyGroup, const string& dataFilename, const string& iAIFilename,
	          int iParentCaSh, const vector<int>& savedGroupsVec, CoordsInt iStartingCoords);

	void SetLaunchWait();
	bool GoToStartCoords();

	void Drag(int state, int x, int y);

	void RunGroupAI();

	void ConvertFireTarget();
	void SelectSmallTargets();

	void DrawSelfBackBack();
	void DrawSelfFront();
	void DrawBound();

	UnitType GetType() const {return UT_SmShUnit;}

protected:
	void SetPosToParentCenter();
	void ConvertCollisions();

	int launchWait;
	float savedPropx;
    float savedPropy;
};

class AutoFireGroup: public Group_Base
{
public:
	AutoFireGroup(const string& iDataFilename, const string& iAIFilename, int iMySide, int iMyGroup, const vector<int>& savedGroupsVec, CoordsInt iStartingCoords);

	virtual UnitType GetType() const = 0;
protected:
	void SelectSmallTargets();
};

class FrGroup: public AutoFireGroup
{
public:
	FrGroup(int iMySide, int iMyGroup, const string& dataFilename, const string& iAIFilename, const vector<int>& savedGroupsVec, CoordsInt iStartingCoords);

	void DrawSelfMiddle();

	UnitType GetType() const {return UT_FrUnit;}
};

class CaShGroup: public AutoFireGroup
{
public:
	CaShGroup(int iMySide, int iMyGroup, const string& dataFilename, const string& iAIFilename, CapShipType iCaShType, const vector<int>& savedGroupsVec, CoordsInt iStartingCoords);

	void DrawSelfBack();

	UnitType GetType() const {return UT_CaShUnit;}
};


#endif
