/*
								+----------------------------------+
								|                                  |
								|  ***  Vertex pool template  ***  |
								|                                  |
								|   Copyright © -tHE SWINe- 2008   |
								|                                  |
								|           VertexPool.h           |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __VERTEX_POOL_INCLUDED
#define __VERTEX_POOL_INCLUDED

/**
 *	@file lml/VertexPool.h
 *	@date 2008
 *	@author -tHE SWINe-
 *	@brief vertex pool template
 *
 *	@date 2009-05-23
 *
 *	removed all instances of std::vector::reserve and replaced them by stl_ut::Reserve_*
 *
 *	@date 2010-12-20
 *
 *	removed CForwardAllocatedPool::b_Error() and added code to re-throw std::bad_alloc on failure instead.
 *	changed size types from int to size_t.
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#include "../NewFix.h"
#include <vector>
#include <algorithm>

#include "../Segregated.h"

/*
 *								=== TRefVertex2 ===
 */

/*
 *	template <class TBaseVertex>
 *	struct TRefVertex2
 *		- template for creating reference vertices for any arbitrary vertices
 */
template <class TBaseVertex>
struct TRefVertex2 {
	TBaseVertex *m_p_ref; // referenced vertex
	CForwardAllocatedPool<TBaseVertex> *m_p_vertex_pool; // vertex pool (here we're going to add new vertices)

	typedef TBaseVertex TIntermediate;
	// intermediate type for calculations will be TBaseVertex

	/*
	 *	inline TRefVertex2(const TBaseVertex &r_t_vertex, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
	 *		- default constructor
	 */
	/*inline TRefVertex2(const TBaseVertex &r_t_vertex, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
		:m_p_ref(0), m_p_vertex_pool(&r_vertex_pool) // throw(std::bad_alloc)
	{
		m_p_ref = r_vertex_pool.p_GetVertex(); // insert it to the list
		*m_p_ref = r_t_vertex; // and copy the data
	}*/ // this is dangerous

