/*
 *  psychlops_figure_visualization.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2009/10/05 by Kenchi HOSOKAWA
 *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */

#include "psychlops_figure_visualization.h"


namespace Psychlops {
namespace Figures {

	XYPlot::XYPlot() : x_max(0), x_min(0), y_max(0), y_min(0) { fill=Color(.2,.2,.6,.35); stroke=Stroke(Color::white, 3, Stroke::SOLID); }
	XYPlot::XYPlot(double wid, double hei) : Rectangle(wid, hei), x_max(wid/2), x_min(-wid/2), y_max(hei/2), y_min(-hei/2) { fill=Color(.2,.2,.6,.35); stroke=Stroke(Color::white, 3, Stroke::SOLID); }
	XYPlot::XYPlot(double wid, double hei, Interval x_a, Interval y_a) : Rectangle(wid, hei), x_max(x_a.end.value), x_min(x_a.begin.value), y_max(y_a.end.value), y_min(y_a.begin.value) { fill=Color(.2,.2,.6,.35); stroke=Stroke(Color::white, 3, Stroke::SOLID); }
	XYPlot& XYPlot::set(double wid, double hei) {
		x_max = wid/2;
		x_min = -wid/2;
		y_max = hei/2;
		y_min = -hei/2;
		Rectangle::set(wid, hei);
		return *this;
	}
	XYPlot& XYPlot::set(double wid, double hei, Interval x_a, Interval y_a) {
		x_max = x_a.end.value;
		x_min = y_a.begin.value;
		y_max = x_a.end.value;
		y_min = y_a.begin.value;
		Rectangle::set(wid, hei);
		return *this;
	}
	XYPlot& XYPlot::setInterval(Interval x_a, Interval y_a) {
		x_max = x_a.end.value;
		x_min = y_a.begin.value;
		y_max = x_a.end.value;
		y_min = y_a.begin.value;
		return *this;
	}
	double XYPlot::Xpix(double x) {
		return left + (x-x_min) * getWidth()/(x_max-x_min);
	}
	double XYPlot::Ypix(double y) {
		return bottom + (y-y_min) * getHeight()/(y_min-y_max);
	}
	const Color default_cols[6] = { Color::green, Color::red, Color::blue, Color::magenta, Color::cyan, Color::yellow };

	FunctionalPlot::FunctionalPlot() : XYPlot() { }
	FunctionalPlot::FunctionalPlot(double wid, double hei) : XYPlot(wid, hei) { }
	FunctionalPlot& FunctionalPlot::set(double wid, double hei) {
		XYPlot::set(wid, hei);
		return *this;
	}
	FunctionalPlot& FunctionalPlot::draw(Drawable &target) {
		target.rect(*this, fill);
		target.rect(*this, stroke);
		if(functions.size()<1) return *this;
		Line elem;
		const double x_delta = (x_max-x_min)/getWidth();
		int pix_x;
		if(x_max>0 && x_min<0) target.line(elem.set(Xpix(0), top, Xpix(0), bottom), Color(1,1,1,0.5));
		if(y_max>0 && y_min<0) target.line(elem.set(left, Ypix(0), right, Ypix(0)), Color(1,1,1,0.5));
		for(int i=0; i<functions.size(); i++) {
			pix_x = getLeft();
			for(double x=x_min; x<x_max; x+=x_delta) {
				pix_x++;
				elem.set( pix_x   , Ypix(functions[i](x)),
						 (pix_x+1), Ypix(functions[i](x+x_delta)));
				target.line(elem, (i<6) ? default_cols[i] : Color::green);
			}
		}
		return *this;
	}
	FunctionalPlot& FunctionalPlot::append(OneDimFun fun) {
		functions.push_back(fun);
		return *this;
	}


	LinePlot::LinePlot() : XYPlot() { }
	LinePlot::LinePlot(double wid, double hei) : XYPlot(wid, hei) { }
	void LinePlot::setTableSize(int n_seq, int n_elems) {
		table.resize(n_seq);
		for(int i=0; i<n_seq; ++i) table[i].resize(n_elems, 0);
	}
	LinePlot& LinePlot::set(double wid, double hei) {
		XYPlot::set(wid, hei);
		return *this;
	}
	void LinePlot::push_pop(double x, int seq_index) { table[seq_index].push_back(x); table[seq_index].pop_front(); }
	LinePlot& LinePlot::draw(Drawable &target) {
		target.rect(*this, fill);
		target.rect(*this, stroke);
		const double x_delta = (x_max-x_min)/getWidth();
		/*
		Line elem;
		for(int j=0; j<table.size(); j++) {
			for(int i=1; i<table[j].size(); i++) {
				elem.set(    i*2.0,  Ypix(table[j][i-1]),
						 (i+1)*2.0,  Ypix(table[j][i]));
				target.line(elem, (j<6) ? default_cols[j] : Color::green);
			}
		}
		*/
		PolyLine elem;
		for(int j=0; j<table.size(); j++) {
			elem.vertices.clear();
			for(int i=0; i<table[j].size(); i++) {
				elem.append(i, Ypix(table[j][i]));
			}
			target.polyline(elem, (j<6) ? default_cols[j] : Color::green);
		}
		return *this;
	}


}	/*	<- namespace Figure 	*/
}	/*	<- namespace Psycholops 	*/
