package dendrarium.trees.svg;

import dendrarium.utils.Pair;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jdom.DocType;
import org.jdom.Element;
import org.jdom.Namespace;

/**
 *
 * @author Tomasz Badowski
 */
public class SVGJdom {

    static public String ns = "http://www.w3.org/2000/svg";

    static public String pref = "svg";

    public static DocType getStandardDocType() {
        String dtdConstrainedElement = "svg";
        String dtdPublicID = "-//W3C//DTD SVG 1.1//EN";
        String dtdSystemID =
                "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";
        DocType docType = new DocType(dtdConstrainedElement,
                dtdPublicID, dtdSystemID);
        return docType;
    }

    public static Element getStandardSVG() {
        Element svg = new Element("svg", pref, ns);
        svg.setAttribute("version", "1.1");
        return svg;
    }

    public static Element getStandardPrefSVG() {
        Element svg = new Element("svg", pref, ns);
        svg.setAttribute("version", "1.1");
        return svg;
    }

    static void drawInteractiveNodeWithRule(int x, int y, int symbolWidth,
            String fillColor, String strokeColor,
            String symbol, String label, String rule, String link, Element svg) {
        drawInteractiveSVGNode(x, y - DrawConfig.getTextFontSize(), symbolWidth, symbol, label, fillColor,
                strokeColor, link, svg);
        drawText(rule, x + DrawConfig.getRuleFontSize(), y + DrawConfig.getRuleFontSize() / 2,
                DrawConfig.getTextColor(), DrawConfig.getRuleFontSize().toString(), svg);
    }

    static int textWidth(String text) {
        int small = 0;
        int middle = 0;
        for (char c : text.toCharArray()) {
            if ((c == ' ') || (c == ',') || (c == '/') || (c == ')') || (c == '(') || (c == 'i') || (c == 'j') || (c == 'l') || (c == '[') || (c == ']') || (c == '.')) {
                small++;
            } else if ((c == 't') || (c == 'y') || (c == 'r') || (c == 'f')) {
                middle++;
            }
        }
        return DrawConfig.getTextFontWidth() * (text.length() - small - middle) +
                small * DrawConfig.getSmallFontWidth() + middle * DrawConfig.getMiddleFontWidth();
    }

    static void drawLine(Integer x1, Integer x2, Integer y1, Integer y2,
            Element svg) {
        Element line = new Element("line", pref, ns);

        line.setAttribute("stroke", DrawConfig.getLineStroke());
        line.setAttribute("stroke-width", DrawConfig.getLineStrokeWidth().toString());

        line.setAttribute("x1", "" + x1);
        line.setAttribute("y1", "" + y1);
        line.setAttribute("x2", "" + x2);
        line.setAttribute("y2", "" + y2);
        svg.addContent(line);
    }

    static void drawHorizLine(Integer x1, Integer x2, Integer y, Element svg) {
        drawLine(x1, x2, y, y, svg);
    }

    static void drawVertLine(Integer x, Integer y1, Integer y2, Element svg) {
        drawLine(x, x, y1, y2, svg);
    }

    static Element addTextWithAttrs(Integer x, Integer y, String textColor,
            String textSize) {
        Element xmlText = new Element("text", pref, ns);
        xmlText.setAttribute("x", x.toString());
        xmlText.setAttribute("y", y.toString());
        xmlText.setAttribute("font-family", DrawConfig.getTextFontFamily());
        xmlText.setAttribute("font-size", textSize);
        xmlText.setAttribute("fill", textColor);
        return xmlText;
    }

    static Element addText(String text, Integer x, Integer y,
            String textColor, String textSize) {
        Element xmlText = addTextWithAttrs(x, y, textColor, textSize);
        xmlText.addContent(text);
        return xmlText;
    }

    static void drawText(String text, Integer x, Integer y, String color,
            String size, Element svg) {
        svg.addContent(addText(text, x, y, color, size));
    }

    static Element addTitledText(String text, String label, Integer x, Integer y,
            String color, String size) {
        Element xmlText = addText(text, x, y, color, size);
        xmlText.setAttribute("title", label);
        return xmlText;
    }

