/*
 *  psychlops_g_module.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2005/10/18 by Kenchi HOSOKAWA
 *  (C) 2005 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_GRAPHIC_MODULE
#define HEADER_PSYCHLOPS_GRAPHIC_MODULE

#include "psychlops_g_fundamental.h"


#include <vector>
#include <list>

namespace Psychlops {


	class Figure;
	class Group;
	class Drawable;



	class Shape;
	class Line;
	class Rectangle;
	class Ellipse; typedef Ellipse Oval;
	class Polygon;
	class PolyLine;
	class Image;
	class Letters;

	class Drawable {
	public:
		static const Drawable *dummy;
		static Drawable *prime;
		static Group billboard;
		static const bool prime_is_a_canvas();

		Drawable();
		virtual ~Drawable() = 0;
		virtual int getWidth() const = 0;
		virtual int getHeight() const = 0;
		virtual const Point getCenter() const = 0;	//  means this Drawable's local center.

		virtual Drawable& clear(const Color &col) = 0;
		virtual Drawable& pix(const double x, const double y, const Color &col) = 0;


		virtual Drawable& line(const Line &drawee, const Color &col) = 0;
		virtual Drawable& line(const Line &drawee, const Stroke &strk) = 0;
		virtual Drawable& rect(const Rectangle &drawee, const Color &col) = 0;
		virtual Drawable& rect(const Rectangle &drawee, const Stroke &strk) = 0;
		//virtual Drawable& rect(const Rectangle[] drawee, const Color &col) = 0;
		//virtual Drawable& rect(const Rectangle[] drawee, const Stroke &strk) = 0;
		virtual Drawable& ellipse(const Ellipse &drawee) = 0;
		virtual Drawable& ellipse(const Ellipse &drawee, const Color &col) = 0;
		virtual Drawable& ellipse(const Ellipse &drawee, const Stroke &strk) = 0;
		virtual Drawable& polygon(const Polygon &drawee) = 0;
		virtual Drawable& polygon(const Polygon &drawee, const Color &col) = 0;
		virtual Drawable& polygon(const Polygon &drawee, const Stroke &strk) = 0;
		virtual Drawable& polyline(const PolyLine &drawee) = 0;
		virtual Drawable& polyline(const PolyLine &drawee, const Color &col) = 0;
		virtual Drawable& polyline(const PolyLine &drawee, const Stroke &strk) = 0;
		virtual Drawable& figures(const Group &drawee) = 0;

		virtual Drawable& image(const Image &img) = 0;
		virtual Drawable& image(Image &img, const Rectangle &target_area, const Rectangle &source_rect) = 0;
		virtual Drawable& image(const Image &img, const double x, const double y) = 0;
			virtual Drawable& image(const Image &img, const double alpha) = 0;
		//virtual Drawable& cacheImage(Image &img, bool on_off) = 0;
		virtual Drawable& letters(Letters &let, const Color &col) = 0;
		//virtual Drawable& letters(const Letters &let, const double x, const double y, const Color &col) = 0;
		//virtual LettersCache cacheLetters(Letters &let) = 0;
	};

	class DrawableWithCache : public Drawable {
	public:
		static DrawableWithCache *prime;
		virtual void cacheImage(Image &img) = 0;
		virtual void uncacheImage(Image &img) = 0;
		virtual void cacheLetters(Letters &let) = 0;
		virtual void uncacheLetters(Letters &let) = 0;
	};

	class Drawable3D : public DrawableWithCache {
	public:
		static Drawable3D *prime;
		virtual void camera() = 0;
		virtual void light() = 0;
	};


	class Figure {
	public:
		virtual ~Figure() = 0;
		virtual const Point getDatum() const = 0;
		virtual Figure& setDatum(const Point &p) = 0;
		virtual Figure& centering(const Point &p) = 0;
		virtual Figure& draw(Drawable &drawable = *Drawable::prime) = 0;
//		virtual const Figure& draw(const double x, const double y, const double z = 0) const;


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

	class FigureDatum : virtual public Figure {
/*		private:
		class DATUM_ {
			friend class Figure;
			private:
			class LENGTH_ {
				friend class Figure;
				friend class Group;
				friend class DATUM_;
				private:
				double px_;
				public:
				operator double() const;
				operator Length() const;
				double operator =(double val);
				Length operator =(Length &val);
			};
			public:
			LENGTH_ x, y, z;
			DATUM_();
			operator Point();
			void operator =(Point &p);
		};
*/
	protected:
		Point datum;

	public:
		using Figure::centering;
		FigureDatum();
		~FigureDatum();
		virtual const Point getDatum() const;
		virtual FigureDatum& setDatum(const Point& p);
		virtual FigureDatum& centering(const Point& p);
		/*
		FigureDatum& centering(const Figure& fig);
		FigureDatum& centering(const Drawable& target = *Drawable::prime);
		FigureDatum& centering(const double x, const double y, const double z = 0);
		FigureDatum& shift(const double x, const double y, const double z = 0);
		*/
	};


	class Group : virtual public FigureDatum {
		friend class Canvas;
	public:
		enum ClippngType { NONE, RECT, STENCIL, ALPHA };
	protected:
		ClippngType clip_type;
		double scissor_top, scissor_left, scissor_width, scissor_height;
		Image *alpha_mask;
	public:
		using FigureDatum::datum;

		std::vector<Figure *> contents;
		double rotation;
		Point axis, scaling;

		Group();
		Group& append(Figure &fig);
		Group& append(Figure *fig);
		Group& replace(int index, Figure *fig);
		Group& remove(int index);
//		inline Figure& operator [](int index) { return *(contents.at(index); }

		virtual Group& draw(Drawable &drawable = *Drawable::prime);

		virtual Group& clip(bool sw);
		virtual Group& clip(const Rectangle &rect);
		virtual Group& clip(Image *img);
	};




}	/*	<- namespace Psycholops 	*/


#endif
