#ifndef UTIL_H
#define UTIL_H

#include "my_mesh.h"

#include <QVector3D>
#include <QtMath>


template <typename Mesh>
class HalfedgeLoopRange {
	Mesh &mesh;
	const typename Mesh::HalfedgeHandle &start;

  public:
	HalfedgeLoopRange(Mesh &mesh, const typename Mesh::HalfedgeHandle &start)
		:mesh(mesh), start(start) {}
	typename Mesh::HalfedgeLoopIter begin() {
		return mesh.hl_begin(start);
	}
	typename Mesh::HalfedgeLoopIter end() {
		return mesh.hl_end(start);
	}
};


template <typename Mesh>
class ConstHalfedgeLoopRange {
	Mesh &mesh;
	const typename Mesh::HalfedgeHandle &start;

  public:
	ConstHalfedgeLoopRange(Mesh &mesh, const typename Mesh::HalfedgeHandle &start)
		:mesh(mesh), start(start) {}
	typename Mesh::HalfedgeLoopIter begin() {
		return mesh.chl_begin(start);
	}
	typename Mesh::HalfedgeLoopIter end() {
		return mesh.chl_end(start);
	}
};


QDebug operator<<(QDebug dbg, const Point &p);


/* Returns the angle between the vector from p2 to p1 and the vector
 * from p2 to p3. */
template <typename Point>
qreal angle_between(Point p1, Point p2, Point p3) {
	Point vec_a = p1 - p2;
	Point vec_b = p3 - p2;
	return qAcos(vec_a.dot(vec_b) / (vec_a.norm() * vec_b.norm()));
}


template <typename Point>
qreal triangle_area(Point p1, Point p2, Point p3) {
	Point vec_a = p1 - p2;
	Point vec_b = p3 - p2;
	return vec_a.cross(vec_b).norm() / 2.;
}


qreal cotan(const qreal x);


template <typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
	if (v < lo) return lo;
	if (v > hi) return hi;
	return v;
}


template <typename ForwardIt>
constexpr typename ForwardIt::value_type average(const ForwardIt first,
												 const ForwardIt last) {
	typedef typename ForwardIt::value_type value_type;
	if (first == last) return 0;
	value_type average = 0;
	for (ForwardIt it = first; it != last; ++it) {
		average += *it;
	}
	return average / (last - first);
}


template <typename ForwardIt>
constexpr  typename ForwardIt::value_type
standard_deviation(const ForwardIt first,
				   const ForwardIt last,
				   typename ForwardIt::value_type average) {
	typedef typename ForwardIt::value_type value_type;
	if (first == last) return 0;
	value_type accumulator = 0;
	for (ForwardIt it = first; it != last; ++it) {
		accumulator += (*it - average) * (*it - average);
	}
	return sqrt(accumulator / (last - first));
}


#endif