    static Element addCentredTitledText(String text, String label, Integer x,
            Integer y, String color, String size) {
        Element xmlText = addText(text, x, y, color, size);
        xmlText.setAttribute("title", label);
        xmlText.setAttribute("style", "text-align:center;text-anchor:middle");
        return xmlText;
    }

    static void drawTitledText(String text, String label, Integer x, Integer y,
            String color, String size, Element svg) {
        Element xmlText = addTitledText(text, label, x, y, color, size);
        svg.addContent(xmlText);
    }

    static void drawCentredTitledText(String text, String label, Integer x,
            Integer y, String color, String size, Element svg) {
        Element xmlText = addCentredTitledText(text, label, x, y, color, size);
        svg.addContent(xmlText);
    }

    private static void drawCentredTitledInteractiveText(String text,
            String label,
            Integer x, Integer y,
            String color, String size, String link, Element svg) {
        Element a = getStandardA(link);
        Element xmlText = addCentredTitledText(text, label, x, y, color, size);
        a.addContent(xmlText);
        svg.addContent(a);
    }

    static int rectangleWidth(int textWidth) {
        return 2 * DrawConfig.getPillowSize() + textWidth;
    }

    static Element addRectangle(Integer x, Integer y, Integer width,
            String color, String strokeColor, Element svg) {
        /* (x , y) to wspolrzedne lewego dolnego rogu tekstu w prostokacie */
        Integer height = DrawConfig.getTextFontSize();
        Integer pillow = DrawConfig.getPillowSize();
        Integer newY = y - height - pillow;
        Integer newX = x - pillow;
        height = height + (5 * pillow) / 2;
        width = width + 2 * pillow;
        Element rectB = new Element("rect", pref, ns);
        rectB.setAttribute("x", newX.toString());
        rectB.setAttribute("y", newY.toString());
        rectB.setAttribute("width", width.toString());
        rectB.setAttribute("height", height.toString());
        rectB.setAttribute("fill", color);
        rectB.setAttribute("stroke", strokeColor);
        rectB.setAttribute("stroke-width", DrawConfig.getLineStrokeWidth().toString());
        rectB.setAttribute("ry", "11");
        rectB.setAttribute("rx", "11");
        return rectB;
    }

    static void drawTitledRectangle(Integer x, Integer y, Integer width,
            String label, String color, String strokeColor, Element svg) {
        Element rect = addRectangle(x, y, width, color, strokeColor, svg);
        rect.setAttribute("title", label);
        svg.addContent(rect);
    }

    static void drawRectangle(Integer x, Integer y, Integer width,
            String color, String strokeColor, Element svg) {
        Element rect = addRectangle(x, y, width, color, strokeColor, svg);
        svg.addContent(rect);
    }

    static void drawSVGNode(int x, int y, int textWidth, String symbol,
            String label,
            String color, String strokeColor, Element svg) {
        /* x i y to wspolrzedne srodka tekstu w wierzcholku */
        int yRect = y;
        int xRect = x - textWidth / 2;
        drawTitledRectangle(xRect, yRect, textWidth, label, color, strokeColor, svg);
        drawCentredTitledText(symbol, label, x, y, DrawConfig.getTextColor(), DrawConfig.getTextFontSize().toString(), svg);
    }

    static List createColoredElemCollection(String symbol, List<Pair<String, String>> attrs,
            List<String> diffAttrs) {
        List elems = new LinkedList<Object>();
        int i = 0;
        boolean isLast;
//        boolean lastWasString = false;
        String sPom;
        elems.add(symbol);
        if (attrs.size() > 0) {
            elems.add("(");
        }
        for (Pair<String, String> p : attrs) {
            String s = p.getF1();
            String k = p.getF2();

            isLast = (attrs.size() == (i + 1));
            sPom = k + ((isLast) ? "" : ", ");
            if (diffAttrs.contains(s)) {
                Element tsp = new Element("tspan", pref, ns);
                tsp.setAttribute("fill", "red");
                if (attrs.size() == i + 1) {
                    isLast = true;
                }
                tsp.addContent(sPom);
                elems.add(tsp);
            } else {
                elems.add(sPom);
            }
            i++;
        }
        if (attrs.size() > 0) {
            elems.add(")");
        }
        return elems;
    }

