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

#ifndef DJ_BOX_H
#define DJ_BOX_H
#include <djVec.h>

namespace dj {

// Generic box base.
//
template <int C, class T>
class _Box {
public:

  _Box() {}
  _Box(const Vec<C, T> & size) : _size(size) {}
  _Box(const Vec<C, T> & position, const Vec<C, T> & size) :
    _position(position), _size(size)
  {}
  
  // Set.
  //
  void set(const Vec<C, T> & size);
  void set(const Vec<C, T> & position, const Vec<C, T> & size);
  void zero();
  
  // Position and size.
  //
  void position(const Vec<C, T> &);
  const Vec<C, T> & position() const { return _position; }
  void size(const Vec<C, T> &);
  const Vec<C, T> & size() const { return _size; }
  
  // Corners.
  //
  void p0(const Vec<C, T> &);
  const Vec<C, T> p0() const { return _position; }
  void p1(const Vec<C, T> &);
  const Vec<C, T> p1() const { return _position + toVec(_size); }

private:

  Vec<C, T> _position, _size;
};
template <int C, class T>
class Box : public _Box<C, T> {};

// Two-dimensional box base.
//
template <class T>
class Box<2, T> : public _Box<2, T> {
public:

  Box() {}
  Box(const Vec<2, T> & size) : _Box<2, T>(size) {}
  Box(const T & width, const T & height) :
    _Box<2, T>(Vec<2, T>(width, height))
  {}
  Box(const Vec<2, T> & position, const Vec<2, T> & size) :
    _Box<2, T>(position, size)
  {}
  Box(const T & x, const T & y, const T & width, const T & height) :
    _Box<2, T>(Vec<2, T>(x, y), Vec<2, T>(width, height))
  {}
  
  // Position and size.
  //
  const T & x() const { return _Box<2, T>::position().x(); }
  const T & y() const { return _Box<2, T>::position().y(); }
  const T & width() const { return _Box<2, T>::size().x(); }
  const T & height() const { return _Box<2, T>::size().y(); }

  // Corners.
  //
  const T x0() const { return _Box<2, T>::p0().x(); }
  const T y0() const { return _Box<2, T>::p0().y(); }
  const T x1() const { return _Box<2, T>::p1().x(); }
  const T y1() const { return _Box<2, T>::p1().y(); }
};

// Three-dimensional box base.
//
template <class T>
class Box<3, T> : public _Box<3, T> {
public:

  Box() {}
  Box(const Vec<3, T> & size) : _Box<3, T>(size) {}
  Box(const T & width, const T & height, const T & depth) :
    _Box<3, T>(Vec<3, T>(width, height, depth))
  {}
  Box(const Vec<3, T> & position, const Vec<3, T> & size) :
    _Box<3, T>(position, size)
  {}
  Box(
    const T & x, const T & y, const T & z,
    const T & width, const T & height, const T & depth
  ) :
    _Box<3, T>(Vec<3, T>(x, y, z), Vec<3, T>(width, height, depth))
  {}
  
  // Position and size.
  //
  const T & x() const { return _Box<3, T>::position().x(); }
  const T & y() const { return _Box<3, T>::position().y(); }
  const T & z() const { return _Box<3, T>::position().z(); }
  const T & width() const { return _Box<3, T>::size().x(); }
  const T & height() const { return _Box<3, T>::size().y(); }
  const T & depth() const { return _Box<3, T>::size().z(); }

  // Corners.
  //
  const T x0() const { return _Box<2, T>::p0().x(); }
  const T y0() const { return _Box<2, T>::p0().y(); }
  const T z0() const { return _Box<2, T>::p0().z(); }
  const T x1() const { return _Box<2, T>::p1().x(); }
  const T y1() const { return _Box<2, T>::p1().y(); }
  const T z1() const { return _Box<2, T>::p1().z(); }
};

// Box types.
//
typedef Box<2, int> Box2i;
typedef Box<2, double> Box2f;
typedef Box<3, int> Box3i;
typedef Box<3, double> Box3f;

// Transforms.
//
template <int C, class T>
const Box<C, T> operator + (const Box<C, T> &, const Vec<C, T> &);
template <int C, class T>
const Box<C, T> operator - (const Box<C, T> &, const Vec<C, T> &);

// Functions.
//
template <int C, class T>
bool intersect(const Box<C, T> &, const Vec<C, T> &);
template <int C, class T>
const Box<C, T> intersect(const Box<C, T> &, const Box<C, T> &);
template <int C, class T>
const Box<C, T> bound(const Box<C, T> &, const Box<C, T> &);
template <int C, class T>
const Box<C, T> expand(const Box<C, T> &, const Vec<C, T> &);

template <int C, class T> bool areaIsValid(const Box<C, T> &);

template <int C, class T> const Box<C, T> swap(const Box<C, T> &);

template <int C, class T>
const Vec<C, T> mirror(
  const Box<C, T> &, const Vec<C, T> &, const bool [C]
);
template <int C, class T>
const Box<C, T> mirror(
  const Box<C, T> &, const Box<C, T> &, const bool [C]
);

// Comparison.
//
template <int C, class T>
bool operator == (const Box<C, T> &, const Box<C, T> &);
template <int C, class T>
bool operator != (const Box<C, T> &, const Box<C, T> &);

// Serialize.
//
template <int C, class T>
const StrList deflateStr(const Box<C, T> &);
template <int C, class T>
bool inflateStr(StrList &, Box<C, T> *);

}

#include <djBox_.h>
#include <djBoxFnc_.h>
#endif
