
#ifndef __RECT_H
#define __RECT_H

namespace GUI
{

class point;
class rect;

class size
{
public:
	int cx,cy;
	
	size() : cx(0), cy(0) {}
	size(int _cx, int _cy) : cx(_cx), cy(_cy) {}
	size(point _p);

	bool is_equal(size _s) const { return cx == _s.cy && cy == _s.cy; }
	bool operator==(size _s) const { return is_equal(_s); }
	bool operator!=(size _s) const { return !is_equal(_s); }
	
	size& operator+=(size _s) { cx+=_s.cx; cy+=_s.cy; return *this; }
	size& operator-=(size _s) { cx-=_s.cx; cy-=_s.cy; return *this; }

	size operator+(size _s) const { return size(cx + _s.cx, cy + _s.cy); }
	rect operator+(rect &_r) const;

	size operator-(size _s) const { return size(cx - _s.cx, cy - _s.cy); }
	rect operator-(rect &_r) const;
	size operator-() const { return size(-cx,-cy); }
};

class point
{
public:
	int x,y;

	point() : x(0), y(0) {}
	point(int _x, int _y) : x(_x), y(_y) {}
	point(const point &_p) : x(_p.x), y(_p.y) {}

	void offset(int _x, int _y) { x+=_x; y+=_y; }
	void offset(point _p) { x+=_p.x; y+=_p.y; }
	void offset(size _s) { x+=_s.cx; y+=_s.cy; }

	bool is_equal(point _p) const { return x == _p.y && y == _p.y; }
	bool operator==(point _p) const { return is_equal(_p); }
	bool operator!=(point _p) const { return !is_equal(_p); }
	
	point& operator+=(point _p) { x+=_p.x; y+=_p.y; return *this; }
	point& operator+=(size _s) { x+=_s.cx; y+=_s.cy; return *this; }
	
	point& operator-=(point _p) { x-=_p.x; y-=_p.y; return *this; }
	point& operator-=(size _s) { x-=_s.cx; y-=_s.cy; return *this; }

	point operator+(point _p) const { return point(x + _p.x, y + _p.y); }
	point operator+(size _s) const { return point(x + _s.cx, y + _s.cy); }
	rect  operator+(const rect &_r) const;

	point operator-(point _p) const { return point(x - _p.x, y - _p.y); }
	point operator-(size _s) const { return point(x - _s.cx, y - _s.cy); }
	rect  operator-(const rect &_r) const;
	point operator-() const { return point(-x,-y); }
};

class rect
{
public:
	int left,top,right,bottom;

	rect() : left(0), top(0), right(0), bottom(0) {}
	rect(int _left, int _top, int _right, int _bottom)
		: left(_left), top(_top), right(_right), bottom(_bottom) {}
	rect(const rect &_r) : left(_r.left), top(_r.top), right(_r.right), bottom(_r.right) {}
	rect(point _p, size _s) : left(_p.x), top(_p.y), right(_p.x+_s.cx), bottom(_p.y+_s.cy) {}
	rect(point _p1, point _p2) : left(_p1.x), top(_p1.y), right(_p2.x), bottom(_p2.y) {}

	point& left_top() { return *(reinterpret_cast<point*>(this)); }
	point left_top()const { return point(left,top); }
	point& right_bottom() { return *(reinterpret_cast<point*>(this)+1); }
	point right_bottom() const { return point(right,bottom); }
	
	
	point center() const { return point((right-left)/2,(bottom-top)/2); }

	void normalize() 
	{ 
		if (left > right)  std::swap(left, right);
		if (top  > bottom) std::swap(top, bottom);
	}

	bool pt_in_rect(point _p) const { return left <= _p.x && _p.x < right && top <= _p.y && _p.y < bottom; }
	
	void set_rect(int _x1, int _y1, int _x2, int _y2) 
		{ left=_x1; top=_y1; right=_x2; bottom=_y2; }
	
	void offset_rect(int _x, int _y) { left+=_x; top+=_y; right+=_x; bottom+=_y; }
	void offset_rect(point _p) { offset_rect(_p.x, _p.y); }
	void offset_rect(size _s)  { offset_rect(_s.cx, _s.cy); }

	void move_xy(int _x, int _y) { set_rect(_x,_y,_x+width(),_y+height()); }
	void move_x(int _x) { move_xy(_x, top); }
	void move_y(int _y) { move_xy(left, _y); }
	void move_xy(point _p)   { move_xy(_p.x, _p.y); }
	
