/*
   core/zone.h
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#ifndef __INCLUDED_CORE_ZONE_H__
#define __INCLUDED_CORE_ZONE_H__

#include <string>
#include <list>
#include <map>

namespace core
{

class Zone;

}

#include "core/entity.h"
#include "core/physics.h"

namespace core
{

/// a Zone contains a compartment of the game universe
class Zone : public Label
{
public:
	/// type definition for the content of a zone
	typedef std::list<Entity *> Content;

	/// type definition for the zone registry
	typedef std::map<unsigned int, Zone *> Registry;

	/* ---- static functions ----------------------------------- */

	/// add a zone to the zone registry
	static void add(Zone *zone);

	/// add a zone with a specific id to the registry
	static void add(Zone *zone, unsigned int id);

	/// find a zone in the zone registry
	static Zone *find(unsigned int id);

	/// find a zone in the zone registry
	static Zone *find(std::string const & name);

	/// remove a zone from the zone registry
	static void remove(Zone *zone);

	/// list the zone registry
	static void list();

	/// search the zone registry for an id, label or name
	static Zone *search(std::string const & searchname);

	/// clear the zone registry
	static void clear();

	/// the zone registry
	static inline Registry & registry() {
		return zone_registry;
	}
	
	/// default infotype for zones
	static inline const InfoType *infotype() {
		return zone_infotype;
	}
	
	/// set the default infotype for zones
	static inline void set_infotype(const InfoType *infotype) {
		zone_infotype = infotype;
	}

	/* ---- Zone class ----------------------------------------- */
	
	enum Flags { Hidden = 1 };

	/**
	 * @brief create a new zone
	 * This is a server-side constructor
	 * */
	Zone(std::string const & label);

	/**
	 * @brief create a zone from stream data
	 * This is a client-side constructor
	 * */
	Zone(std::istream & is);

	/**
	 * @brief default destructor
	 * */
	virtual ~Zone();

	/* ---- inspectors ----------------------------------------- */

	/// print the content of a zone
	void print();

	/// zone id
	inline unsigned int id() const {
		return zone_id;
	}
	
	/// zone flags
	inline const unsigned int flags() const {
		return zone_flags;
	}

	/**
	 * @brief returns true if a specified flag is set
	 * */
	inline const bool has_flag(const Flags flag) const {
		return ((zone_flags & (unsigned int) flag) == (unsigned int) flag);
	}

	/// ambient light color
	inline math::Color const & ambient_color() {
		return zone_ambient_color;
	}
	
	/// name of the skybox
	inline std::string const & sky() const {
		return zone_sky;
	}

	/// default zone view, returns 0 if not set
	inline Entity *default_view() {
		return zone_defaultview;
	}
	
	/// zone information record, returns 0 if not set
	inline const Info *info() const {
		return zone_info;
	}
	
	/**
	 * @brief return the zone's color
	 * This is the color used to represent the zone on the galactic map
	 * */
	const math::Color & color() const {
		return zone_color;
	}
	
	/**
	 * @brief returns the galactic location of this zone
	 * */
	const math::Vector3f & location() const {
		return zone_location;
	}

	/// find an entity inside a zone
	Entity *find_entity(const Entity *entity);

	/// find an entity inside a zone
	Entity *find_entity(unsigned int id);

	/// find a labeled entity inside a zone
	Entity *find_entity(const std::string & label);

	/// search for an entity inside a zone
	Entity *search_entity(const std::string & label);

	/* ---- mutators ------------------------------------------- */
	
	/**
	 * @brief set flag
	 * */
	inline void set_flag(Flags flag) {
		zone_flags |= (unsigned int) flag;
	}

	/**
	 * @brief unset flag
	 * */
	inline void unset_flag(Flags flag) {
		zone_flags &= ~((unsigned int) flag);
	}

	/**
	 * @brief set the skybox name
	 * */
	inline void set_sky(std::string const & sky) {
		zone_sky.assign(sky);
	}

	/**
	 * @brief set the ambient light color
	 * */
	inline void set_ambient_color(const math::Color & ambient_color) {
		zone_ambient_color.assign(ambient_color);
	}
	
	/**
	 * @brief set the ambient light color
	 * @param r red value [0-1]
	 * @param g green value [0-1]
	 * @param b blue value [0-1]
	 * */
	inline void set_ambient_color(float r, float g, float b) {
		zone_ambient_color.assign(r, g, b);
	}
	
	/**
	 * @brief set the default view for this zone
	 * */	
	inline void set_default_view(Entity *entity) {
		zone_defaultview = entity;
	}
	
	/**
	 * @brief set the galactic location for this zone
	 * */
	inline void set_location(float x, float y, float z) {
		zone_location.assign(x, y, z);
	}
	
	/**
	 * @brief set the galactic location for this zone
	 * */
	inline void set_location(const math::Vector3f & location) {
		zone_location.assign(location);
	}
	
	/**
	 * @brief set the information record for this zone
	 * */
	void set_info(const Info *info);
	
	/**
	 * @brief set the zone color
	 * */
	void set_color(const math::Color & color);
	
	void set_color(float r, float g, float b);
	
	/* ---- serializers ---------------------------------------- */

	/**
	 * @brief serialize the zone's state to a server-to-client update message on a stream
	 * */
	void serialize_server_update(std::ostream & os) const;

	/**
	 * @brief deserialize the zone's state from a server-to-client update message on a stream
	 * */
	void receive_server_update(std::istream &is);

	/* ---- zone content --------------------------------------- */

	/// the entities belonging to this zone
	inline Content & content() {
		return zone_content;
	}

	/// add an entity to this zone
	void add(Entity *entity);

	/// remove an entity from this zone
	void remove(Entity *entity);

	/// physics world for this zone
	inline btDiscreteDynamicsWorld *physics() {
		return zone_bullet_world;
	}
	
	/// physics vehicle raycaster
	inline btVehicleRaycaster *raycaster() {
		return zone_bullet_raycaster;
	}
	
	math::BoundingBox3f & keepalive_box() {
		return zone_keepalive_box;
	}
	
	const bool keepalive_run() const {
		return zone_keepalive_run;
	}

	void set_keepalive_run(const bool keepalive_run) {
		zone_keepalive_run = keepalive_run;
	}
	
private:
	unsigned int		zone_id;
	unsigned int		zone_flags;
	math::Vector3f		zone_location;
	math::Color		zone_color;
	
	std::string		zone_sky;
	math::Color		zone_ambient_color;

	
	Content			zone_content;
	Entity			*zone_defaultview;
	
	btAxisSweep3		*zone_bullet_cache;
	btDiscreteDynamicsWorld *zone_bullet_world;
	btVehicleRaycaster	*zone_bullet_raycaster;
	
	math::BoundingBox3f	zone_keepalive_box;
	bool			zone_keepalive_run;
	
	const Info*		zone_info;
	
	static const InfoType 	*zone_infotype;
	static Registry		zone_registry;
};

}

#endif // __INCLUDED_CORE_ZONE_H__