package de.duehl.swing.ui.colors;

/*
 * Copyright 2024 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

/**
 * Diese Klasse stellt grundlegende, einfache Methoden rund um Farben zur Verfügung.
 *
 * @version 1.01     2024-07-26
 * @author Christian Dühl
 */

public class ColorTool {

    /**
     * Bildet aus einem der für die Anzeige als HTML-Datei gebildeten Farbnamen der Form "FF0000"
     * ein passendes Color-Objekt.
     *
     * @param hexColor
     *            Farbe in der Art "FF0000".
     * @return Color-Objekt mit der entsprechenden Farbe (im Beispiel Color.RED).
     * @throws UnknownColorException
     *             Wenn die Farbe nicht 6 Zeichen lang ist oder nicht zur Basis 16 in einen Integer
     *             geparst werden kann.
     */
    public static Color hexColorToJavaColor(String hexColor) {
        return ColorTranslator.hex2Swing(hexColor);
    }

    /**
     * Bildet aus einer Liste mit für die Anzeige als HTML-Datei gebildeten Farbnamen der Form
     * "FF0000" ein Liste mit passenden Color-Objekten.
     *
     * @param hexColors
     *            Die Liste der Farben in der Art "FF0000".
     * @return Die Liste der Color-Objekte mit der entsprechenden Farbe (im Beispiel Color.RED).
     * @throws UnknownColorException
     *             Wenn eine Farbe nicht 6 Zeichen lang ist oder nicht zur Basis 16 in einen
     *             Integer geparst werden kann.
     */
    public static List<Color> hexColorListToJavaColorList(List<String> hexColors) {
        List<Color> colors = new ArrayList<>();

        for (String hexColor : hexColors) {
            Color color = ColorTool.hexColorToJavaColor(hexColor);
            colors.add(color);
        }

        return colors;
    }

    /**
     * Bildet aus einer Java-Farbe einen HTML-Farbwert in der Form "FF0000".
     *
     * @param color
     *            Java-Farbe (etwa Color.RED).
     * @return HTML-Farbwert (etwa "FF0000").
     */
    public static String javaColorToHexColor(Color color) {
        return ColorTranslator.swing2Hex(color);
    }

    /**
     * Bildet aus einem RGB Integer-Tripel einen HTML-Farbwert in der Form "FF0000".
     *
     * @param red
     *            Farbwert für rot als Integer zwischen 0 und 255.
     * @param green
     *            Farbwert für grün als Integer zwischen 0 und 255.
     * @param blue
     *            Farbwert für blau als Integer zwischen 0 und 255.
     * @return HTML-Farbwert (etwa "FF0000").
     */
    public static String rgbToHexColor(int red, int green, int blue) {
        return ColorTranslator.rgbToHexColor(red, green, blue);
    }

    /** Berechnet die entgegengesetzte Farbe. */
    public static Color anticolor(Color color) {
        int red   = 255 - color.getRed();
        int green = 255 - color.getGreen();
        int blue  = 255 - color.getBlue();
        return new Color(red, green, blue);
    }

    /**
     * Berechnet die entgegengesetzte Farbe.
     *
     * @param hexColor
     *            Farbe in der Art "FF0000".
     * @throws UnknownColorException
     *             Wenn die Farbe nicht 6 Zeichen lang ist oder nicht zur Basis
     *             16 in einen Integer geparst werden kann.
     */
    public static String anticolor(String hexColor) {
        Color color = hexColorToJavaColor(hexColor);
        Color antiColor = anticolor(color);
        String antiHexColor = javaColorToHexColor(antiColor);
        return antiHexColor;
    }

    /**
     * Hier wird aus einer Swing-Farbe eine leicht hellere Farbe berechnet.
     *
     * @param color
     *            Farbe.
     * @return hellere Farbe.
     */
    public static Color calculateLighterColor(Color color) {
        return changeColor(color, 20);
    }

    /**
     * Hier wird aus einer Swing-Farbe eine leicht dunklere Farbe berechnet.
     *
     * @param color
     *            Farbe.
     * @return dunklere Farbe.
     */
    public static Color calculateDarkerColor(Color color) {
        return changeColor(color, -20);
    }

