#ifndef BOX_H
# define BOX_H

# ifndef V2_H
#  include "v2.h"
# endif
# ifndef LTRANS_H
#  include "ltrans.h"
# endif
# ifndef LINE_H
#  include "line.h"
# endif

class geo_shape	{
	public:
	virtual double area() C = 0;
	virtual vector2 center() C = 0;
	virtual box outsidebox() C = 0;
	virtual box insidebox() C = 0;
	virtual BOOL encloses(C vector2& pos) C = 0;
	virtual BOOL ok() C = 0;
	virtual C vector_space *space() C = 0;
	virtual ~geo_shape() {;};
	};

class box : public geo_shape	{
	double xl, xh, yl, yh;
	C vector_space *sp;

	public:

	~box() {}
	box() :	xl(0), xh(-1), yl(0), yh(-1), sp(&vector_space::bad)	{}
	box(double x1, double y1, double x2, double y2, BOOL sort=TRUE);
	box(double x1, double y1, double x2, double y2, C vector_space *v,
			BOOL sort=TRUE);
	box(C vector2& c00, C vector2& c11, BOOL sort=TRUE);
	box(C box& a)
		: geo_shape(), xl(a.xl), xh(a.xh), yl(a.yl), yh(a.yh), sp(a.sp)
		{}
	box& operator=(C box& a) {xl=a.xl; xh=a.xh; yl=a.yl; yh=a.yh;
					sp=a.sp; return *this;}

	vector2 c00() C	{return vector2(xl, yl, sp);}
	vector2 c01() C	{return vector2(xl, yh, sp);}
	vector2 c10() C	{return vector2(xh, yl, sp);}
	vector2 c11() C	{return vector2(xh, yh, sp);}
	vector2 c(int which_corner) C;
	vector2 size() C	{return vector2(xh-xl, yh-yl, sp);}
	vector2 center() C	{return vector2(0.5*(xl+xh), 0.5*(yl+yh), sp);}
	double area() C	{return (xh-xl)*(yh-yl);}
	line s0() C	{return s(0);}
	line s1() C	{return s(1);}
	line s2() C	{return s(2);}
	line s3() C	{return s(3);}
	line s(int which_side) C;

	box outsidebox() C	{return *this;}
	box insidebox() C	{return *this;}
	BOOL encloses(C vector2& pos) C;
	BOOL encloses(C box& pos) C;

	C static box unitbox;
	BOOL is_good() C	{return xl<=xh && yl<=yh;}
	BOOL ok() C	{return vector_space::vsok(sp);}
	C vector_space *space() C {return sp;}
	};

box intersect(C box& a, C box& b);
box operator+(C box& a, C vector2& shift);
inline box operator-(C box& a, C vector2& shift)	{return a+(-shift);}
inline box operator+(C vector2& shift, C box& a)	{return a+shift;}
ostream& operator<<(ostream&, C box&);


class parallelogram : public geo_shape	{
	ltransform a;

	public:

	~parallelogram();
	parallelogram() : a() {}
	parallelogram(C box& x);
	parallelogram(C ltransform& b, C box& x);
	parallelogram(C parallelogram& i) : geo_shape(), a(i.a) {}
	parallelogram& operator=(C parallelogram& i) {a=i.a; return *this;}

	vector2 c00() C	{return a(box::unitbox.c00());}
	vector2 c01() C	{return a(box::unitbox.c01());}
	vector2 c10() C	{return a(box::unitbox.c10());}
	vector2 c11() C	{return a(box::unitbox.c11());}
	vector2 c(int which_corner) C;
	inline vector2 center() C	{return a(box::unitbox.center());}
	line s0() C	{return s(0);}
	line s1() C	{return s(1);}
	line s2() C	{return s(2);}
	line s3() C	{return s(3);}
	line s(int which_side) C;

	double area() C	{return a.Wronskian();}
	box outsidebox() C;
	box insidebox() C;
	BOOL encloses(C vector2& pos) C;
	BOOL encloses(C box& pos) C;
	BOOL encloses(C parallelogram& pos) C;
	C ltransform& Transform() C	{return a;}

	friend parallelogram operator*(C ltransform& a, C parallelogram& b);
	friend parallelogram operator+(C parallelogram& a, C vector2& shift);
	BOOL ok() C	{return a.ok();}
	C vector_space *space() C	{return a.Shift().space();}
	};

parallelogram operator*(C ltransform& a, C parallelogram& b);
parallelogram operator*(C ltransform& a, C box& b);
parallelogram operator+(C parallelogram& a, C vector2& shift);
inline parallelogram operator-(C parallelogram& a, C vector2& shift)
	{return a+(-shift);}
inline parallelogram operator+(C vector2& shift, C parallelogram& a)
	{return a+shift;}
box inverse_image(C box& db1, C ltransform& fwd);

#endif
