#ifndef INCLUDED_RENDERER_MODEL
#define INCLUDED_RENDERER_MODEL

#include "Color.h"

#include <Math/Vector.h>

#include <vector>
#include <memory>

//////////////////////////////////////////////////////////////
namespace Dubious {

namespace Utility { 
class AC3DFile;
class AC3DModel; 
class AC3DMaterial;
typedef std::vector<AC3DMaterial> AC3DMaterialVector;
}

namespace Renderer {

class Model;
typedef std::shared_ptr<Model> ModelPtr;
typedef std::vector<ModelPtr> ModelPtrVector;
typedef std::vector<Math::LocalVector> LocalVectorVector;

/// @brief Representation of a visible model
///
/// The Renderer::Model is a model suitable for drawing in
///	OpenGL.  It is similar to the AC3DModel, but it contains
///	more information, like point normals.
class Model
{
public:
	Model( const Utility::AC3DFile& File, bool IncludeEdges );
	Model( const Math::CubeVector& Size, bool IncludeEdges );
	~Model();

	/// @brief Model Surface
	///
	/// A Model Surface object contains 3 indices into the Point
	///	array.  
	struct Surface
	{
		unsigned short  p0, p1, p2;
		Math::LocalVector Normal;
	};
	typedef std::vector<Surface> SurfaceVector;

	/// @brief A Model Edge
	///
	/// The Edge structure is a simple thing used to keep
	///	track of points and surfaces.  Each variable is an index
	///	into the m_Points and m_Surfaces members
	struct Edge
	{
		unsigned short  p0, p1;
		unsigned short  s0, s1;
	};
	typedef std::vector<Edge> EdgeVector;

	/// @brief Builds the edges
	///
	/// Builds the internal edges structure.  This is used by
	///	the shadow rendering system to construct silhouettes.
	void				BuildEdges();

	const Math::LocalVector& Offset() const { return m_Offset; }
	const LocalVectorVector& Points() const { return m_Points; }
	const SurfaceVector& Surfaces() const { return m_Surfaces; }
	const EdgeVector&	Edges() const { return m_Edges; }
	const Color&		MaterialColor() const { return m_Color; }
	const ModelPtrVector& Kids() const { return m_Kids; }
private:
	Model();
	Model( const Model& );
	Model& operator=( const Model& );

	void				Construct( const Utility::AC3DModel& AC3DModel, const Utility::AC3DMaterialVector& Materials, bool IncludeEdges );
	void				ComputePointNormals();
	void				AddEdge( unsigned short p0, unsigned short p1, unsigned short s0, unsigned short s1 );

	Math::LocalVector	m_Offset;
	LocalVectorVector	m_Points;
	LocalVectorVector	m_PointNormals;
	SurfaceVector		m_Surfaces;
	EdgeVector			m_Edges;
	Color				m_Color;
	ModelPtrVector		m_Kids;

};

}
}
#endif
