#ifndef SECTOR_H_
#define SECTOR_H_

#include <iostream>
#include <string>

#include "../config.h"
#include <ode/ode.h>
#include "../typedefs.h"
#include "../iface/Visualized.h"

class ConfigurationParser;
class Car;

class Sector: public Visualized {
public:
	/** Types of sectors
	 * LANE - simple 1-way lane
	 * JUNCTION - any kind of junction
	 */
	enum SectorType {LANE, JUNCTION};
	
	Sector(int id);
	virtual ~Sector();
	
	/** Gives the ID of the sector */
	int getID() const { return _id; };
	/** Gives the maximum speed allowed in the sector */
	dReal getMaxSpeed() const { return _maxSpeed; };
	/** Gives the type of the sector */
	SectorType getType() const { return _type; };
	/** Visualizes the sector */
	void visualize();
	/** True if the sector is watched by a CarSink */
	bool hasCarSink() const { return _hasCarSink; };
	/** True if the argument sector leads to the sector */
	bool hasEntrySector(Sector* sector) const;
	/** True if the argument sector can be entered from the sector */
	bool hasExitSector(Sector* sector) const;
	/** True if the argument sector is parallel the sector */
	bool hasParallelSector(Sector* sector) const;
	/** Gives the list of adjacent vectors from which the car can enter the sector */
	SectorVector &getEntrySectors() { return _entrySectors; };
	/** Gives the list of adjacent vectors to which the car can drive over to */
	SectorVector &getExitSectors() { return _exitSectors; };
	/** Gives the list of adjacent vectors to which the car can change lane to */
	SectorVector &getParallelSectors() { return _parallelSectors; };
	/** Gives the transit polygon for the argument sector (NULL if not transit sector) */
	Line getTransitLine(Sector* s);
	/** Gives the list of sector borders */
	PolygonVector &getPolygons() { return _polygons; };
	/** Registers a new car among those on the current sector */
	void registerCar(Car* car);
	/** Deregisters car from the current sector */
	void deregisterCar(Car* car);
	/** Adds new listener for car events happening on the sector */
	void addCarEventListener(Car* car);
	/** Removes listener for car events */
	void removeCarEventListener(Car* car);
	/** True if car has registered a listener with this sector */
	bool hasCarEventListener(Car* car) const;
	/** Gives the list of cars currently associated with this sector */
	CarVector &getCars() { return _cars; };
	/** Gives the number of cars currently associated with this sector */
	unsigned getNumOfCars() const { return _cars.size(); };
	/** Reorders the polygons to create a circle and checks for consistency
	 * @return false if consistency check failed (sector cannot be reordered as a circle), otherwise true
	 */
	bool circularize();
	/** Finds if given point lies inside or outside the sector */
	bool containsPoint(const Vector3r &point) const;
	/** Returns links of the sector to other sectors (entry, exit, parallel) */
	std::string describeLinks() const;
	/** Returns string representation of the sector */
	std::string toString() const;
	
private:
	/** Sector ID */
	int _id;
	/** Maximum speed allowed in the sector */
	dReal _maxSpeed;
	/** The type of the sector */
	SectorType _type;
	/** If the sector has a CarSink attached */
	bool _hasCarSink;
	/** The borders of the sector */
	PolygonVector _polygons;
	/** List of adjacent vectors from which the car can enter the sector */
	SectorVector _entrySectors;
	/** List of adjacent vectors to which the car can drive over to */
	SectorVector _exitSectors;
	/** List of adjacent vectors to which the car can change lane to */
	SectorVector _parallelSectors;
	/** Mapping table of polygons to sectors */
	SectorPolygonMapping _s2pmapping;
	
	/** Vector of cars currently located within the range of the sector */
	CarVector _cars;
	/** Vector of cars currently listening to car events on the sector */
	CarVector _carEventListeners;
	
	friend class ConfigurationParser;
	friend std::ostream& operator<<(std::ostream& os, const Sector* s);
};

#endif /*SECTOR_H_*/
