#ifndef TYPEDEFS_H_
#define TYPEDEFS_H_

#include <map>
#include <vector>
#include <deque>

#include "config.h"
#include <ode/ode.h>
#include "AssertionException.h"
#include "vectorMath/vmath.h"

/** Own ASSERT macro, defined to work with own AssertionException */
#define mASSERT(a) if (!(a)) {\
	_FATAL("Assertion \"" #a "\" failed");\
	throw AssertionException("assertion \"" #a "\" failed");\
}

/** Shorthand notations for basic vector and matrix types */
typedef Vector2<dReal> Vector2r;
typedef Vector3<dReal> Vector3r;
typedef Vector4<dReal> Vector4r;
typedef Matrix3<dReal> Matrix3r;
typedef Matrix4<dReal> Matrix4r;
typedef Quaternion<dReal> Quatr;

/** Positioned vector */
typedef struct PVector3r {
	/** Vector position */
	Vector3r _pos;
	/** Vector direction */
	Vector3r _dir;
	PVector3r(const Vector3r &pos, const Vector3r &dir): _pos(pos), _dir(dir) {};
} PVector3r;
std::ostream& operator<<(std::ostream &oss, const PVector3r &p);
std::ostream& operator<<(std::ostream &oss, const PVector3r* p);

/** Structure for holding Viewpoint data */
typedef struct ViewPoint {
	/** Viewpoint position in x,y,z coordinates */
	float _xyz[3];
	/** Viewpoint direction along x,y,z axes */
	float _hpr[3];
} ViewPoint;
/** Basic Viewpoint container */
typedef std::vector<ViewPoint> ViewPointVector;

class SimulationObject;
/** Basic container for holding simulation object pointers by their ID */
typedef std::map<int, SimulationObject*> SOContainer;
typedef std::vector<SimulationObject*> SOVector;

class Car;
/** Basic container for holding car pointers */
typedef std::vector<Car*> CarVector;
std::ostream& operator<<(std::ostream &oss, const CarVector &cv);

class Animated;
/** Basic container for animated objects */
typedef std::map<int, Animated*> AOContainer;

class Visualized;
/** Basic container for visualized objects */
typedef std::map<int, Visualized*> VOContainer;

class Sector;
/** Basic container for holding sector pointers by their ID */
typedef std::map<int, Sector*> SectorMap;
/** Vector container for sectors */
typedef std::vector<Sector*> SectorVector;
/** Deque container for sectors */
typedef std::deque<Sector*> SectorDeque;
std::ostream& operator<<(std::ostream &oss, const SectorDeque &sd);

/** Structure for holding polygon data - a series of vetrices */
typedef std::deque<Vector3r> Polygon;
std::ostream& operator<<(std::ostream &oss, const Polygon &p);
std::ostream& operator<<(std::ostream &oss, const Polygon* p);

/** Basic 2-point line */
typedef struct Line {
	Line(): _a(), _b() {};
	Line(const Vector3r &a, const Vector3r &b): _a(a), _b(b) {};
	/** Start point */
	Vector3r _a;
	/** End point */
	Vector3r _b;
	bool operator==(const Line &l) { return (_a == l._a) && (_b == l._b); };
	/** Inverts the line by exchanging the start and end points */
	inline void invert() { Vector3r tmp = _a; _a = _b; _b = tmp; };
} Line;
std::ostream& operator<<(std::ostream &oss, const Line &l);

/** Deque-like polygon vector */
typedef std::deque<Polygon*> PolygonVector;
/** Container mapping sectors to border polygons */
typedef std::map<Sector*, Polygon*> SectorPolygonMapping;

/** Structure for holding data about a particular car type */
typedef struct CarType {
	CarType(): _bodySize(-1, -1, -1), _wheelRad(-1), _wheelThick(-1), _wheelWeight(-1), _weight(-1), _maxSpeed(-1), _acceleration(-1), _decceleration(-1) {};
	/** Size of car's body */
	Vector3r _bodySize;
	/** Wheel radius */
	dReal _wheelRad;
	/** Wheel thickness */
	dReal _wheelThick;
	/** Weight of a single wheel */
	dReal _wheelWeight;
	/** Car weight */
	dReal _weight;
	/** Maximum car speed */
	dReal _maxSpeed;
	/** Maximum car acceleration */
	dReal _acceleration;
	/** Maximum car decceleration */
	dReal _decceleration;
	/** Checks if all car parameters have been filled in */
	bool check() {
		if (_bodySize.x == -1 || _bodySize.y == -1 || _bodySize.z == -1 ||
			_wheelRad == -1 || _wheelThick == -1 || _wheelWeight == -1 || _weight == -1 || _maxSpeed == -1 || _acceleration == -1 || _decceleration == -1) return false;
		else return true;
	}
} CarType;

/** Basic container for holding the car type data by the type name */
typedef std::map<std::string, CarType> CarTypeMap;

/** Priority of a car
 * CAR_FOLLOW - use the car follow mode and adjust speed accordingly
 * CAR_NOT_INTERFERING - ignore the car
 * CAR_LET_GO - basicaly wait until car clears the sector
 * CAR_LETS_GO - such car should let us go, so ignore and go
 */
enum CarPriority { CAR_FOLLOW, CAR_NOT_INTERFERING, CAR_LET_GO, CAR_LETS_GO };

/** Internal definition for assignment of a car to it's priority */
typedef std::pair<Car*, CarPriority> CarInSight;

/** Container for holding all cars in sight along with their priority */
typedef std::multimap<Sector*, CarInSight> SectorCarMapping;
std::ostream& operator<<(std::ostream &oss, const SectorCarMapping &sm);

#endif /*TYPEDEFS_H_*/
