/*
 * N-dimensional vector
 */

#ifndef __OGL2_NVEC__
#define __OGL2_NVEC__

#if !defined (__GNUG__) && !defined (__attribute__)
#define __attribute__(foo) /* Ignore.  */
#endif

#include <iostream>

extern "C++" {

template <class __type>
struct nvec
{
  int dim;
  mutable __type* v;

  nvec() : dim(0), v(0) {}
  nvec(int n) : dim(n) {
    v = new __type[n];
    __type *d = v;
    for(int i=dim; i; i--, d++)
      *d = 0;
  }
  nvec(const nvec<__type>& B) {
    dim = B.dim;
    v = new __type[B.dim];
    __type* d = v;
    __type* s = B.v;
    for(int i=dim; i; i--, d++, s++) 
      *d = *s;
  }
  nvec<__type>& operator = (const nvec<__type>& B) {
    delete[] v;
    dim = B.dim;
    v = new __type[B.dim];
    __type* d = v;
    __type* s = B.v;
    for(int i=dim; i; i--, d++, s++) 
      *d = *s;
  }
  __type& operator [] (int i) const { return v[i]; }
  nvec<__type>& operator += (const nvec<__type>& b) {
    int i = b.dim>dim ? dim : b.dim;
    __type* d = v;
    __type* s = b.v;
    for(;i;i--, s++, d++) 
      *d += *s;
    return *this;
  }
  nvec<__type>& operator -= (const nvec<__type>& b) {
    int i = b.dim>dim ? dim : b.dim;
    __type* d = v;
    __type* s = b.v;
    for(;i;i--, s++, d++)
      *d -= *s;
    return *this;
  }
  nvec<__type>& operator *= (const nvec<__type>& b) {
    int i = b.dim>dim ? dim : b.dim;
    __type* d = v;
    __type* s = b.v;
    for(;i;i--, s++, d++) 
      *d *= *s;
    return *this;
  }

  ~nvec() {
    delete[] v;
  }
};

template class nvec<float>;
typedef nvec<float> nvecf;

template class nvec<double>;
typedef nvec<double> nvecd;

template class nvec<long double>;
typedef nvec<long double> nvecld;

template class nvec<int>;
typedef nvec<int> nveci;

template <class __type>
ostream& operator << (ostream& s, const nvec<__type>& a)
{
  int i=0;
  s << "(";
  while(i<(a.dim-1))
  {
    s << a[i] << ",";
    i++;
  }
  s << a[i] << ")";
  return (s);
}


template <class __type> inline nvec<__type>
operator + (const nvec<__type>& a) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator + (const nvec<__type>& a)
{
  return a;
}

template <class __type> inline nvec<__type>
operator - (const nvec<__type>& a) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator - (const nvec<__type>& a)
{
  nvec<__type> u(a.dim);
  __type* s = a.v;
  __type* d = u.v;
  for(int i=a.dim; i; i--, s++, d++)
    *d = -(*s);
  return u;
}

template <class __type> inline nvec<__type>
operator + (const nvec<__type>& a, const nvec<__type>& b) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator + (const nvec<__type>& a, const nvec<__type>& b)
{
  if(a.dim>b.dim) {
    nvec<__type> c(a); 
    c+=b;
    return c;
  }
  else {
    nvec<__type> c(b);
    c+=a;
    return c;
  }
}

template <class __type> inline nvec<__type>
operator - (const nvec<__type>& a, const nvec<__type>& b) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator - (const nvec<__type>& a, const nvec<__type>& b)
{
  if(a.dim>b.dim) {
    nvec<__type> c(a); 
    c-=b;
    return c;
  }
  else {
    nvec<__type> c(b.dim);
    c+=a;
    c-=b;
    return c;
  }
}

template <class __type> inline nvec<__type>
operator * (const nvec<__type>& a, __type s) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator * (const nvec<__type>& a, __type s)
{
  nvec<__type> c(a);
  __type *d = c.v;
  for(int i=c.dim; i; i--, d++)
    *d *= s;
  return c;
}

template <class __type> inline nvec<__type>
operator * (__type s, const nvec<__type>& a) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator * (__type s, const nvec<__type>& a)
{
  nvec<__type> c(a);
  __type *d = c.v;
  for(int i=c.dim; i; i--, d++)
    *d *= s;
  return c;
}

template <class __type> inline nvec<__type>
operator * (const nvec<__type>& a, const nvec<__type>& b) __attribute__ ((const));

template <class __type> inline nvec<__type>
operator * (const nvec<__type>& a, const nvec<__type>& b)
{
  if(a.dim>b.dim) {
    nvec<__type> c(a); 
    c*=b;
    return c;
  }
  else {
    nvec<__type> c(b);
    c*=a;
    return c;
  }
}

} // extern "C++"

#endif 
