package net.ranides.assira.ui.parsers;

import lombok.experimental.UtilityClass;
import net.ranides.assira.collection.maps.ArrayMap;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.grammar.G4Selector;
import net.ranides.assira.grammar.G4SelectorBuilder;
import net.ranides.assira.ui.helpers.ColorUtils;
import net.ranides.assira.ui.model.CssHexCode;

import java.awt.*;
import java.util.Map;

@UtilityClass
public class ParseCssColor {

    private static final Map<String, Color> COLOR_NAMES = new ArrayMap<>(
        new String[]{
            "aliceblue",
            "antiquewhite",
            "aqua",
            "aquamarine",
            "azure",
            "beige",
            "bisque",
            "black",
            "blanchedalmond",
            "blue",
            "blueviolet",
            "brown",
            "burlywood",
            "cadetblue",
            "chartreuse",
            "chocolate",
            "coral",
            "cornflowerblue",
            "cornsilk",
            "crimson",
            "cyan",
            "darkblue",
            "darkcyan",
            "darkgoldenrod",
            "darkgray",
            "darkgreen",
            "darkgrey",
            "darkkhaki",
            "darkmagenta",
            "darkolivegreen",
            "darkorange",
            "darkorchid",
            "darkred",
            "darksalmon",
            "darkseagreen",
            "darkslateblue",
            "darkslategray",
            "darkslategrey",
            "darkturquoise",
            "darkviolet",
            "deeppink",
            "deepskyblue",
            "dimgray",
            "dimgrey",
            "dodgerblue",
            "firebrick",
            "floralwhite",
            "forestgreen",
            "fuchsia",
            "gainsboro",
            "ghostwhite",
            "gold",
            "goldenrod",
            "gray",
            "green",
            "greenyellow",
            "grey",
            "honeydew",
            "hotpink",
            "indianred",
            "indigo",
            "ivory",
            "khaki",
            "lavender",
            "lavenderblush",
            "lawngreen",
            "lemonchiffon",
            "lightblue",
            "lightcoral",
            "lightcyan",
            "lightgoldenrodyellow",
            "lightgray",
            "lightgreen",
            "lightgrey",
            "lightpink",
            "lightsalmon",
            "lightseagreen",
            "lightskyblue",
            "lightslategray",
            "lightslategrey",
            "lightsteelblue",
            "lightyellow",
            "lime",
            "limegreen",
            "linen",
            "magenta",
            "maroon",
            "mediumaquamarine",
            "mediumblue",
            "mediumorchid",
            "mediumpurple",
            "mediumseagreen",
            "mediumslateblue",
            "mediumspringgreen",
            "mediumturquoise",
            "mediumvioletred",
            "midnightblue",
            "mintcream",
            "mistyrose",
            "moccasin",
            "navajowhite",
            "navy",
            "oldlace",
            "olive",
            "olivedrab",
            "orange",
            "orangered",
            "orchid",
            "palegoldenrod",
            "palegreen",
            "paleturquoise",
            "palevioletred",
            "papayawhip",
            "peachpuff",
            "peru",
            "pink",
            "plum",
            "powderblue",
            "purple",
            "rebeccapurple",
            "red",
            "rosybrown",
            "royalblue",
            "saddlebrown",
            "salmon",
            "sandybrown",
            "seagreen",
            "seashell",
            "sienna",
            "silver",
            "skyblue",
            "slateblue",
            "slategray",
            "slategrey",
            "snow",
            "springgreen",
            "steelblue",
            "tan",
            "teal",
            "thistle",
            "tomato",
            "turquoise",
            "violet",
            "wheat",
            "white",
            "whitesmoke",
            "yellow",
            "yellowgreen"
        },
        new Color[]{
            hexRGB("#f0f8ff"),
            hexRGB("#faebd7"),
            hexRGB("#00ffff"),
            hexRGB("#7fffd4"),
            hexRGB("#f0ffff"),
            hexRGB("#f5f5dc"),
            hexRGB("#ffe4c4"),
            hexRGB("#000000"),
            hexRGB("#ffebcd"),
            hexRGB("#0000ff"),
            hexRGB("#8a2be2"),
            hexRGB("#a52a2a"),
            hexRGB("#deb887"),
            hexRGB("#5f9ea0"),
            hexRGB("#7fff00"),
            hexRGB("#d2691e"),
            hexRGB("#ff7f50"),
            hexRGB("#6495ed"),
            hexRGB("#fff8dc"),
            hexRGB("#dc143c"),
            hexRGB("#00ffff"),
            hexRGB("#00008b"),
            hexRGB("#008b8b"),
            hexRGB("#b8860b"),
            hexRGB("#a9a9a9"),
            hexRGB("#006400"),
            hexRGB("#a9a9a9"),
            hexRGB("#bdb76b"),
            hexRGB("#8b008b"),
            hexRGB("#556b2f"),
            hexRGB("#ff8c00"),
            hexRGB("#9932cc"),
            hexRGB("#8b0000"),
            hexRGB("#e9967a"),
            hexRGB("#8fbc8f"),
            hexRGB("#483d8b"),
            hexRGB("#2f4f4f"),
            hexRGB("#2f4f4f"),
            hexRGB("#00ced1"),
            hexRGB("#9400d3"),
            hexRGB("#ff1493"),
            hexRGB("#00bfff"),
            hexRGB("#696969"),
            hexRGB("#696969"),
            hexRGB("#1e90ff"),
            hexRGB("#b22222"),
            hexRGB("#fffaf0"),
            hexRGB("#228b22"),
            hexRGB("#ff00ff"),
            hexRGB("#dcdcdc"),
            hexRGB("#f8f8ff"),
            hexRGB("#ffd700"),
            hexRGB("#daa520"),
            hexRGB("#808080"),
            hexRGB("#008000"),
            hexRGB("#adff2f"),
            hexRGB("#808080"),
            hexRGB("#f0fff0"),
            hexRGB("#ff69b4"),
            hexRGB("#cd5c5c"),
            hexRGB("#4b0082"),
            hexRGB("#fffff0"),
            hexRGB("#f0e68c"),
            hexRGB("#e6e6fa"),
            hexRGB("#fff0f5"),
            hexRGB("#7cfc00"),
            hexRGB("#fffacd"),
            hexRGB("#add8e6"),
            hexRGB("#f08080"),
            hexRGB("#e0ffff"),
            hexRGB("#fafad2"),
            hexRGB("#d3d3d3"),
            hexRGB("#90ee90"),
            hexRGB("#d3d3d3"),
            hexRGB("#ffb6c1"),
            hexRGB("#ffa07a"),
            hexRGB("#20b2aa"),
            hexRGB("#87cefa"),
            hexRGB("#778899"),
            hexRGB("#778899"),
            hexRGB("#b0c4de"),
            hexRGB("#ffffe0"),
            hexRGB("#00ff00"),
            hexRGB("#32cd32"),
            hexRGB("#faf0e6"),
            hexRGB("#ff00ff"),
            hexRGB("#800000"),
            hexRGB("#66cdaa"),
            hexRGB("#0000cd"),
            hexRGB("#ba55d3"),
            hexRGB("#9370db"),
            hexRGB("#3cb371"),
            hexRGB("#7b68ee"),
            hexRGB("#00fa9a"),
            hexRGB("#48d1cc"),
            hexRGB("#c71585"),
            hexRGB("#191970"),
            hexRGB("#f5fffa"),
            hexRGB("#ffe4e1"),
            hexRGB("#ffe4b5"),
            hexRGB("#ffdead"),
            hexRGB("#000080"),
            hexRGB("#fdf5e6"),
            hexRGB("#808000"),
            hexRGB("#6b8e23"),
            hexRGB("#ffa500"),
            hexRGB("#ff4500"),
            hexRGB("#da70d6"),
            hexRGB("#eee8aa"),
            hexRGB("#98fb98"),
            hexRGB("#afeeee"),
            hexRGB("#db7093"),
            hexRGB("#ffefd5"),
            hexRGB("#ffdab9"),
            hexRGB("#cd853f"),
            hexRGB("#ffc0cb"),
            hexRGB("#dda0dd"),
            hexRGB("#b0e0e6"),
            hexRGB("#800080"),
            hexRGB("#663399"),
            hexRGB("#ff0000"),
            hexRGB("#bc8f8f"),
            hexRGB("#4169e1"),
            hexRGB("#8b4513"),
            hexRGB("#fa8072"),
            hexRGB("#f4a460"),
            hexRGB("#2e8b57"),
            hexRGB("#fff5ee"),
            hexRGB("#a0522d"),
            hexRGB("#c0c0c0"),
            hexRGB("#87ceeb"),
            hexRGB("#6a5acd"),
            hexRGB("#708090"),
            hexRGB("#708090"),
            hexRGB("#fffafa"),
            hexRGB("#00ff7f"),
            hexRGB("#4682b4"),
            hexRGB("#d2b48c"),
            hexRGB("#008080"),
            hexRGB("#d8bfd8"),
            hexRGB("#ff6347"),
            hexRGB("#40e0d0"),
            hexRGB("#ee82ee"),
            hexRGB("#f5deb3"),
            hexRGB("#ffffff"),
            hexRGB("#f5f5f5"),
            hexRGB("#ffff00"),
            hexRGB("#9acd32")
        }
    );