    static void drawCentredColoredText(String symbol, Integer x, Integer y,
            List<Pair<String, String>> attrs, List<String> diffAttrs, String textColor,
            String textSize, Element svg) {
        Element xmlText = addTextWithAttrs(x, y, textColor, textSize);
        xmlText.addContent(createColoredElemCollection(symbol, attrs, diffAttrs));
        xmlText.setAttribute("style", "text-align:center;text-anchor:middle");
        svg.addContent(xmlText);
    }

    static void drawTextColoredSVGNode(int x, int y, String symbol,
            int textWidth,
            List<Pair<String, String>> attrs, List<String> diffAttrs, String color,
            String strokeColor, Element svg) {
        /* x i y to wspolrzedne srodka tekstu w wierzcholku */
        int yRect = y;
        int xRect = x - textWidth / 2;
        drawRectangle(xRect, yRect, textWidth, color, strokeColor, svg);
        drawCentredColoredText(symbol, x, y, attrs, diffAttrs, DrawConfig.getTextColor(), DrawConfig.getTextFontSize().toString(), svg);
    }

    static void drawNodeWithRule(int x, int y, int symbolWidth, String symbol,
            String label, String rule, Element svg) {
        drawSVGNode(x, y - DrawConfig.getTextFontSize(), symbolWidth, symbol, label, DrawConfig.getFillColor(),
                DrawConfig.getStrokeColor(), svg);
        drawText(rule, x + DrawConfig.getRuleFontSize(), y + DrawConfig.getRuleFontSize() / 2,
                DrawConfig.getTextColor(), DrawConfig.getRuleFontSize().toString(), svg);
    }

    static void drawPolygon(int[] points, String stroke, String strokeWidth,
            String fill, Element svg) {
        Element polygon = new Element("polygon", pref, ns);
        polygon.setAttribute("stroke", stroke);
        polygon.setAttribute("stroke-width", strokeWidth);
        polygon.setAttribute("fill", fill);

        String dataPoints = "";
        for (int i = 0 ; i < points.length ; i++) {
            dataPoints += "" + points[i] + ",";
        }
        polygon.setAttribute("points", dataPoints);

        svg.addContent(polygon);
    }

    static void drawHorizTriangle(int xLeft, int xRight, int yBottom,
            int yTop, String strokeColor, String fillColor, Element svg) {
        drawPolygon(new int[] {xLeft, yBottom, xRight, yBottom,
                    (xLeft + xRight) / 2, yTop},
                strokeColor, DrawConfig.getLineStrokeWidth().toString(), fillColor, svg);
    }

    static void drawInteractiveSVGNode(int x, int y, int symbolWidth,
            String symbol, String label,
            String color, String strokeColor, String link, Element svg) {
        int yRect = y;
        int xRect = x - symbolWidth / 2;
        drawTitledInteractiveRectangle(xRect, yRect, symbolWidth, label, color, strokeColor, link, svg);
        drawCentredTitledInteractiveText(symbol, label, x, yRect, DrawConfig.getTextColor(),
                DrawConfig.getTextFontSize().toString(), link, svg);
    }

    private static Element getStandardA(String link) {
        Element a = new Element("a", pref, ns);
        if (link != null) {
            a.setAttribute("onclick", link);
        }
        Namespace nsXlink = Namespace.getNamespace("xlink", "http://www.w3.org");

        // pta
        a.setAttribute("href", /*link*/ "#", nsXlink);
        a.setAttribute("cursor", "pointer");

        return a;
    }

    private static void drawTitledInteractiveRectangle(int x, int y,
            int width, String label, String color, String strokeColor,
            String link, Element svg) {
        Element a = getStandardA(link);
        Element rect = addRectangle(x, y, width, color, strokeColor, svg);
        rect.setAttribute("title", label);
        a.addContent(rect);
        svg.addContent(a);
    }
}