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

#include "psychlops_g_SVG.h"
#include "../../../core/graphic/psychlops_g_shape.h"
#include "../../../core/graphic/psychlops_g_font.h"
#include "../../../core/devices/psychlops_io_file.h"
#include <stdio.h>
#include <math.h>
#include <vector>
#include <fstream>
#include <iostream>

namespace Psychlops {


	const char* strokeStyleSVG[3] = { "", "5 5", "1 1" };
	const char* strokeStyleToSVG(const Stroke &strk) {
		switch(strk.pattern) {
			case Stroke::DASHED:
				return strokeStyleSVG[1];
			case Stroke::DOTTED:
				return strokeStyleSVG[2];
			case Stroke::SOLID:
			default:
				return strokeStyleSVG[0];
		}
	}

	SVGCanvas::SVGCanvas(double width_, double height_) : width(width_), height(height_) {
		prime_backup = Drawable::prime;
		Drawable::prime = this;
	}
	SVGCanvas::~SVGCanvas() {
		Drawable::prime = prime_backup;
	}
	SVGCanvas& SVGCanvas::save(std::string filename) {
		char buf[32];
		std::string filenamechacker = File::decodePath(filename);
		std::ofstream outport;
		outport.open(filenamechacker.c_str());
		outport << "<?xml version=\"1.0\" standalone=\"no\"?>" << std::endl <<
		"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << std::endl <<
		"<svg";
		sprintf(buf, " width=\"%gpx\" height=\"%gpx\"", width, height);
		outport << buf;
		outport << " xmlns=\"http://www.w3.org/2000/svg\"> " << std::endl;
		outport << output;
		outport << "</svg>";
		outport.close();
		return *this;
	}
	int SVGCanvas::getWidth() const {
		return (int)ceil(width);
	}
	int SVGCanvas::getHeight() const {
		return (int)ceil(height);
	}
	const Point SVGCanvas::getCenter() const {
		Point po(width/2.0, height/2.0);
		return po;
	}

	SVGCanvas& SVGCanvas::clear(const Color &col) {
		output.clear();
		return *this;
	}

