/*
 *  psychlops_g_shape.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2006/01/04 by Kenchi HOSOKAWA
 *  (C) 2006 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_GRAPHIC_SHAPE
#define HEADER_PSYCHLOPS_GRAPHIC_SHAPE


#include "psychlops_g_fundamental.h"
#include "psychlops_g_color.h"
#include "psychlops_g_module.h"

#include <deque>
#include <list>


namespace Psychlops {


	struct Stroke {
	public:
		enum Pattern { SOLID=0xFFFF, DASHED=0x0F0F, DOTTED=0xAAAA };

		Color color;
		double width;
		unsigned short pattern;

		Stroke();
		Stroke(const Color col, const double wid, const Pattern pat);
		Stroke& set(const Color col, const double wid, const Pattern pat);

		static const Stroke null_line;
		static const Stroke hair_line;
	};


	class Shape : virtual public Figure {
	public:
		Color fill;
		Stroke stroke;
		Shape();

		virtual Shape& draw_base(Drawable &target);
#if !defined(_MSC_VER)
		virtual Shape& draw(Drawable &target = *Drawable::prime);
#endif
		virtual Shape& draw(const Color &col, Drawable &target = *Drawable::prime) = 0;
		virtual Shape& draw(const Stroke &strk, Drawable &target = *Drawable::prime) = 0;

		using Figure::centering;
		inline Shape& centering(const Figure& fig) { centering(fig.getDatum()); return *this; }
		inline Shape& centering(const Drawable &target = *Drawable::prime) { centering(target.getCenter()); return *this; }
		inline Shape& centering(const double x, const double y, const double z = 0) { centering(Point(x,y,z)); return *this; }
		inline Shape& shift(const double x, const double y, const double z = 0) { Point n=getDatum(); n=n+Point(x,y,z); setDatum(n); return *this; }

/*
		template<class T> class Colored : public T {
		public:
			Color color;
			Stroke stroke;
			Colored<T>() : T(), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1> Colored<T>(T1 a1) : T(a1), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1, typename T2> Colored<T>(T1 a1, T2 a2) : T(a1, a2), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1, typename T2, typename T3> Colored<T>(T1 a1, T2 a2, T3 a3) : T(a1, a2, a3), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1, typename T2, typename T3, typename T4> Colored<T>(T1 a1, T2 a2, T3 a3, T4 a4) : T(a1, a2, a3, a4), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1, typename T2, typename T3, typename T4, typename T5> Colored<T>(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) : T(a1, a2, a3, a4, a5), color(Color::null_color), stroke(Stroke::null_line) {}
			template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Colored<T>(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) : T(a1, a2, a3, a4, a5, a6), color(Color::null_color), stroke(Stroke::null_line) {}
			//using T::draw;
			virtual Colored<T>& draw(Drawable &target = *Drawable::prime) {
				if(color.getA()!=0) T::draw(color, target);
				if(stroke.width!=0) T::draw(stroke, target);
				return *this;
			}
			virtual Colored<T>& draw(const Color &col, Drawable &target = *Drawable::prime) { T::draw(col, target); return *this; }
			virtual Colored<T>& draw(const Stroke &strk, Drawable &target = *Drawable::prime) { T::draw(strk, target); return *this; }
		};
 */
	};




	class Rectangle : virtual public Shape {
		friend class Point;
		friend class Canvas;
		friend class Image;

	protected:
		double left;
		double top;
		double right;
		double bottom;

	protected:
		template <typename X> inline void correctInversion(X &l, X &t, X &r, X &b);
		void setbypix(double l, double t, double r, double b);
		void setbypix(double width, double height);
		void set(double size);

	public:
		Rectangle();
		Rectangle(double l, double t, double r, double b);
		Rectangle(double width, double height);
		//Rectangle(double width, double height);
		//Rectangle(double width, double height, double hcentre, double vcentre);
		Rectangle& set(const Rectangle &r);
		Rectangle& set(const Point &po1, const Point &po2);
		Rectangle& set(double l, double t, double r, double b);
		Rectangle& set(double width, double height);
		Rectangle dup();
		Rectangle& resize(double width, double height);
		Rectangle& locate(const Point &p);
		Rectangle& locate(double x, double y);

		virtual Rectangle& setDatum(const Point &po);
		virtual Rectangle& centering(const Drawable& target = *Drawable::prime);
		virtual Rectangle& centering(const Figure& fig);
		virtual Rectangle& centering(const Point &po);
		virtual Rectangle& centering(const double x, const double y, const double z = 0.0);
		virtual Rectangle& move_to(const double x, const double y, const double z = 0.0);
		virtual Rectangle& shift(const double h, const double v, const double d = 0.0);
		Rectangle& alignLeft(const double lef);
		Rectangle& alignTop(const double to_);
		Rectangle& alignRight(const double rig);
		Rectangle& alignBottom(const double bot);

		void clipped_by(const Rectangle &source);
		void clip(Rectangle &target);
		// obsolete: misspelled
		void cripped(const Rectangle &source);
		void crip(Rectangle &target);
		bool include(double x, double y) const;
		bool include(const Point &p) const;
		bool include(const Rectangle &rect) const;

		void setColor(Color col);
		virtual Rectangle& draw(Drawable &target = *Drawable::prime);
		virtual Rectangle& draw(const Color &col, Drawable &target = *Drawable::prime);
		virtual Rectangle& draw(const Stroke &strk, Drawable &target = *Drawable::prime);
		// obsolete
		Rectangle& display();
		Rectangle& display(const Color &col);


		double getWidth() const;
		double getHeight() const;
		virtual const Point getDatum() const;
		const Point getCenter() const;
		double getHcenter() const;
		double getVcenter() const;
		double getTop() const;
		double getLeft() const;
		double getBottom() const;
		double getRight() const;
	};


	class Line : virtual public Shape, virtual public FigureDatum {
	public:
		using FigureDatum::datum;
		Point end;
		Point getEnd() const;

		Line();
		Line(const double x1, const double y1, const double x2, const double y2);
		Line(const Point &dbegin, const Point &dend);
		Line& set(const double x1, const double y1, const double x2, const double y2);
		Line& set(const Point &dbegin, const Point &dend);

		virtual Line& setDatum(const Point &p);
		virtual Line& centering(const Point &p);
		virtual Line& draw(Drawable &target = *Drawable::prime);
		virtual Line& draw(const Color &col, Drawable &target = *Drawable::prime);
		virtual Line& draw(const Stroke &strk, Drawable &target = *Drawable::prime);

		using Shape::centering;
	};

	class Ellipse;
	typedef Ellipse Oval;
	class Ellipse : virtual public Shape, virtual public FigureDatum {
	public:
		using FigureDatum::datum;
		double radius, v_radius;
	public:
		Ellipse();
		Ellipse(const double d_radius, const double d_v_radius = -1, const Point& d_datum = Point());
		Ellipse(const Rectangle& rect);
		virtual ~Ellipse();
		Ellipse& set(const double d_radius, const double d_v_radius = -1, const Point& d_datum = Point());
		Ellipse& set(const Rectangle& rect);
		virtual Ellipse& centering(const Point &p);
		virtual Ellipse& draw(Drawable &target = *Drawable::prime);
		virtual Ellipse& draw(const Color &col, Drawable &target = *Drawable::prime);
		virtual Ellipse& draw(const Stroke &strk, Drawable &target = *Drawable::prime);

		using Shape::centering;
	};

	class Polygon : virtual public Shape, virtual public FigureDatum {
		friend class Canvas;
		struct Vertex { Point point; };
	protected:
	public:
		std::deque<Point> vertices;
		using FigureDatum::datum;

		bool empty() const;

		Polygon();

		Polygon& append(const Point& p);
		Polygon& append(const double x, const double y, const double z = 0.0);
//		Polygon& append(const Point& p, const Color& col);
//		Polygon& append(const double x, const double y, const double z, const Color& col);
//		Polygon& append(const double x, const double y, const Color& col);

		virtual Polygon& centering(const Point &p);
		virtual Polygon& draw(Drawable &target = *Drawable::prime);
		virtual Polygon& draw(const Color& col, Drawable &target = *Drawable::prime);
		virtual Polygon& draw(const Stroke& strk, Drawable &target = *Drawable::prime);

		using Shape::centering;
	};

	class PolyLine : virtual public Shape, virtual public FigureDatum {
		friend class Canvas;
		struct Vertex { Point point; };
	protected:
	public:
		std::deque<Point> vertices;
		using FigureDatum::datum;
		bool empty() const;
		PolyLine();
		PolyLine& append(const Point& p);
		PolyLine& append(const double x, const double y, const double z = 0.0);
		virtual PolyLine& centering(const Point &p);
		virtual PolyLine& draw(Drawable &target = *Drawable::prime);
		virtual PolyLine& draw(const Color& col, Drawable &target = *Drawable::prime);
		virtual PolyLine& draw(const Stroke& strk, Drawable &target = *Drawable::prime);

		using Shape::centering;
	};



}	/*	<- namespace Psycholops 	*/


#endif
