// 
// Decompiled by Procyon v0.6.0
// 

package org.jline.utils;

import java.util.logging.Level;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Function;
import java.util.logging.Logger;

public class StyleResolver
{
    private static final Logger log;
    private final Function<String, String> source;
    
    public StyleResolver(final Function<String, String> source) {
        this.source = Objects.requireNonNull(source);
    }
    
    private static Integer colorRgb(String name) {
        name = name.toLowerCase(Locale.US);
        Label_0070: {
            if (name.charAt(0) != 'x') {
                if (name.charAt(0) != '#') {
                    break Label_0070;
                }
            }
            try {
                return Integer.parseInt(name.substring(1), 16);
            }
            catch (final NumberFormatException e) {
                StyleResolver.log.warning("Invalid hexadecimal color: " + name);
                return null;
            }
        }
        Integer color = color(name);
        if (color != null && color != -1) {
            color = Colors.DEFAULT_COLORS_256[color];
        }
        return color;
    }
    
    private static Integer color(String name) {
        int flags = 0;
        if (name.equals("default")) {
            return -1;
        }
        if (name.charAt(0) == '!') {
            name = name.substring(1);
            flags = 8;
        }
        else if (name.startsWith("bright-")) {
            name = name.substring(7);
            flags = 8;
        }
        else if (name.charAt(0) == '~') {
            name = name.substring(1);
            try {
                return Colors.rgbColor(name);
            }
            catch (final IllegalArgumentException e) {
                StyleResolver.log.warning("Invalid style-color name: " + name);
                return null;
            }
        }
        final String s = name;
        switch (s) {
            case "black":
            case "k": {
                return flags + 0;
            }
            case "red":
            case "r": {
                return flags + 1;
            }
            case "green":
            case "g": {
                return flags + 2;
            }
            case "yellow":
            case "y": {
                return flags + 3;
            }
            case "blue":
            case "b": {
                return flags + 4;
            }
            case "magenta":
            case "m": {
                return flags + 5;
            }
            case "cyan":
            case "c": {
                return flags + 6;
            }
            case "white":
            case "w": {
                return flags + 7;
            }
            default: {
                return null;
            }
        }
    }
    
    public AttributedStyle resolve(final String spec) {
        Objects.requireNonNull(spec);
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Resolve: " + spec);
        }
        final int i = spec.indexOf(":-");
        if (i != -1) {
            final String[] parts = spec.split(":-");
            return this.resolve(parts[0].trim(), parts[1].trim());
        }
        return this.apply(AttributedStyle.DEFAULT, spec);
    }
    
    public AttributedStyle resolve(final String spec, final String defaultSpec) {
        Objects.requireNonNull(spec);
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest(String.format("Resolve: %s; default: %s", spec, defaultSpec));
        }
        AttributedStyle style = this.apply(AttributedStyle.DEFAULT, spec);
        if (style == AttributedStyle.DEFAULT && defaultSpec != null) {
            style = this.apply(style, defaultSpec);
        }
        return style;
    }
    
    private AttributedStyle apply(AttributedStyle style, final String spec) {
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Apply: " + spec);
        }
        for (String item : spec.split(",")) {
            item = item.trim();
            if (!item.isEmpty()) {
                if (item.startsWith(".")) {
                    style = this.applyReference(style, item);
                }
                else if (item.contains(":")) {
                    style = this.applyColor(style, item);
                }
                else if (item.matches("[0-9]+(;[0-9]+)*")) {
                    style = this.applyAnsi(style, item);
                }
                else {
                    style = this.applyNamed(style, item);
                }
            }
        }
        return style;
    }
    
    private AttributedStyle applyAnsi(final AttributedStyle style, final String spec) {
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Apply-ansi: " + spec);
        }
        return new AttributedStringBuilder().style(style).ansiAppend("\u001b[" + spec + "m").style();
    }
    
    private AttributedStyle applyReference(final AttributedStyle style, final String spec) {
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Apply-reference: " + spec);
        }
        if (spec.length() == 1) {
            StyleResolver.log.warning("Invalid style-reference; missing discriminator: " + spec);
        }
        else {
            final String name = spec.substring(1);
            final String resolvedSpec = this.source.apply(name);
            if (resolvedSpec != null) {
                return this.apply(style, resolvedSpec);
            }
        }
        return style;
    }
    
    private AttributedStyle applyNamed(final AttributedStyle style, final String name) {
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Apply-named: " + name);
        }
        final String lowerCase = name.toLowerCase(Locale.US);
        switch (lowerCase) {
            case "default": {
                return AttributedStyle.DEFAULT;
            }
            case "bold": {
                return style.bold();
            }
            case "faint": {
                return style.faint();
            }
            case "italic": {
                return style.italic();
            }
            case "underline": {
                return style.underline();
            }
            case "blink": {
                return style.blink();
            }
            case "inverse": {
                return style.inverse();
            }
            case "inverse-neg":
            case "inverseneg": {
                return style.inverseNeg();
            }
            case "conceal": {
                return style.conceal();
            }
            case "crossed-out":
            case "crossedout": {
                return style.crossedOut();
            }
            case "hidden": {
                return style.hidden();
            }
            default: {
                StyleResolver.log.warning("Unknown style: " + name);
                return style;
            }
        }
    }
    
    private AttributedStyle applyColor(final AttributedStyle style, final String spec) {
        if (StyleResolver.log.isLoggable(Level.FINEST)) {
            StyleResolver.log.finest("Apply-color: " + spec);
        }
        final String[] parts = spec.split(":", 2);
        final String colorMode = parts[0].trim();
        final String colorName = parts[1].trim();
        final String lowerCase = colorMode.toLowerCase(Locale.US);
        switch (lowerCase) {
            case "foreground":
            case "fg":
            case "f": {
                final Integer color = color(colorName);
                if (color == null) {
                    StyleResolver.log.warning("Invalid color-name: " + colorName);
                    break;
                }
                return (color >= 0) ? style.foreground(color) : style.foregroundDefault();
            }
            case "background":
            case "bg":
            case "b": {
                final Integer color = color(colorName);
                if (color == null) {
                    StyleResolver.log.warning("Invalid color-name: " + colorName);
                    break;
                }
                return (color >= 0) ? style.background(color) : style.backgroundDefault();
            }
            case "foreground-rgb":
            case "fg-rgb":
            case "f-rgb": {
                final Integer color = colorRgb(colorName);
                if (color == null) {
                    StyleResolver.log.warning("Invalid color-name: " + colorName);
                    break;
                }
                return (color >= 0) ? style.foregroundRgb(color) : style.foregroundDefault();
            }
            case "background-rgb":
            case "bg-rgb":
            case "b-rgb": {
                final Integer color = colorRgb(colorName);
                if (color == null) {
                    StyleResolver.log.warning("Invalid color-name: " + colorName);
                    break;
                }
                return (color >= 0) ? style.backgroundRgb(color) : style.backgroundDefault();
            }
            default: {
                StyleResolver.log.warning("Invalid color-mode: " + colorMode);
                break;
            }
        }
        return style;
    }
    
    static {
        log = Logger.getLogger(StyleResolver.class.getName());
    }
}
