#ifndef __SL_VECTOR_3D_H
#define __SL_VECTOR_3D_H

#include<iostream>
#include<cstring>
#include<cmath>

#include "slMathTraits.h"

namespace sl {

template<class T> class vector3D;
template<class T> class matrix4x4;

template<class T>
class vector3D {
  friend class matrix4x4<T>;
 private :
  T data[3];
 public :
  T& operator [](int index);
  const T& operator [](int index)const;
 public :
  vector3D<T>& operator =(const vector3D& v);
 public :
  const T* c_ptr(void)const;
  T length(void)const;
  T length_squared(void)const;
  void normalize(void);
 public :
  vector3D();
  vector3D(T x, T y, T z);
  vector3D(const vector3D& v);
 ~vector3D();
};

template<class T>
inline vector3D<T>::vector3D()
{
}

template<class T>
inline vector3D<T>::vector3D(T x, T y, T z)
{
 data[0] = x;
 data[1] = y;
 data[2] = z;
}

template<class T>
inline vector3D<T>::vector3D(const vector3D& v)
{
 data[0] = v.data[0];
 data[1] = v.data[1];
 data[2] = v.data[2];
}

template<class T>
inline vector3D<T>::~vector3D()
{
}

template<class T>
inline vector3D<T>& vector3D<T>::operator =(const vector3D& v)
{
 if(this == &v) return *this;
 data[0] = v.data[0];
 data[1] = v.data[1];
 data[2] = v.data[2];
 return *this;
}

template<class T>
inline T& vector3D<T>::operator [](int index)
{
 return data[index];
}

template<class T>
inline const T& vector3D<T>::operator [](int index)const
{
 return data[index];
}

template<class T>
inline const T* vector3D<T>::c_ptr(void)const
{
 return &data[0];
}

template<class T>
inline T vector3D<T>::length(void)const
{
 return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]);
}

template<class T>
inline T vector3D<T>::length_squared(void)const
{
 return data[0]*data[0] + data[1]*data[1] + data[2]*data[2];
}

template<class T>
inline void vector3D<T>::normalize(void)
{
 T denom = math_traits<T>::one()/length();
 data[0] *= denom;
 data[1] *= denom;
 data[2] *= denom;
}

};

template<class T>
inline ostream& operator <<(ostream& os, const sl::vector3D<T>& v)
{
 os << "<" << v[0] << "," << v[1] << "," << v[2] << ">";
 return os;
}

#endif
