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

#include "psychlops_figure_standard.h"
#include <string.h>


namespace Psychlops {
namespace Figures {



	////////	Arrow	////////
	Polygon Arrow::default_head;

	void Arrow::createDefaultHead() {
		default_head.append(Point(0,0));
		default_head.append(Point( 5,20));
		default_head.append(Point(-5,20));
	}
	void Arrow::setDefaultHead() {
		if(default_head.empty()) createDefaultHead();
		if(head==0) head = &default_head;
		gr.append(head);
	}

	Arrow::Arrow() : Line(), head(0) {
		setDefaultHead();
	}
	Arrow::Arrow(const double x1, const double y1, const double x2, const double y2) : Line(x1, y1, x2, y2), head(0) {
		setDefaultHead();
	}
	Arrow::Arrow(const Point &dbegin, const Point &dvec) : Line(dbegin, dvec), head(0) {
		setDefaultHead();
	}
	Arrow& Arrow::set(const double x1, const double y1, const double x2, const double y2) {
		Point b(x1, y1), e(x2, y2);
		return set(b, e);
	}
	Arrow& Arrow::set(const Point &dbegin, const Point &dend) {
		datum = dbegin, end = dend;
		setDefaultHead();
		return *this;
	}

	Arrow& Arrow::draw(Drawable& target) {
		Shape::draw_base(target);
		return *this;
	}
	Arrow& Arrow::draw(const Color &col, Drawable& target) {
		target.line(*this, col);
		gr.centering(this->end);
		Point vec = this->end-this->datum;
		gr.rotation = 180-atan2(vec.x, vec.y)/2.0/PI*360;
		head->fill = col;
		head->stroke = Stroke::null_line;
		target.figures(gr);
		return *this;
	}
	Arrow& Arrow::draw(const Stroke &strk, Drawable& target) {
		target.line(*this, strk);
		gr.centering(this->end);
		Point vec = this->end-this->datum;
		gr.rotation = 180-atan2(vec.x, vec.y)/2.0/PI*360;
		head->fill = strk.color;
		head->stroke = Stroke::null_line;
		target.figures(gr);
		return *this;
	}



	////////	Cross	////////
	Cross::Cross() { stroke = Stroke::hair_line; }
	Cross::Cross(const Rectangle& rect, Stroke dstrk) {
		set(rect, dstrk);
	}
	Cross::Cross(double wid, double hei, Stroke dstrk) {
		set(wid, hei, dstrk);
	}
	Cross::~Cross() {}
	Cross& Cross::set(const Rectangle& rect, Stroke dstrk) {
		width = rect.getWidth();
		height = rect.getHeight();
		stroke = dstrk;
		return *this;
	}
	Cross& Cross::set(double wid, double hei, Stroke dstrk) {
		width = wid;
		height = hei;
		stroke = dstrk;
		return *this;
	}
	Cross& Cross::centering() {
		if(Drawable::prime!=0) {
			centering(Drawable::prime->getCenter());
		}
		return *this;
	}
	Cross& Cross::centering(const Point &p) {
		datum = p;
		return *this;
	}
	Cross& Cross::draw(Drawable &target) {
		draw(stroke, target);
		return *this;
	}
	Cross& Cross::draw(const Color &col, Drawable &target) {
		Line lx(datum.x - width/2, datum.y, datum.x + width/2, datum.y);
		Line ly(datum.x, datum.y - height/2, datum.x, datum.y + height/2);
		target.line(lx, col);
		target.line(ly, col);
		return *this;
	}
	Cross& Cross::draw(const Stroke &strk, Drawable &target) {
		Line lx(datum.x - width/2, datum.y, datum.x + width/2, datum.y);
		Line ly(datum.x, datum.y - height/2, datum.x, datum.y + height/2);
		target.line(lx, strk);
		target.line(ly, strk);
		return *this;
	}




	Movie::Movie()
	{
		current_frame = 0;
	}
	Movie::~Movie()
	{
		clear();
	}

	Movie & Movie::clear()
	{
		for(int i=0; i<frame.size(); i++)
		{
			delete frame[i];
		}
		return *this;
	}
	Movie & Movie::setFrameNumber(int frame_num)
	{
		clear();
		frame.resize(frame_num);
		for(int i=0; i<frame.size(); i++)
		{
			frame[i] = new Image();
		}
		return *this;
	}
	Movie & Movie::set(Image* frames, int frame_num)
	{
		setFrameNumber(frame_num);
		for(int i=0; i<frame_num; i++)
		{
			frame[i]->from(frames[i]);
		}
		return *this;
	}

	Image& Movie::operator[](int frame_num)
	{
		return *frame[frame_num];
	}
	int Movie::getCurrentFrame()
	{
		return current_frame;
	}
	int Movie::setCurrentFrame(int new_current)
	{
		return current_frame = new_current;
	}


	Movie& Movie::draw(Drawable& target)
	{
		current_frame %= frame.size();
		//frame[current_frame]->move_to(this->getDatum().x, this->getDatum().y);
		frame[current_frame]->draw(target);
		current_frame++;
		return *this;
	}

	Movie& Movie::capture()
	{
		capture(source);
		return *this;
	}
	Movie& Movie::capture(const Rectangle &source_area_)
	{
		Image *img = new Image();
		frame.push_back(img);
		if(Drawable::prime_is_a_canvas())
		{
			Canvas *a = dynamic_cast<Canvas *>(Drawable::prime);
			a->to(*img, source_area_);
		}
		return *this;
	}
	Movie& Movie::capture(int target_frame)
	{
		capture(source, target_frame);
		return *this;
	}
	Movie& Movie::capture(const Rectangle &source_area_, int target_frame)
	{
		if(Drawable::prime_is_a_canvas())
		{
			dynamic_cast<Canvas *>(Drawable::prime)->to(*(frame[target_frame]), source_area_);
		}
		return *this;
	}
	const Movie& Movie::saveEachFrames(const std::string filePrefix)
	{
		char buf[256];
		for(int i=0; i<frame.size(); i++) {
			memset(buf, 0, 256);
			sprintf(buf, "%u", i);
			frame[i]->save(filePrefix+"_"+buf+".png");
		}
		clear();
		return *this;
	}

}
}	/*	<- namespace Psycholops 	*/


