//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#ifndef NVECTOR_H
#define NVECTOR_H
#ifdef _WIN32
#pragma once
#endif


#include <math.h>


#define NVectorN	NVector<N>
#define NVector3	NVector<3>


// N-dimensional vector.
template<int N>
class NVector
{
public:

					NVectorN() {}

	float&			operator[]( int i );
	float const&	operator[]( int i ) const;
	
	float			Dot( NVectorN const &b ) const;
	NVectorN		Cross( NVectorN const &b ) const;
	NVectorN		Normalize() const;
	float			Length() const;

	NVectorN		operator-() const;
	NVectorN		operator+( NVectorN const &b ) const;
	NVectorN const &operator+=( NVectorN const &b );
	NVectorN		operator-( NVectorN const &b ) const;
	NVectorN		operator*( float val ) const;


// Static helpers.
public:

	static NVectorN	SetupNVectorNull();	// Returns a vector of all zeros.


public:
	
	float			v[N];
};


template<int N>
inline float NDot( NVector<N> const &a, NVector<N> const &b )
{
	float ret = 0;
	for( int i=0; i < N; i++ )
		ret += a.v[i] * b.v[i];
	return ret;
}

template<int N>
Vector& ToVec( NVector<N> &vec )			{assert( N >= 3 ); return *((Vector*)&vec);}

template<int N>
Vector const& ToVec( NVector<N> const &vec ){assert( N >= 3 ); return *((Vector const*)&vec);}

NVector<3>&			ToNVec( Vector &vec )		{return *((NVector<3>*)&vec);}
NVector<3> const&	ToNVec( Vector const &vec )	{return *((NVector<3> const*)&vec);}


// ------------------------------------------------------------------------------------ //
// NVector inlines.
// ------------------------------------------------------------------------------------ //

template<int N>
NVectorN NVectorN::SetupNVectorNull()
{
	NVector<N> ret;
	memset( ret.v, 0, sizeof(float)*N );
	return ret;
}


template<int N>
float& NVectorN::operator[]( int i )
{
	assert( i >= 0 && i < N );
	return v[i];
}


template<int N>
float const& NVectorN::operator[]( int i ) const
{
	assert( i >= 0 && i < N );
	return v[i];
}


template<int N>
float NVectorN::Dot( NVectorN const &b ) const
{
	float ret = 0;
	
	for( int i=0; i < N; i++ )
		ret += v[i]*b.v[i];

	return ret;
}


template<int N>
NVectorN NVectorN::Cross( NVectorN const &b ) const
{
	NVector<N> ret;
	NMatrix<N-1> mat;
	
	for( int i=0; i < N; i++ )
	{
		for( y=0; y < N; y++ )
			for( x=0; x < N; x++ )
				mat.m[y][x] = 

		ret.v[i] = v[i]*b.v[i];
	}

	return ret;
}


template<int N>
NVectorN NVectorN::Normalize() const
{
	return *this * (1.0f / Length());
}


template<int N>
float NVectorN::Length() const
{
	return (float)sqrt( Dot(*this) );
}


template<int N>
NVectorN NVectorN::operator-() const
{
	NVectorN ret;
	for( int i=0; i < N; i++ )
		ret.v[i] = -v[i];
	return ret;
}


template<int N>
NVectorN NVectorN::operator+( NVectorN const &b ) const
{
	NVectorN ret;
	
	for( int i=0; i < N; i++ )
		ret.v[i] = v[i]+b.v[i];

	return ret;
}


template<int N>
NVectorN const &NVectorN::operator+=( NVectorN const &b )
{
	for( int i=0; i < N; i++ )
		v[i] += b.v[i];
	return *this;
}


template<int N>
NVectorN NVectorN::operator-( NVectorN const &b ) const
{
	NVectorN ret;
	
	for( int i=0; i < N; i++ )
		ret.v[i] = v[i]-b.v[i];

	return ret;
}

template<int N>
NVectorN NVectorN::operator*( float val ) const
{
	NVectorN ret;
	for( int i=0; i < N; i++ )
		ret.v[i] = v[i] * val;
	return ret;
}


#endif // NVECTOR_H