package net.ranides.assira.ui.parsers;

import lombok.experimental.UtilityClass;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.grammar.G4Exception;
import net.ranides.assira.grammar.G4Node;
import net.ranides.assira.grammar.G4Selector;
import net.ranides.assira.grammar.G4SelectorBuilder;
import net.ranides.assira.text.StringUtils;
import net.ranides.assira.ui.helpers.ColorUtils;

import java.awt.*;
import java.util.NoSuchElementException;

@UtilityClass
public class ParseCssColor {

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

            return new Color(r, g, b, alpha);
        })
        .mapRule("colorHSL", node -> {
            float h = Integer.parseInt(node.child("@h").text()) / 360.0f;
            float s = Float.parseFloat(StringUtils.substr(node.child("@s").text(), 0, -1)) / 100.0f;
            float v = Float.parseFloat(StringUtils.substr(node.child("@l").text(), 0, -1)) / 100.0f;

            return Color.getHSBColor(h,s,v);
        })
        .mapRule("colorHSLA", node -> {
            float h = Integer.parseInt(node.child("@h").text()) / 360.0f;
            float s = Float.parseFloat(StringUtils.substr(node.child("@s").text(), 0, -1)) / 100.0f;
            float v = Float.parseFloat(StringUtils.substr(node.child("@l").text(), 0, -1)) / 100.0f;
            int alpha = Math.round(255 * Float.parseFloat(node.child("@alpha").text()));;

            return ColorUtils.alpha(Color.getHSBColor(h,s,v), alpha);
        })
        .mapToken("CODE_HEX3", v -> {
            int r = 17 * Integer.parseInt(v.text().substring(1,2), 16);
            int g = 17 * Integer.parseInt(v.text().substring(2,3), 16);
            int b = 17 * Integer.parseInt(v.text().substring(3,4), 16);

            return new Color(r, g, b);
        })
        .mapToken("CODE_HEX4", v -> {
            int r = 17 * Integer.parseInt(v.text().substring(1,2), 16);
            int g = 17 * Integer.parseInt(v.text().substring(2,3), 16);
            int b = 17 * Integer.parseInt(v.text().substring(3,4), 16);
            int a = 17 * Integer.parseInt(v.text().substring(4,5), 16);

            return new Color(r, g, b, a);
        })
        .mapToken("CODE_HEX6", v -> {
            int r = Integer.parseInt(v.text().substring(1,3), 16);
            int g = Integer.parseInt(v.text().substring(3,5), 16);
            int b = Integer.parseInt(v.text().substring(5,7), 16);

            return new Color(r, g, b);
        })
        .mapToken("CODE_HEX8", v -> {
            int r = Integer.parseInt(v.text().substring(1,3), 16);
            int g = Integer.parseInt(v.text().substring(3,5), 16);
            int b = Integer.parseInt(v.text().substring(5,7), 16);
            int a = Integer.parseInt(v.text().substring(7,9), 16);

            return new Color(r, g, b, a);
        })
        .prepare();

    /**
     * Converts string into Color. Supported formats:
     *      #rrggbb
     *      #rgb
     *      rgb() rgba()
     *      hsl() hsla()
     *
     * @param value input
     * @return color
     */
    public static Color color(String value) {
        try {
            return COLOR.single(GrammarBase.PARSER.parse("root_color", value));
        } catch (NoSuchElementException | G4Exception e) {
            throw new IllegalArgumentException("Invalid color: " + value);
        }
    }

    public static CQuery<Color> colors(String values) {
        try {
            return COLOR.stream(GrammarBase.PARSER.parse("root_colors", values));
        } catch (NoSuchElementException | G4Exception e) {
            throw new IllegalArgumentException("Invalid color: " + values);
        }
    }

}