	/*
	 *	inline TRefVertex2(TBaseVertex *p_vertex, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
	 *		- reference vertex that is already in the list
	 */
	inline TRefVertex2(TBaseVertex &r_vertex, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
		:m_p_ref(&r_vertex), m_p_vertex_pool(&r_vertex_pool)
	{
		_ASSERTE(r_vertex_pool.n_IndexOf(&r_vertex) != -1); // make sure it's inside the vertex list
	}

	/*
	 *	inline TRefVertex2(int n_index, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
	 *		- reference vertex that is already in the list
	 */
	/*inline TRefVertex2(size_t n_index, CForwardAllocatedPool<TBaseVertex> &r_vertex_pool)
		:m_p_ref(r_vertex_pool.p_Vertex(n_index)), m_p_vertex_pool(&r_vertex_pool)
	{
		_ASSERTE(m_p_ref);
	}*/

	/*
	 *	inline TRefVertex2(const TRefVertex2 &r_t_vertex)
	 *		- copy constructor
	 */
	inline TRefVertex2(const TRefVertex2 &r_t_vertex)
		:m_p_ref(r_t_vertex.m_p_ref), m_p_vertex_pool(r_t_vertex.m_p_vertex_pool)
	{}

	/*
	 *	inline TRefVertex2 operator =(const TRefVertex2 &r_t_vertex)
	 *		- copy operator = (need it to avoid unwanted conversions)
	 */
	inline TRefVertex2 operator =(const TRefVertex2 &r_t_vertex)
	{
		m_p_ref = r_t_vertex.m_p_ref;
		m_p_vertex_pool = r_t_vertex.m_p_vertex_pool;

		return *this;
	}

	/*
	 *	inline TRefVertex2 operator =(const TBaseVertex &r_t_vertex)
	 *		- conversion from TBaseVertex to TRefVertex2 (conversion
	 *		  is solved by adding vertex to the vertex list)
	 */
	inline TRefVertex2 operator =(const TBaseVertex &r_t_vertex) // throw(std::bad_alloc)
	{
		m_p_vertex_pool->Insert_Back(1, r_t_vertex); // insert it to the list and copy the data
		m_p_ref = &m_p_vertex_pool->r_Back();

		return *this;
	}

	/*
	 *	inline operator TBaseVertex() const
	 *		- now we need means to convert vertex type to intermediate vertex type
	 */
	inline operator TBaseVertex() const
	{
		return *m_p_ref;
	}

	/*
	 *	inline operator Vector3f() const
	 *		- conversion to Vector3f should return vertex position
	 */
	inline operator Vector3f() const
	{
		return m_p_ref->v_position;
	}

	/*
	 *	inline TRefVertex2 operator =(const Vector3f &r_v_position)
	 *		- assigning Vector3f should write to vertex position
	 */
	inline TRefVertex2 operator =(const Vector3f &r_v_position)
	{
		m_p_ref->v_position = r_v_position;
		return *this;
	}

	/*
	 *	inline bool operator ==(const TBaseVertex &r_t_vertex)
	 *		- we might need means to compare two vertices
	 *		- constant f_epsilon is used as maximal coordinate distance tolerance
	 */
	inline bool operator ==(const TBaseVertex &r_t_vertex)
	{
		return *m_p_ref == r_t_vertex;
	}

	/*
	 *	TVertex operator *(float f_scalar) const
	 *		- return vertex, scaled by f_scalar
	 *		- returns a new TBaseVertex because new vertex originated
	 *		  (in case it will need to be converted to TRefVertex2, it will be added to the list)
	 */
	TBaseVertex operator *(float f_scalar) const
	{
		return *m_p_ref * f_scalar;
	}

	/*
	 *	TBaseVertex operator +(const TBaseVertex &r_vertex) const
	 *		- return vertex with sum of coordinates of both original vertices
	 *		- returns a new TBaseVertex because new vertex originated
	 *		  (in case it will need to be converted to TRefVertex2, it will be added to the list)
	 */
	TBaseVertex operator +(const TBaseVertex &r_vertex) const
	{
		return *m_p_ref + r_vertex;
	}

	/*
	 *	TBaseVertex operator -(const TBaseVertex &r_vertex) const
	 *		- return vertex with sum of coordinates of both original vertices
	 *		- returns a new TBaseVertex because new vertex originated
	 *		  (in case it will need to be converted to TRefVertex2, it will be added to the list)
	 */
	TBaseVertex operator -(const TBaseVertex &r_vertex) const
	{
		return *m_p_ref - r_vertex;
	}

	/*
	 *	TRefVertex2 operator *=(float f_scalar) const
	 *		- return vertex, scaled by f_scalar
	 *		- returns this because no new vertex originated
	 *		  (coordinates of some existing vertex were scaled only)
	 */
	TRefVertex2 operator *=(float f_scalar)
	{
		*m_p_ref *= f_scalar;
		return *this;
	}

	/*
	 *	TRefVertex2 operator +=(const TBaseVertex &r_vertex) const
	 *		- return vertex with sum of coordinates of both original vertices
	 *		- returns this because no new vertex originated
	 *		  (coordinates of some existing vertex were scaled only)
	 */
	TRefVertex2 operator +=(const TBaseVertex &r_vertex)
	{
		*m_p_ref += r_vertex;
		return *this;
	}

	/*
	 *	TRefVertex2 operator -=(const TBaseVertex &r_vertex) const
	 *		- return vertex with sum of coordinates of both original vertices
	 *		- returns this because no new vertex originated
	 *		  (coordinates of some existing vertex were scaled only)
	 */
	TRefVertex2 operator -=(const TBaseVertex &r_vertex)
	{
		*m_p_ref -= r_vertex;
		return *this;
	}
};

/*
 *								=== ~TRefVertex2 ===
 */

#endif // !__VERTEX_POOL_INCLUDED
