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

#include "djBox.h"
#include <djMath.h>

namespace dj {

template <int C, class T>
inline const Box<C, T> operator + (const Box<C, T> & a, const Vec<C, T> & b)
{
  return Box<C, T>(a.position() + b, a.size());
}

template <int C, class T>
inline const Box<C, T> operator - (const Box<C, T> & a, const Vec<C, T> & b)
{
  return Box<C, T>(a.position() - b, a.size());
}

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

template <int C, class T>
inline const Box<C, T> intersect(const Box<C, T> & a, const Box<C, T> & b)
{
  Vec<C, T> position, size;
  for (int c = 0; c < C; ++c)
    intersect(
      a.position()[c], a.size()[c], b.position()[c], b.size()[c],
      &position[c], &size[c]
    );
  return Box<C, T>(position, size);
}

template <int C, class T>
inline const Box<C, T> bound(const Box<C, T> & a, const Box<C, T> & b)
{
  Vec<C, T> position, size;
  for (int c = 0; c < C; ++c)
    bound(
      a.position()[c], a.size()[c], b.position()[c], b.size()[c],
      &position[c], &size[c]
    );
  return Box<C, T>(position, size);
}

template <int C, class T>
inline const Box<C, T> expand(const Box<C, T> & a, const Vec<C, T> & b)
{
  return Box<C, T>(a.position() - b, a.size() + b * 2);
}

template <int C, class T>
inline bool areaIsValid(const Box<C, T> & in)
{
  return areaIsValid(in.size());
}

template <int C, class T>
inline const Box<C, T> swap(const Box<C, T> & in)
{
  return Box<C, T>(swap(in.position()), swap(in.size()));
}

template <int C, class T>
inline const Vec<C, T> mirror(
  const Box<C, T> & a, const Vec<C, T> & b, const bool mirror [C]
) {
  Vec<C, T> out;
  for (int c = 0; c < C; ++c)
    out[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] - (b[c] - a.position()[c])) :
      b[c];
  return out;
}

// XXX Partial template specialization?
//
inline const Vec<2, int> mirror(
  const Box<2, int> & a, const Vec<2, int> & b, const bool mirror [2]
) {
  Vec<2, int> out;
  for (int c = 0; c < 2; ++c)
    out[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] - 1 - (b[c] - a.position()[c])) :
      b[c];
  return out;
}
inline const Vec<3, int> mirror(
  const Box<3, int> & a, const Vec<3, int> & b, const bool mirror [3]
) {
  Vec<3, int> out;
  for (int c = 0; c < 3; ++c)
    out[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] - 1 - (b[c] - a.position()[c])) :
      b[c];
  return out;
}

template <int C, class T>
inline const Box<C, T> mirror(
  const Box<C, T> & a, const Box<C, T> & b, const bool mirror [C]
) {
  Vec<C, T> tmp;
  for (int c = 0; c < C; ++c)
    tmp[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] -
        (b.position()[c] - a.position()[c] + b.size()[c])) :
      b.position()[c];
  return Box<C, T>(tmp, b.size());
}

// XXX Partial template specialization?
//
inline const Box<2, int> mirror(
  const Box<2, int> & a, const Box<2, int> & b, const bool mirror [2]
) {
  Vec<2, int> tmp;
  for (int c = 0; c < 2; ++c)
    tmp[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] - 1 -
        (b.position()[c] - a.position()[c] + b.size()[c] - 1)) :
      b.position()[c];
  return Box<2, int>(tmp, b.size());
}
inline const Box<3, int> mirror(
  const Box<3, int> & a, const Box<3, int> & b, const bool mirror [3]
) {
  Vec<3, int> tmp;
  for (int c = 0; c < 3; ++c)
    tmp[c] = mirror[c] ?
      (a.position()[c] + a.size()[c] - 1 -
        (b.position()[c] - a.position()[c] + b.size()[c] - 1)) :
      b.position()[c];
  return Box<3, int>(tmp, b.size());
}

template <int C, class T>
inline bool operator == (const Box<C, T> & a, const Box<C, T> & b)
{
  return a.position() == b.position() && a.size() == b.size();
}

template <int C, class T>
inline bool operator != (const Box<C, T> & a, const Box<C, T> & b)
{
  return a.position() == b.position() && a.size() != b.size();
}

template <int C, class T>
inline const StrList deflateStr(const Box<C, T> & in)
{
  return deflateStr(in.position()) + deflateStr(in.size());
}

template <int C, class T>
inline bool inflateStr(StrList & in, Box<C, T> * out)
{
  Vec<C, T> position, size;
  if (! inflateStr(in, &position)) return false;
  if (! inflateStr(in, &size)) return false;
  out->set(position, size);
  return true;
}

}