	SVGCanvas& SVGCanvas::pix(const double x, const double y, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		sprintf(buffer, "<rect x1=\"%gpx\" y1=\"%gpx\" x2=\"%gpx\" y2=\"%gpx\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" />"
				, x-.5, y-.5, x+.5, y+.5
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		return *this;
	}

	SVGCanvas& SVGCanvas::line(const Line &drawee, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		sprintf(buffer, "<line x1=\"%gpx\" y1=\"%gpx\" x2=\"%gpx\" y2=\"%gpx\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" />"
				, drawee.datum.x, drawee.datum.y, drawee.getEnd().x, drawee.getEnd().y
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::line(const Line &drawee, const Stroke &strk) {
		double r, g, b, a;
		strk.color.get(r,g,b,a);
		sprintf(buffer, "line x1=\"%gpx\" y1=\"%gpx\" x2=\"%gpx\" y2=\"%gpx\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" stroke-width=\"%g\" stroke-dasharray=\"%s\" />"
				, drawee.datum.x, drawee.datum.y, drawee.getEnd().x, drawee.getEnd().y
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a
				, strk.width, strokeStyleToSVG(strk));
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::rect(const Rectangle &drawee, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		sprintf(buffer, "<rect x=\"%gpx\" y=\"%gpx\" width=\"%gpx\" height=\"%gpx\" fill=\"#%02x%02x%02x\" opacity=\"%g\" />"
				, drawee.getLeft(), drawee.getTop(), drawee.getWidth(), drawee.getHeight()
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::rect(const Rectangle &drawee, const Stroke &strk) {
		double r, g, b, a;
		strk.color.get(r,g,b,a);
		sprintf(buffer, "<rect x=\"%gpx\" y=\"%gpx\" width=\"%gpx\" height=\"%gpx\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" stroke-width=\"%g\" stroke-dasharray=\"%s\" />"
				, drawee.getLeft(), drawee.getTop(), drawee.getWidth(), drawee.getHeight()
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a
				, strk.width, strokeStyleToSVG(strk));
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::ellipse(const Ellipse &drawee, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		sprintf(buffer, "<ellipse cx=\"%gpx\" cy=\"%gpx\" rx=\"%gpx\" ry=\"%gpx\" fill=\"#%02x%02x%02x\" opacity=\"%g\" />"
				, drawee.datum.x, drawee.datum.y, drawee.radius, drawee.v_radius
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::ellipse(const Ellipse &drawee, const Stroke &strk) {
		double r, g, b, a;
		strk.color.get(r,g,b,a);
		sprintf(buffer, "<ellipse cx=\"%gpx\" cy=\"%gpx\" rx=\"%gpx\" ry=\"%gpx\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" stroke-width=\"%g\" stroke-dasharray=\"%s\" />"
				, drawee.datum.x, drawee.datum.y, drawee.radius, drawee.v_radius
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a
				, strk.width, strokeStyleToSVG(strk));
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::polygon(const Polygon &drawee) {
		return polygon(drawee, drawee.stroke);
	}
	SVGCanvas& SVGCanvas::polygon(const Polygon &drawee, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		output.append("<polygon points=\"");
		for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
			sprintf(buffer, "%gpx,%gpx ", (*v).x, (*v).y);
			output.append(buffer);
		}
		sprintf(buffer, "\" fill=\"#%02x%02x%02x\" opacity=\"%g\" />"
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::polygon(const Polygon &drawee, const Stroke &strk) {
		double r, g, b, a;
		strk.color.get(r,g,b,a);
		output.append("<polygon points=\"");
		for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
			sprintf(buffer, "%gpx,%gpx ", (*v).x, (*v).y);
			output.append(buffer);
		}
		sprintf(buffer, "\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" stroke-width=\"%g\" stroke-dasharray=\"%s\" />"
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a
				, strk.width, strokeStyleToSVG(strk));
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::polyline(const PolyLine &drawee) {
		return polyline(drawee, Color::black);
	}
	SVGCanvas& SVGCanvas::polyline(const PolyLine &drawee, const Color &col) {
		Stroke strk(col, 1, Stroke::SOLID);
		return polyline(drawee, strk);
	}
	SVGCanvas& SVGCanvas::polyline(const PolyLine &drawee, const Stroke &strk) {
		double r, g, b, a;
		strk.color.get(r,g,b,a);
		output.append("<polyline points=\"");
		for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
			sprintf(buffer, "%gpx,%gpx ", (*v).x, (*v).y);
			output.append(buffer);
		}
		sprintf(buffer, "\" stroke=\"#%02x%02x%02x\" stroke-opacity=\"%g\" stroke-width=\"%g\" stroke-dasharray=\"%s\" />"
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a
				, strk.width, strokeStyleToSVG(strk));
		output.append(buffer);
		return *this;
	}
	SVGCanvas& SVGCanvas::figures(const Group &drawee) {
		output.append("<g transform=\"");
		sprintf(buffer, "%g, %g", drawee.datum.x, drawee.datum.y);
		output.append(" translate(").append(buffer).append(")");
		if(drawee.scaling.x!=0.0 || drawee.scaling.y!=0.0 || drawee.scaling.z!=0.0) {
			sprintf(buffer, "%g, %g", drawee.scaling.x, drawee.scaling.y);
			output.append(" scale(").append(buffer).append(")");
		}
		if(drawee.rotation!=0.0) {
			sprintf(buffer, "%g, %g, %g", drawee.rotation, drawee.datum.x, drawee.datum.y);
			output.append(" rotate(").append(buffer).append(")");
		}
		output.append("\">");
		if(!drawee.contents.empty()) {
			for(int i=0; i<drawee.contents.size(); i++) {
				drawee.contents[i]->draw(*this);
			}
		}
		output.append("</g>");
		return *this;
	}

	SVGCanvas& SVGCanvas::image(const Image &img) {
		return *this;
	}
	SVGCanvas& SVGCanvas::image(const Image &img, const double x, const double y) {
		return *this;
	}
	SVGCanvas& SVGCanvas::image(const Image &img, const double alpha) {
		return *this;
	}

	const char* SVG_TEXT_ANCHOR[4] = { "start", "start", "middle", "end" };
	const char* SVG_FONT_STYLE[3] = { "normal", "italic", "oblique" };
	const char* SVG_TEXT_DECORATION[4] = { "none", "underline", "overline", "line-through" };
	SVGCanvas& SVGCanvas::letters(Letters &let, const Color &col) {
		double r, g, b, a;
		col.get(r,g,b,a);
		Font font = let.getFont();
		output.append("<text x=\"");
		sprintf(buffer, "%gpx\", y=\"%g\" text-anchor=\"%s\" "
				, let.getDatum().x, let.getDatum().y, SVG_TEXT_ANCHOR[let.align+1]);
		output.append(buffer);
		sprintf(buffer, "font-size=\"%gpx\" font-weight=\"%d\" font-style=\"%s\" font-family=\"%s\" />"
				, font.size, font.weight, SVG_FONT_STYLE[font.style], font.family[0].c_str());
		output.append(buffer);
		sprintf(buffer, "fill=\"#%02x%02x%02x\" opacity=\"%g\" />"
				, (unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), a);
		output.append(buffer);
		output.append(">");
		output.append("</text>");
		return *this;
	}

}	/*	<- namespace Psycholops 	*/
