/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.awt;

import java.awt.Color;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.ranides.assira.math.MathUtils;

public final class ColorUtils {
    
    private static final Pattern RE_RGBA = Pattern.compile("rgba? *\\( *([0-9]+) *, *([0-9]+) *, *([0-9]+)(?: *, *([0-9\\.]+) *)?\\)");
    
    private static final Pattern RE_HSLA = Pattern.compile("hsla? *\\( *([0-9]+) *, *([0-9]+) *% *, *([0-9]+) *%(?: *, *([0-9\\.]+) *)?\\)");

    private ColorUtils() { }

    public static Color invert(Color color) {
        int r = 255 - color.getRed();
        int g = 255 - color.getGreen();
        int b = 255 - color.getBlue();
        int a = color.getAlpha();
        return new Color(r,g,b,a);
    }
    
    public static Color alpha(Color color, int alpha) {
        return new Color( (color.getRGB()&0x00FFFFFF)|(MathUtils.clip(alpha,0,255)<<24), true);
    }
    
    public static Color merge(Color back, Color fore, double ratio) {
        double p = MathUtils.clip(ratio, 0, 1.0);
        double f = 1.0 - p;
        int r = MathUtils.round( back.getRed()*f + fore.getRed() * p, 0, 255);
        int g = MathUtils.round( back.getGreen()*f + fore.getGreen() * p, 0, 255);
        int b = MathUtils.round( back.getBlue()*f + fore.getBlue() * p, 0, 255);
        int a = MathUtils.round( back.getAlpha()*f + fore.getAlpha() * p, 0, 255);
        return new Color(r,g,b,a);
    }

    public static Color copy(Color color) {
        return new Color( color.getRGB(), true);
    }
    
    public static String asCSS2(Color color) {
        return String.format("#%06x", color.getRGB() & 0xFFFFFF );
    }
    
    public static String asCSS3(Color color) {
        if(color.getAlpha()!=255) {
            return String.format(Locale.ROOT, "rgba(%d,%d,%d,%.2f)", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()/255.0 );
        } else {
            return String.format(Locale.ROOT, "rgb(%d,%d,%d)", color.getRed(), color.getGreen(), color.getBlue() );
        }
    }
    
    public static Color fromCSS(String value) {
        if(7 == value.length() && value.startsWith("#")) {
            return fromCSS_H6(value);
        }
        if(4 == value.length() && value.startsWith("#")) {
            return fromCSS_H3(value);
        }
        if(value.startsWith("rgb")) {
            Matcher hit = RE_RGBA.matcher(value);
            if(hit.matches()) {
                return fromCSS_RGBA(hit);
            }                    
        }
        if(value.startsWith("hsl")) {
            Matcher hit = RE_HSLA.matcher(value);
            if(hit.matches()) {
                return fromCSS_HSLA(hit);
            }
        }

        throw new IllegalArgumentException("Invalid color: " + value);
    }


    private static Color fromCSS_H6(String value) { // NOPMD
        return new Color(Integer.parseInt(value.substring(1),16));
    }

    private static Color fromCSS_H3(String value) { // NOPMD
        int r = 17*ord(value.charAt(1)); 
        int g = 17*ord(value.charAt(2));
        int b = 17*ord(value.charAt(3));
        return new Color(r,g,b);

    }
    
    private static Color fromCSS_RGBA(Matcher hit) { // NOPMD
        int r = Integer.parseInt(hit.group(1));
        int g = Integer.parseInt(hit.group(2));
        int b = Integer.parseInt(hit.group(3));
        
        if(null !=hit.group(4)) {
            int a = MathUtils.round(255 * Double.parseDouble(hit.group(4)), 0, 255);
            return new Color(r,g,b,a);
        } else {
            return new Color(r,g,b);
        }
    }
    
    private static Color fromCSS_HSLA(Matcher hit) { // NOPMD
        float h = Float.parseFloat(hit.group(1)) / 360.0f;
        float s = Float.parseFloat(hit.group(2)) / 100.0f;
        float v = Float.parseFloat(hit.group(3)) / 100.0f;
        
        if(null !=hit.group(4)) {
            int a = MathUtils.round(255 * Double.parseDouble(hit.group(4)), 0, 255);
            return alpha(Color.getHSBColor(h,s,v), a);
        } else {
            return Color.getHSBColor(h,s,v);
        }
    }

    private static int ord(char c) {
        if( c>='0' && c<='9') {
            return (c-'0');
        }
        if( c>='a' && c<='z') {
            return 10+(c-'a');
        }
        if( c>='A' && c<='Z') {
            return 10+(c-'A');
        }
        throw new IllegalArgumentException("Invalid digit: " + c);
    }
    
}