    /**
     * Hier wird eine Swing-Farbe um den angegebenen Betrag verändert.
     *
     * @param color
     *            Farbe.
     * @param delta
     *            Betrag um den die Farbe verändert wird.
     * @return veränderte Farbe.
     */
    public static Color changeColor(Color color, int delta) {
        return new Color(
                adjustRangeFrom0To255(color.getRed()   + delta),
                adjustRangeFrom0To255(color.getGreen() + delta),
                adjustRangeFrom0To255(color.getBlue()  + delta));
    }

    private static int adjustRangeFrom0To255(int value) {
        if (value < 0) {
            return 0;
        }
        else if (value > 255) {
            return 255;
        }
        else {
            return value;
        }
    }

    /**
     * Hier wird eine Swing-Farbe um den angegebenen Betrag verändert. Hierbei wird die originale
     * Farbe aber verhältnismäßig auf den Bereich über bzw. unter den addierten Wert angepasst und
     * nicht wir bei changeColor bei 255 bzw. 0 abgeschnitten.
     *
     * @param color
     *            Farbe.
     * @param delta
     *            Betrag um den die Farbe verändert wird.
     * @return veränderte Farbe.
     */
    public static Color changeColorMultiplicative(Color color, int delta) {
        return new Color(
                adjustRangeFrom0To255Multiplicative(color.getRed(), delta),
                adjustRangeFrom0To255Multiplicative(color.getGreen(), delta),
                adjustRangeFrom0To255Multiplicative(color.getBlue(), delta));
    }

    private static int adjustRangeFrom0To255Multiplicative(int value, int delta) {
        if (delta >= 255) {
            return 255;
        }
        if (delta < -255 ) {
            return 0;
        }

        double oldFactor = value / 255d;
        int sizeOfNewRangeWithoutDelta = 255 - Math.abs(delta);
        int newValue = (int) (sizeOfNewRangeWithoutDelta * oldFactor);
        if (delta >= 0) {
            newValue += delta;
        }
        return newValue;
    }

    /**
     * Hier wird aus einer Hex-Farbe eine leicht hellere Farbe berechnet.
     *
     * @param hexColor
     *            Farbe.
     * @return hellere Farbe.
     */
    public static String calculateLighterColor(String hexColor) {
        return changeColor(hexColor, 20);
    }

    /**
     * Hier wird aus einer Hex-Farbe eine leicht dunklere Farbe berechnet.
     *
     * @param hexColor
     *            Farbe.
     * @return dunklere Farbe.
     */
    public static String calculateDarkerColor(String hexColor) {
        return changeColor(hexColor, -20);
    }

    /**
     * Hier wird eine Hex-Farbe um den angegebenen Betrag verändert.
     *
     * @param hexColor
     *            Farbe.
     * @param delta
     *            Betrag um den die Farbe verändert wird.
     * @return veränderte Farbe.
     */
    public static String changeColor(String hexColor, int delta) {
        Color color = hexColorToJavaColor(hexColor);
        color = changeColor(color, delta);
        return javaColorToHexColor(color);
    }

    /** Gibt die Farbe Orange zurück. */
    public static Color orange() {
        return getColorByName(NamedColorListFabric.ORANGE);
    }

    /**
     * Gibt die benannte Farbe zurück.
     *
     * @param colorName
     *            Name der Farbe - hier nimmt man am besten eine der Konstanten aus der Klasse
     *            NamedColorListFabric.
     */
    public static Color getColorByName(String colorName) {
        NamedColorListFabric fabric = new NamedColorListFabric();
        return fabric.getColorByName(colorName);
    }

    /**
     * Gibt die benannte Farbe als Hex-Wert zurück.
     *
     * @param colorName
     *            Name der Farbe - hier nimmt man am besten eine der Konstanten aus der Klasse
     *            NamedColorListFabric.
     */
    public static String getHexColorByName(String colorName) {
        NamedColorListFabric colorFabric = new NamedColorListFabric();
        return colorFabric.getHexColorByName(colorName);
    }

}
