package schema;

import model.*;

@:expose
class MLDToSVG {
	/**
	 * génère un diagramme au format SVG à partir d'un MLD
	 * @param diagram le MLD
	 * @return le diagramme SVG (sous la forme d'un objet XML)
	 */
	public static function generateSVG(mld : MLD, typed : Bool) : Xml {
		var doc : Xml = Xml.createDocument();
		var svg : Xml = Svg.initSvg(doc);

		for (relation in mld.relations) {
			relation.svg = generateTableSvg(relation, typed);
			svg.addChild(relation.svg);
		}

		Svg.placeObjects(mld.relations, svg, mld.height, mld.width);
		for (relation in mld.relations) {
			for (fk in relation.foreignKeys) {
				svg.addChild(generateLineSVG(relation, fk));
			}
		}
		return doc;
	}

	static function generateTableSvg(relation : Relation, typed : Bool) : Xml {
		var chrWidth : Int = relation.name.length;
		for (field in relation.fields) {
			var lineWidth : Int = field.name.length + (typed ? field.dbType.length + 2 : 0);
			if (lineWidth > chrWidth) {
				chrWidth = lineWidth;
			}
		}
		var g : Xml = Xml.createElement("g");
		var rect : Xml = Xml.createElement("rect");
		g.addChild(rect);
		rect.set("height", Std.string((relation.fields.length + 1) * Svg.LETTER_HEIGHT + Svg.PADDING * 2));
		rect.set("width", Std.string(Std.int(chrWidth * Svg.LETTER_WIDTH + Svg.PADDING * 2)));
		rect.set("style", Svg.FILL_WHITE_STYLE);

		var titleBG : Xml = Xml.createElement("rect");
		g.addChild(titleBG);
		titleBG.set("height", Std.string(Svg.LETTER_HEIGHT + Svg.PADDING));
		titleBG.set("width", Std.string(chrWidth * Svg.LETTER_WIDTH + Svg.PADDING * 2));
		titleBG.set("style", /*Svg.FILL_GREY_STYLE*/Svg.FILL_WHITE_STYLE);

		var title : Xml = Xml.createElement("text");
		g.addChild(title);
		title.addChild(Xml.createPCData(relation.name));
		title.set("x", Std.string(Svg.PADDING + (chrWidth - relation.name.length) * Svg.LETTER_WIDTH / 2));
		title.set("y", Std.string(Svg.LETTER_HEIGHT));

		var text : Xml = Xml.createElement("text"); //space
		g.addChild(text);
		for (i in 0...relation.fields.length) {
			var tspan : Xml = Xml.createElement("tspan");
			text.addChild(tspan);
			tspan.set("x", Std.string(Svg.PADDING / 2));
			tspan.set("y", Std.string(Svg.LETTER_HEIGHT * (i + 2) + Svg.PADDING));
			if (relation.key.indexOf(relation.fields[i].name) != -1) {
				tspan.set("style", Svg.UNDERLINE_STYLE);
			}
			tspan.addChild(Xml.createPCData(relation.fields[i].name));
			if (typed) {
				tspan = Xml.createElement("tspan");
				text.addChild(tspan);
				tspan.set("x", Std.string(Svg.PADDING + (chrWidth - relation.fields[i].dbType.length) * Svg.LETTER_WIDTH));
				tspan.set("y", Std.string(Svg.LETTER_HEIGHT * (i + 2) + Svg.PADDING));
				tspan.addChild(Xml.createPCData(relation.fields[i].dbType));
			}
		}
		return g;
	}

	static function generateLineSVG(relation : Relation, fk : ForeignKey) : Xml {
		//retrieve boxes coordinates:
		var coords1 : Array<String> = Svg.coordRE.replace(relation.svg.get("transform"), "$1").split(","); //"translate(x,y)" -> [x, y]
		var x1 : Int = Std.parseInt(coords1[0]);
		var y1 : Int = Std.parseInt(coords1[1]);
		var w1 : Int = Std.parseInt(relation.svg.firstChild().get("width"));
		var coords2 : Array<String> = Svg.coordRE.replace(fk.relation.svg.get("transform"), "$1").split(",");
		var x2 : Int = Std.parseInt(coords2[0]);
		var y2 : Int = Std.parseInt(coords2[1]);
		var w2 : Int = Std.parseInt(fk.relation.svg.firstChild().get("width"));

		//calculate line path points position:
		y1 = y1 + Svg.LETTER_HEIGHT * (relation.getFieldIndex(fk.name) + 2); //yl1 = y1
		y2 = y2 + Svg.LETTER_HEIGHT * (fk.relation.getFieldIndex(fk.key) + 2); //yl2 = y2
		var xl1 : Int;
		var xl2 : Int;
		var xa : Int = Svg.PADDING;
		if (relation.col == fk.relation.col) {
			x1 = x1 + w1; //vertical line on the left
			x2 = x2 + w2;
			xl1 = Std.int(Math.max(x1, x2)) + Svg.PADDING * 2;
			xl2 = xl1;
		} else if (relation.col < fk.relation.col) {
			x1 = x1 + w1;
			xl1 = x1 + Svg.PADDING * 2;
			xl2 = x2 - Svg.PADDING * 2;
			xa = -xa; //invert arrow direction
		} else {
			x2 = x2 + w2;
			xl1 = x1 - Svg.PADDING * 2;
			xl2 = x2 + Svg.PADDING * 2;
		}
		var g : Xml = Xml.createElement("g");
		var line : Xml = Xml.createElement("path");
		line.set("d", 'M $x1 $y1 L $xl1 $y1 L $xl2 $y2 L $x2 $y2');
		line.set("marker-end", 'url(#${Svg.MARKERS[0].id})');
		g.addChild(line);
		return g;
	}
}
