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


#include "../Math/psychlops_math.h"
#include "psychlops_g_module.h"
#include "psychlops_g_canvas.h"


namespace Psychlops {
	class DrawableDummy : virtual public Drawable {
	public:
		void NoDrawableError() const { throw new Exception("Canvas-dependent function was called before the instantiation of Canvas."); }
		DrawableDummy() {}
		virtual ~DrawableDummy() {}
		virtual int getWidth() const { NoDrawableError(); return 0; }
		virtual int getHeight() const { NoDrawableError(); return 0; }
		virtual const Point getCenter() const { NoDrawableError(); return Point(); }	//  means this Drawable's local center.

		virtual Drawable& clear(const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& pix(const double x, const double y, const Color &col) { NoDrawableError(); return *this; }

		virtual Drawable& line(const Line &drawee, const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& line(const Line &drawee, const Stroke &strk) { NoDrawableError(); return *this; }
		virtual Drawable& rect(const Rectangle &drawee, const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& rect(const Rectangle &drawee, const Stroke &strk) { NoDrawableError(); return *this; }
		virtual Drawable& ellipse(const Ellipse &drawee, const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& ellipse(const Ellipse &drawee, const Stroke &strk) { NoDrawableError(); return *this; }
		virtual Drawable& polygon(const Polygon &drawee) { NoDrawableError(); return *this; }
		virtual Drawable& polygon(const Polygon &drawee, const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& polygon(const Polygon &drawee, const Stroke &strk) { NoDrawableError(); return *this; }
		virtual Drawable& polyline(const PolyLine &drawee) { NoDrawableError(); return *this; }
		virtual Drawable& polyline(const PolyLine &drawee, const Color &col) { NoDrawableError(); return *this; }
		virtual Drawable& polyline(const PolyLine &drawee, const Stroke &strk) { NoDrawableError(); return *this; }
		virtual Drawable& figures(const Group &drawee) { NoDrawableError(); return *this; }
		virtual Drawable& figures(const Group &drawee, const Color &col) { NoDrawableError(); return *this; }

		virtual Drawable& image(const Image &img) { NoDrawableError(); return *this; }
		virtual Drawable& image(const Image &img, const double x, const double y) { NoDrawableError(); return *this; }
		virtual Drawable& image(Image &img, const Rectangle &target_rect, const Rectangle &source_rect) { NoDrawableError(); return *this; }
		virtual Drawable& image(const Image &img, const double) { NoDrawableError(); return *this; }
		virtual Drawable& letters(Letters &let, const Color &col) { NoDrawableError(); return *this; }
	} drawableDummy;

	const Drawable *Drawable::dummy = &drawableDummy;
	Drawable *Drawable::prime = &drawableDummy;
	DrawableWithCache *DrawableWithCache::prime = 0;
	Group Drawable::billboard;
	const bool Drawable::prime_is_a_canvas() {
		if(prime==dummy) return false;
		if(dynamic_cast<Canvas*>(prime)) return true;
		else return false;
	}

	Drawable::Drawable() {}
	Drawable::~Drawable() {}




/*
	Figure::DATUM_::DATUM_() {
		x.px_ = 0.0;
		y.px_ = 0.0;
		z.px_ = 0.0;
	}

	Figure::DATUM_::LENGTH_::operator double() const {
		return px_;
	}
	Figure::DATUM_::LENGTH_::operator Length() const {
		return Length(px_);
	}
	double Figure::DATUM_::LENGTH_::operator =(double val) {
		px_ = val;
		return val;
	}
	Length Figure::DATUM_::LENGTH_::operator =(Length &val) {
		px_ = val;
		return val;
	}
*/


	Figure::~Figure() {}
	Figure& Figure::join(Group &fg){ fg.append(this); return *this; }

	FigureDatum::FigureDatum() : datum(0,0,0) {}
	FigureDatum::~FigureDatum() {}
	const Point FigureDatum::getDatum() const {
		return datum;
	}
	FigureDatum& FigureDatum::setDatum(const Point& p) {
		datum = p;
		return *this;
	}
	FigureDatum& FigureDatum::centering(const Point & p) {
		datum = p;
		return *this;
	}
/*	FigureDatum& FigureDatum::centering(const Figure& fig) {
		centering(fig.getDatum());
		return *this;
	}
	FigureDatum& FigureDatum::centering(const Drawable& target) {
		centering(target.getCenter());
		return *this;
	}
	FigureDatum& FigureDatum::centering(const double x, const double y, const double z) {
		centering(Point(x,y,z));
		return *this;
	}
	FigureDatum& FigureDatum::shift(const double x, const double y, const double z) {
		centering(datum.x+x, datum.y+y, datum.z+z);
//		centering(datum.x.px_+x, datum.y.px_+y, datum.z.px_+z);
		return *this;
	}
*/
//  see Specific/Graphic/psychlops_g_module_XX.cpp
//	const Figure& Figure::draw(const double x, const double y, const double z) const {
//		return *this;
//	}


	Group::Group() : axis(0,0,1), scaling(1,1,1), rotation(0), clip_type(NONE), alpha_mask(0) {
	}
	Group& Group::append(Figure &fig) {
		contents.push_back(&fig);
		return *this;
	}
	Group& Group::append(Figure *fig) {
		contents.push_back(fig);
		return *this;
	}
	Group& Group::replace(int index, Figure *fig) {
		contents.at(index) = fig;
		return *this;
	}
	Group& Group::remove(int index) {
		if(index>=contents.size()) return *this;
		std::vector<Figure*>::iterator it = contents.begin();
		for(int i=0;i<index; i++) it++;
		contents.erase(it);
		return *this;
	}


	Group& Group::draw(Drawable &drawable) {
		drawable.figures(*this);
		return *this;
	}
/*
	Group& Group::draw(const Color &col, Drawable &drawable) {
		drawable.figures(*this, col);
		return *this;
	}
*/

	Group& Group::clip(bool sw) {
		clip_type = NONE;
		return *this;
	}
	Group& Group::clip(const Rectangle &rect) {
		clip_type = RECT;
		scissor_top = rect.getTop();
		scissor_left = rect.getLeft();
		scissor_width = rect.getWidth();
		scissor_height = rect.getHeight();
		return *this;
	}
	Group& Group::clip(Image *img) {
		clip_type = ALPHA;
		alpha_mask = img;
		return *this;
	}




}	/*	<- namespace Psycholops 	*/


