/*------------------------------------------------------------------------------
 src/lib/dj/djVecFnc_.h
 
 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

#include <djMath.h>

namespace dj {

template <int C, class T>
inline const Vec<C, T> normalize(const Vec<C, T> & in)
{
  const double l = length(in);
  Vec<C, T> tmp;
  if (! isZero(l))
    for (int c = 0; c < C; ++c) tmp[c] = T(in[c] / l);
  return tmp;
}

template <int C, class T>
inline double dot(const Vec<C, T> & a, const Vec<C, T> & b)
{
  double out = 0.0;
  for (int c = 0; c < C; ++c)
    out += a[c] * b[c];
  return out;
}

template <int C, class T>
inline const Vec<C, T> swap(const Vec<C, T> & in)
{
  Vec<C, T> out;
  for (int c = 0; c < C; ++c)
    out[c] = in[C - 1 - c];
  return out;
}

template <int C, class T>
inline double length(const Vec<C, T> & in)
{
  double r = 0.0;
  for (int c = 0; c < C; ++c)
    r += in[c] * in[c];
  return sqrt(r);
}

template <int C, class T>
inline const T area(const Vec<C, T> & in)
{
  T out = C ? in[0] : T(0);
  for (int c = 1; c < C; ++c)
    out *= in[c];
  return out;
}

template <int C, class T>
inline bool areaIsValid(const Vec<C, T> & in)
{
  for (int c = 0; c < C; ++c)
    if (in[c] <= 0) return false;
  return true;
}

template <class T>
inline double aspect(const Vec<2, T> & in)
{
  return in.y() != T(0) ? (in.x() / double(in.y())) : 0.0;
}

#define _DJ_VEC_ARITHMETIC(OP) \
template <int C, class T> \
inline const Vec<C, T> operator OP ( \
  const Vec<C, T> & a, \
  const Vec<C, T> & b \
) { \
  Vec<C, T> out; \
  for (int c = 0; c < C; ++c) \
    out[c] = a[c] OP b[c]; \
  return out; \
}
_DJ_VEC_ARITHMETIC(+)
_DJ_VEC_ARITHMETIC(-)
_DJ_VEC_ARITHMETIC(*)
_DJ_VEC_ARITHMETIC(/)

#define _DJ_VEC_ARITHMETIC_SCALAR(OP) \
template <int C, class T> \
inline const Vec<C, T> operator OP ( \
  const Vec<C, T> & a, \
  const T & b \
) { \
  Vec<C, T> out; \
  for (int c = 0; c < C; ++c) \
    out[c] = a[c] OP b; \
  return out; \
}
_DJ_VEC_ARITHMETIC_SCALAR(+)
_DJ_VEC_ARITHMETIC_SCALAR(-)
_DJ_VEC_ARITHMETIC_SCALAR(*)
_DJ_VEC_ARITHMETIC_SCALAR(/)

#define _DJ_VEC_ARITHMETIC_DOUBLE(OP) \
template <int C, class T> \
inline const Vec<C, T> operator OP ( \
  const Vec<C, T> & a, \
  double b \
) { \
  Vec<C, T> out; \
  for (int c = 0; c < C; ++c) \
    out[c] = T(a[c] OP b); \
  return out; \
}
_DJ_VEC_ARITHMETIC_DOUBLE(+)
_DJ_VEC_ARITHMETIC_DOUBLE(-)
_DJ_VEC_ARITHMETIC_DOUBLE(*)
_DJ_VEC_ARITHMETIC_DOUBLE(/)

template <int C, class T>
inline const Vec<C, T> operator - (const Vec<C, T> & in)
{
  Vec<C, T> out;
  for (int c = 0; c < C; ++c)
    out[c] = -in[c];
  return out;
}

template <int C, class T>
inline const Vec<C, T> min(const Vec<C, T> & a, const Vec<C, T> & b)
{
  Vec<C, T> out;
  for (int c = 0; c < C; ++c)
    out[c] = min(a[c], b[c]);
  return out;
}

template <int C, class T>
inline const Vec<C, T> max(const Vec<C, T> & a, const Vec<C, T> & b)
{
  Vec<C, T> out;
  for (int c = 0; c < C; ++c)
    out[c] = max(a[c], b[c]);
  return out;
}

#define _DJ_VEC_COMPARE(OP, COMPARE) \
template <int C, class T> \
inline bool operator OP ( \
  const Vec<C, T> & a, \
  const Vec<C, T> & b \
) { \
  for (int c = 0; c < C; ++c) \
    if (a[c] COMPARE b[c]) return false; \
  return true; \
}
_DJ_VEC_COMPARE(==, !=)
_DJ_VEC_COMPARE(<, >=)
_DJ_VEC_COMPARE(<=, >)
_DJ_VEC_COMPARE(>, <=)
_DJ_VEC_COMPARE(>=, <)

template <int C, class T>
inline bool operator != (const Vec<C, T> & a, const Vec<C, T> & b)
{
  for (int c = 0; c < C; ++c)
    if (a[c] != b[c]) return true;
  return false;
}

template <int C, class T>
inline const StrList deflateStr(const Vec<C, T> & in)
{
  StrList out;
  for (int c = 0; c < C; ++c)
    out += deflateStr(in[c]);
  return out;
}

template <int C, class T>
inline bool inflateStr(StrList & in, Vec<C, T> * out)
{
  for (int c = 0; c < C; ++c)
    if (! inflateStr(in, &((*out)[c]))) return false;
  return true;
}

}
