/*
* box.h
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/

#ifndef __box
#define __box

#include <algorithm>

struct edge {
	enum {NONE=-1, BOTTOM, RIGHT, TOP, LEFT}; 
};

template <typename T> struct box {

  T left, bottom;
  T right, top;
  T width, height;
  T midx, midy;

  double width_1, height_1;

  box () {
    left = bottom = right = top = width = height = midx = midy = 0;
    width_1 = height_1 = 0.0;
  }

  box (T l, T b, T r, T t) { operator() (l, b, r, t); }

  inline void operator() (T l, T b, T r, T t) {
    left = l;
    bottom = b;
    right = r;
    top = t;
    calc ();
  }

  inline bool operator== (const box<T>& b1) {
    return (left == b1.left && right == b1.right && bottom == b1.bottom && top == b1.top);
  }

  inline int calc () {

		int ret = 0;

    if (left > right) {
			std::swap (left, right);
			ret = 1;
		}

    if (bottom > top) {
			std::swap (bottom, top);
			ret = 1;
		}

    width = right - left;
    height = top - bottom;

    midx = (T) ((left + right) / 2.0);
    midy = (T) ((bottom + top) / 2.0);

    if (width != 0) width_1 = 1.0 / width;
    if (height != 0) height_1 = 1.0 / height;

		return ret;

  }

  inline void move (T dx, T dy) {
    left += dx;
    right += dx;
    bottom += dy;
    top += dy;
    calc ();
  }

  inline void resize (T dx, T dy) {
    right += dx;
    left -= dx;
    top += dy;
    bottom -= dy;
    calc ();
  }

  inline void lower_corner (T x, T y) {
    left = x;
    bottom = y;
    right = left + width;
    top = bottom + height;
    calc ();
  }

  int within_delta (T u, T v, T d2) {
    T vu = v - u;
		T vu2 = vu * vu;
		if (vu2 > d2) return 0; else return 1;
  }

  inline int get_edge_hit (T x, T y, T d2) {
		if (within_delta (top, y, d2)) return edge::TOP; else
		if (within_delta (bottom, y, d2)) return edge::BOTTOM; else
		if (within_delta (left, x, d2)) return edge::LEFT; else
		if (within_delta (right, x, d2)) return edge::RIGHT; else 
		return edge::NONE;
  }

  inline void set_edge (int e, T x, T y) {
		if (e == edge::LEFT) {
			if (x < right) left = x;
		} else if (e == edge::RIGHT) {
			if (x > left) right = x;
		} else if (e == edge::BOTTOM) {
			if (y < top) bottom = y;
		} else if (e == edge::TOP) {
			if (y > bottom) top = y;
		} else return;
    calc ();
  }

};

template <typename T> inline bool inbox (const box<T>& b, T x, T y) {
  return ((x >= b.left) && (x <= b.right) && (y >= b.bottom) && (y <= b.top));
}

#endif
