// player.h: Beispielspieler für Asteroids
// Harald Bögeholz / c't
#if defined(WINDOWS)
#define ADDRESS DWORD
#else
#define SOCKET int
#define ADDRESS in_addr_t
// 3 Includes für sockaddr_in
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

#include <vector>
//#define _USE_MATH_DEFINES
//#include <math.h>
#include "object.h"
using namespace std;

static const int MAX_ASTEROIDS = 50;
static const int MAX_SHOTS = 10;

/*
struct Vector {
	int x,y;
	Vector():x(0),y(0) {}
	Vector(const int x, const int y):x(x),y(y) {}

	Vector operator-(const Vector &v) const {	return Vector(x-v.x,y-v.y); }
	Vector operator+(const Vector &v) const {	return Vector(x+v.x,y+v.y); }
	Vector operator*(const int &d) const	{	return Vector(x*d,y*d); }
 
	double dist() const {return sqrt((double)(x*x+y*y));}
	int dist2() const {return x*x+y*y;}
};

class Asteroid
{
public:
	Vector pos;
	Vector last_pos;
	int type; // 1 ... 4, äußere Form
	int sf;   // scale factor: 0 = groß, 15 = mittel, 14 = klein

	Asteroid():type(-1),sf(-1) {}

	void set(int x, int y, int type, int sf);

	Vector getPos(const int f) { return (pos-last_pos)*f+pos; }
	void protocol() {
		static FILE *fP=fopen("asteroids.txt","a");

		fprintf(fP,"{%d,%d} \t {%d,%d} \t {%d,%d} \t %f\n",pos.x,pos.y,last_pos.x,last_pos.y, (pos-last_pos).x,(pos-last_pos).y, (pos-last_pos).dist() );
		fflush(fP);
	}
};
class Ship
{
public:
	Vector pos,richt;
	Vector last_pos;
	bool ship_present;  // Schiff sichtbar

	void set(int x, int y, int rx, int ry, bool b);

	Vector getPos(const int f) { return (pos-last_pos)*f+pos; }
};

class Shot
{
public:
	Vector pos;
	Vector last_pos;

	void set(int x, int y);

	Vector getPos(const int f) { return (pos-last_pos)*f+pos; }
	void protocol() {
		static FILE *fP=fopen("shots.txt","a");

		fprintf(fP,"{%d,%d} \t {%d,%d} \t {%d,%d} \t %f\n",pos.x,pos.y,last_pos.x,last_pos.y, (pos-last_pos).x,(pos-last_pos).y, (pos-last_pos).dist() );
		fflush(fP);
	}
};*/

class GameStatus
{
public:
	struct TrackAst {
		enum {NEW, OLD, NONE, NORMAL, CABOOM} status;
		Asteroid ast;
		TrackAst():status(NONE),ast(Vector(0,0),0,0) {}
	};

	Circle circle;
	Ship ship;
	bool saucer_present;// UFO sichtbar
	Saucer saucer;
	int nastro_pos;
	Object *objptrs[100];
	TrackAst asteroids[MAX_ASTEROIDS*2];
	int naster;
	int nshots,nshots_last;     // Anzahl Schüsse
	Shot shots[MAX_SHOTS];
	void clear(void);

	void clearAstroid();
	void setAstroid(int x, int y, int t, int sf);
	void finalAstroid();

	GameStatus():nshots_last(0),saucer(Vector(0,0),0) {}
	
};

#pragma pack(1)
struct FramePacket
{
	char vectorram[1024];
	char frameno;  // wird bei jedem Frame inkrementiert
	char ping;     // Der Server schickt das letzte empfangene ping-Byte zurück
};

class KeysPacket
{
private:

	char signature[6];
public:
	static const char KEY_HYPERSPACE = 1;
	static const char KEY_FIRE = 2;
	static const char KEY_THRUST = 4;
	static const char KEY_RIGHT = 8;
	static const char KEY_LEFT = 0x10;
	char keys;
	char ping;     // wird vom Server bei nächster Gelegenheit zurückgeschickt. Für Latenzmessung.

	KeysPacket(void);
	void clear(void);         // alle Tasten loslassen
	void hyperspace(bool b);  // Hyperspace drücken (true) oder loslassen (false)
	void fire(bool b);        // Feuerknopf drücken (true) oder loslassen (false)
	void thrust(bool b);      // Beschleunigen ...
	void right(bool b);       // rechts drehen ...
	void left(bool b);        // links drehen

	bool right() const {return keys&KEY_RIGHT;}
	bool left() const {return keys&KEY_LEFT;}
	bool fire() const {return keys&KEY_FIRE;}
};
#pragma pack()


class Player
{
public:
	Player(SOCKET sd, ADDRESS server_ip) : sd(sd), server_ip(server_ip) {};
	void Run(void);
	void InterpretScreen(FramePacket &packet, GameStatus& game);
	void ReceivePacket(FramePacket &packet);
	void SendPacket(KeysPacket &packet);
	void SendPlayerName();
private:
	SOCKET sd;
	ADDRESS server_ip;
};
