/***********************************************************************
 * Software License Agreement (BSD License)
 *
 * Copyright 2012  <NAME> (<EMAIL>) All rights reserved.
 *
 * THE BSD LICENSE
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *************************************************************************/
#ifndef NGLGEOMETRYHPP
#define NGLGEOMETRYHPP

#include "math.h"

namespace ngl 
{
	typedef unsigned int IndexType;
	
	template<typename T>
	struct NGLPoint
	{
		T*data;
		inline T& operator[](int i) {
			return data[i];
		}
		inline T operator *() {
			return data;
		}
	};
	
	template<typename T>
	class Geometry {
	public:
		static unsigned int D;
		static void init(unsigned int d) 
		{
			D = d;
		}
		static NGLPoint<T>* allocate(int numPts) 
		{
			NGLPoint<T>* ptr = static_cast<NGLPoint<T>*>( new NGLPoint<T>[numPts] );
			for(int i = 0; i < numPts ; i++) 
			{
				allocate(ptr[i]);
			}
			return ptr;
		}
		static void allocate(NGLPoint<T> &p) 
		{
			p.data = static_cast<T*>( new T[D] );
		}
		static void deallocate(NGLPoint<T> &p) 
		{
			delete p.data;
		}
		inline static T distanceL2(NGLPoint<T> &a, NGLPoint<T> &b) 
		{
			return sqrt(distanceL2sqr(a,b));
		}
		inline static T distanceL2sqr(NGLPoint<T> &a, NGLPoint<T> &b) 
		{
			T dis2 = 0;
			for(unsigned int k=0;k<D;k++) 
			{
				dis2+=(a[k] - b[k])*(a[k] - b[k]);
			}
			return dis2;
		}
		static T distanceL0(NGLPoint<T> &a, NGLPoint<T> & b) 
		{
		}
		static T distanceLinf(NGLPoint<T> &a, NGLPoint<T> & b) 
		{
		}
		inline static void add(NGLPoint<T> & a, NGLPoint<T> & b, NGLPoint<T> &c) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				c[k] = a[k] + b[k];
			}
		}
		inline static void subtract(NGLPoint<T> & a, NGLPoint<T> & b, NGLPoint<T> & c) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				c[k] = a[k] - b[k];
			}
		}
		inline static T dot(NGLPoint<T> & a, NGLPoint<T> & b) 
		{
			T res = 0;
			for(unsigned int k=0;k<D;k++) 
			{
				res+=a[k]*b[k];
			}
			return res;
		}
		inline static T normalize(NGLPoint<T> & a) 
		{
			T adota = dot(a,a);
			T lena = sqrt(adota);
			if(lena>0) {
				for(unsigned int k=0;k<D;k++) 
				{
					a[k]/=lena;
				}
			}
			return lena;
		}
		inline static void set(NGLPoint<T> & dst, NGLPoint<T> & src) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				dst[k] = src[k];
			}
		}
		inline static void set(NGLPoint<T> & dst, T*src) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				dst[k] = src[k];
			}
		}
		inline static void muladd(NGLPoint<T> & a, NGLPoint<T> & b, T t, NGLPoint<T> & c) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				c[k] = a[k] + t*b[k];
			}
		}
		inline static void interpolate(NGLPoint<T> & a, NGLPoint<T> & b, T t, NGLPoint<T> & c) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				c[k] = (1-t)*a[k] + t*b[k];
			}
		}
		inline static void mul(NGLPoint<T> & a, T x, NGLPoint<T> &b) 
		{
			for(unsigned int k=0;k<D;k++) 
			{
				b[k] = a[k]*x;
			}
		}
		
	};
	
	/*
	template<class T>
	struct NGL
	{
		typedef T* Point;
	};
	 */
}

#endif
