#ifndef _GEO_COMPARE_H_
#define _GEO_COMPARE_H_

#include "geometry_types.h"
#include "geometry_common.h"

class Vertex;

namespace Compare {

	class GEOMETRY_API VertexCmp
	{
	public:
		VertexCmp(float eps=1e-6) : eps_(eps) {}
		bool operator()(const Point3f& v0, const Point3f& v1) const ;
	private:
		float eps_;
	};


	//////////////////////////////////////////////////////////////////////////

	template<class T>
	class ElementAndValue
	{
	public:
		ElementAndValue(const T& e, double v = 0)
			: element_(e)
			, value_(v)
		{
		}

		ElementAndValue(const ElementAndValue& ev)
			: element_(ev.element_)
			, value_(ev.value_)
		{
		}		

		ElementAndValue& operator = (const ElementAndValue<T>& ev) {
			element_ = ev.element_;
			value_ = ev.value_;
			return *this;
		}

		T		  element_;
		double    value_;
	};


	template<class T>
	class ElementAndValueLess {  // smallest -> biggest
	public:
		bool operator()(const ElementAndValue<T>& first, const ElementAndValue<T>& second) const {
			if(first.value_ < second.value_)
				return true;
			else
				return false;
		}
	}; 

	template<class T>
	class ElementAndValueGreater { // biggest -> smallest
	public:
		bool operator()(const ElementAndValue<T>& first, const ElementAndValue<T>& second) const {
			if(first.value_ > second.value_)
				return true;
			else
				return false;
		}
	}; 


	//////////////////////////////////////////////////////////////////////////

	class IndicesAndScore {
	public:
		IndicesAndScore(unsigned int left_idx, unsigned int right_idx, unsigned int s) 
			: left_index_(left_idx)
			, right_index_(right_idx)
			, score_(s)
		{}

		IndicesAndScore(const IndicesAndScore& is) 
			: left_index_(is.left_index_)
			, right_index_(is.right_index_)
			, score_(is.score_)
		{}

		unsigned int left_index_;
		unsigned int right_index_;
		unsigned int score_;
	};


	class IndicesAndScoreGreater {
	public:
		bool operator()(const IndicesAndScore& first, const IndicesAndScore& second) const {
			if(first.score_ > second.score_)
				return true;
			else
				return false;
		}
	}; 


	//////////////////////////////////////////////////////////////////////////

	class IndexAndValue {
	public:
		IndexAndValue(unsigned int idx, const Point3f& pos, double v) : index(idx), value(v) {}
		unsigned int index;
		Point3f      position;
		double       value;
	};


	class IndexAndValueGreater {
	public:
		bool operator()(const IndexAndValue& first, const IndexAndValue& second) const {
			if(first.value > second.value)
				return true;
			else
				return false;
		}
	}; 


	//////////////////////////////////////////////////////////////////////////


	class PositionAndNeighbors
	{
	public:
		PositionAndNeighbors() {}	

		PositionAndNeighbors(const Line3f& l, const Segment3f& seg, const Point3f& pos, std::vector<Vertex*>& nbs) 
			: line(l) 
			, segment(seg)
			, position(pos)
			, neighbors(nbs)
		{}

		PositionAndNeighbors(const PositionAndNeighbors& pn) 
			: line(pn.line) 
			, segment(pn.segment)
			, position(pn.position)
			, neighbors(pn.neighbors)
		{}

		Line3f					line;
		Segment3f				segment;
		Point3f                 position;
		std::vector<Vertex*>	neighbors;
	};


	class PositionAndValue 
	{
	public:
		PositionAndValue() {}

		PositionAndValue(const Point3f& p, double v) 
			: position(p)
			, value(v) 
		{}

		PositionAndValue(const PositionAndValue& pv)
			: position(pv.position)
			, value(pv.value)
		{
		}

		PositionAndValue& operator=(const PositionAndValue& pv) {
			position = pv.position;
			value = pv.value;
			return *this;
		}

		Point3f		position;
		double		value;
	};
}


#endif