    public static final G4Selector<Color> COLOR = new G4SelectorBuilder<Color>()
        .withName("CssColor:COLOR")
        .withParser(GrammarBase.PARSER)
        .mapRule("colorRGB", node -> {
            int r = ParsePrimitives.parseInt(node.child("@r"));
            int g = ParsePrimitives.parseInt(node.child("@g"));
            int b = ParsePrimitives.parseInt(node.child("@b"));
            return new Color(r, g, b);
        })
        .mapRule("colorRGBA", node -> {
            int r = ParsePrimitives.parseInt(node.child("@r"));
            int g = ParsePrimitives.parseInt(node.child("@g"));
            int b = ParsePrimitives.parseInt(node.child("@b"));
            int alpha = Math.round(255 * ParsePrimitives.parseFloat(node.child("@alpha")));

            return new Color(r, g, b, alpha);
        })
        .mapRule("colorHSL", node -> {
            float h = ParseCssUnit.angle(node.child("@h").text()).floatValue() / 360.0f;
            float s = ParsePrimitives.parsePct(node.child("@s")) / 100.0f;
            float v = ParsePrimitives.parsePct(node.child("@l")) / 100.0f;

            return Color.getHSBColor(h,s,v);
        })
        .mapRule("colorHSLA", node -> {
            float h = ParseCssUnit.angle(node.child("@h").text()).floatValue() / 360.0f;
            float s = ParsePrimitives.parsePct(node.child("@s")) / 100.0f;
            float v = ParsePrimitives.parsePct(node.child("@l")) / 100.0f;
            int alpha = Math.round(255 * ParsePrimitives.parseFloat(node.child("@alpha")));

            return ColorUtils.alpha(Color.getHSBColor(h,s,v), alpha);
        })
        .mapToken("CODE_HEX3", v -> {
            return hexRGB(v.text());
        })
        .mapToken("CODE_HEX4", v -> {
            return hexRGBA(v.text());
        })
        .mapToken("CODE_HEX6", v -> {
            return hexRGB(v.text());
        })
        .mapToken("CODE_HEX8", v -> {
            return hexRGBA(v.text());
        })
        .valueForToken("COLOR_TRANSPARENT", new Color(0,0,0,0))
        .mapToken("COLOR_NAME", v -> {
            return COLOR_NAMES.get(v.text());
        })
        .prepare();

    private static Color hexRGB(String text) {
        CssHexCode hex = CssHexCode.of(text);
        return new Color(hex.component(0), hex.component(1), hex.component(2));
    }

    private static Color hexRGBA(String text) {
        CssHexCode hex = CssHexCode.of(text);
        return new Color(hex.component(0), hex.component(1), hex.component(2), hex.component(3));
    }

    /**
     * Converts string into Color. Supported formats:
     *      #rrggbb
     *      #rgb
     *      rgb() rgba()
     *      hsl() hsla()
     *
     * @param value input
     * @return color
     */
    public static Color color(String value) {
        return GrammarBase.parseSingle(COLOR, "root_color", value);
    }

    public static CQuery<Color> colors(String values) {
        return GrammarBase.parseStream(COLOR, "root_colors", values);
    }

}
