/*
   model/fragment.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_MODEL_FRAGMENT_H__
#define __INCLUDED_MODEL_FRAGMENT_H__

#include <list>

#include "math/axis.h"
#include "math/vector3f.h"
#include "math/vector2f.h"
#include "model/material.h"

namespace model
{

/// a fragment of a model, a pointer into a continuous part of the VertexArray containing tris or quads
class Fragment
{
public:
	/// fragment primitive type: triangles or quads
	enum Type {Triangles, Quads};

	/// create a new fragment
	Fragment(Type type, const Material *material);

	/**
	 * @brief copy constructor
	 */
	Fragment(const Fragment &other);

	/// add a vertex to the fragment
	size_t add_vertex(math::Vector3f const & vertex, math::Vector3f const &normal, bool detail);

	/// add a vertex to the fragment
	size_t add_vertex(math::Vector3f const & vertex, math::Vector3f const &normal, math::Vector2f const &texcoord, bool detail);

	/// the type of primitives this fragment consists of
	inline Type type() const {
		return fragment_type;
	}

	/// VertexArray index of the start of the fragment
	inline size_t index() const {
		return fragment_index;
	}

	/// number of structural vertices in the fragment
	inline size_t structural_size() const {
		return fragment_structural_size;
	}

	/// number of detail vertices in the fragment
	inline size_t detail_size() const {
		return fragment_detail_size;
	}

	/// material flags
	inline const Material * material() const {
		return fragment_material;
	}

private:
	Type			fragment_type;
	size_t			fragment_index;
	size_t			fragment_structural_size;
	size_t			fragment_detail_size;
	const Material *	fragment_material;
};

/// a collection of fragments
/**
 * a FragmentGroup contains the model fragments for one class in the .map file.
 * worldspawn is a FragmentGroup
 */
class FragmentGroup
{
public:
	enum Type {None = 0, Rotate = 1, Door = 2 };

	/// type definition for a list of model fragments
	typedef std::list<Fragment *> Fragments;

	FragmentGroup();

	~FragmentGroup();
	
	/* ---- inspectors ----------------------------------------- */

	inline const Type type() const {
		return group_type;
	}

	inline const math::Vector3f &location() const {
		return group_location;
	}

	inline const math::Axis & axis() const {
		return group_axis;
	}

	inline const float speed() const {
		return group_speed;
	}

	inline const float scale() const {
		return group_scale;
	}

	inline const bool transform() const {
		return group_transform;
	}
	
	inline const bool engine() const {
		return group_engine;
	}

	inline const size_t size() const {
		return group_fragments.size();
	}

	inline const Fragments & fragments() const {
		return group_fragments;
	}
	
	/* ---- mutators ------------------------------------------- */
	
	inline void set_type(const Type type) {
		group_type = type;
	}

	inline void set_engine(const bool engine) {
		group_engine = engine;
	}
	
	inline void set_location(const math::Vector3f &location) {
		group_location.assign(location);
	}

	inline void set_axis(const math::Axis &axis) {
		group_axis.assign(axis);
	}

	inline void set_speed(const float speed) {
		group_speed = speed;
	}

	inline void set_scale(const float scale) {
		group_scale = scale;
	}

	inline void set_transform(const bool transform) {
		group_transform = transform;
	}

	inline void add_fragment(Fragment *fragment) {
		group_fragments.push_back(fragment);
	}

	void clear();

private:
	Fragments		group_fragments;
	math::Vector3f		group_location;
	math::Axis		group_axis;

	Type			group_type;
	float			group_speed;
	float			group_scale;

	bool			group_transform;
	bool			group_engine;
};

}

#endif // __INCLUDED_MODEL_FRAGMENT_H__