	size get_size() const { return size(right-left, bottom-top); }
	int width() const { return right - left; }
	int height() const { return bottom - top; }

	void set_size(GUI::size _s) { right = left + _s.cx;  right = left + _s.cy;  }
	void set_width(int _w) { right = left + _w; }
	void set_height(int _h) { bottom = top + _h; }
	
	bool is_empty() const { return left < right && top < bottom; }
	bool is_equal(const rect &_r) const 
		{ return left == _r.left && top == _r.top && right == _r.right && bottom == _r.bottom; }

	void set_emtpy() { left=right=top=bottom=0; }

	bool intersect_rect(const rect &_r1, const rect &_r2)
	{
		left = std::max(_r1.left, _r2.left);
		right = std::min(_r1.right, _r2.right);
		top = std::max(_r1.top, _r2.top);
		bottom = std::min(_r1.bottom, _r2.bottom);
		
		return is_empty();		
	}

	bool union_rect(const rect &_r1, const rect &_r2)
	{
		left = std::min(_r1.left, _r2.left);
		right = std::max(_r1.right, _r2.right);
		top = std::min(_r1.top, _r2.top);
		bottom = std::max(_r1.bottom, _r2.bottom);
		
		return is_empty();
	}

	bool subtract_rect(const rect &_r1, const rect &_r2);

	void inflate_rect(int _l, int _t, int _r, int _b)
	{
		left -= _l; right += _r;
		top -= _t; bottom += _b;
	}
	void inflate_rect(int _x, int _y) { inflate_rect(_x,_y,_x,_y); }
	void inflate_rect(GUI::size _s) { inflate_rect(_s.cx, _s.cy, _s.cx, _s.cy); }
	void inflate_rect(const rect &_r) { inflate_rect(_r.left, _r.top, _r.right, _r.bottom); }

	void deflate_rect(int _l, int _t, int _r, int _b)
	{
		left += _l; right -= _r;
		top += _t; bottom -= _b;
	}
	void deflate_rect(int _x, int _y) { deflate_rect(_x,_y,_x,_y); }
	void deflate_rect(GUI::size _s) { deflate_rect(_s.cx, _s.cy, _s.cx, _s.cy); }
	void deflate_rect(const rect &_r) { deflate_rect(_r.left, _r.top, _r.right, _r.bottom); }

	rect operator+(point _p) const { rect r(*this); r.offset_rect(_p);  return r; }
	rect operator+(GUI::size _s)  const { rect r(*this); r.offset_rect(_s);  return r; }
	rect operator+(const rect &_r) const { rect r(*this); r.inflate_rect(_r); return r; }

	rect operator-(point _p) const { rect r(*this); r.offset_rect(-_p); return r; }	
	rect operator-(GUI::size _s)  const { rect r(*this); r.offset_rect(-_s); return r; }
	rect operator-(const rect &_r) const { rect r(*this); r.deflate_rect(_r); return r; }

	rect& operator+=(point _p) { offset_rect(_p); return *this; }
	rect& operator+=(GUI::size _s)  { offset_rect(_s); return *this; }
	rect& operator+=(const rect &_r) { inflate_rect(_r); return *this; }   
	
	rect& operator-=(point _p) { offset_rect(-_p); return *this; }
	rect& operator-=(GUI::size _s)  { offset_rect(-_s); return *this; }
	rect& operator-=(const rect &_r) { deflate_rect(_r); return *this; } 
	
	bool operator==(const rect &_r) const { return is_equal(_r); }
	bool operator!=(const rect &_r) const { return !is_equal(_r); }
	
	rect operator&(const rect &_r) const { rect r; r.intersect_rect(*this, _r); return *this; }	
	rect operator|(const rect &_r) const { rect r; r.union_rect(*this, _r); return *this; }	

	void operator&=(const rect &_r) { rect r; intersect_rect(*this, _r); }	
	void operator|=(const rect &_r) { rect r; union_rect(*this, _r); }	

	//rect &operator=(const rect &_r) { set_rect(_r); return *this; }
};

inline size::size(point _p) : cx(_p.x), cy(_p.y) {}
inline rect size::operator+(rect &_r) const { return _r+(*this); }
inline rect size::operator-(rect &_r) const { return _r-(*this); }	
inline rect point::operator+(const rect &_r) const { return _r+(*this); }
inline rect point::operator-(const rect &_r) const { return _r-(*this); }	

};

#endif //__RECT_H
