package de.duehl.swing.ui.colors;

/*
 * Copyright 2020 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 ein Objekt zur Verfügung, das zyklisch immer eine neue Farbe aus einer
 * Liste von zur Verfügung stehenden Farben liefert.
 *
 * @version 1.01     2020-01-17
 * @author Christian Dühl
 */

public class Colorator {

    /** Liste mit den zyklisch zu verwendenden Farben. */
    private List<String> colors;

    /** Index der nächsten zu vergebenden Farbe. */
    private int index;

    /** Der Konstruktor. */
    public Colorator() {
        index = 0;
        colors = new ArrayList<String>();
        initColorSequenze();
        if (!isColorSequenzOk()) {
            throw new RuntimeException("Nullwerte in Farben!");
        }
    }

    /**
     * Initialisiert die zyklische Farbsequenz.
     *
     * Diese Methode kann überschrieben werden, um eine eigene Farbsequenz anzulegen.
     *
     * Möchte man nur Farben anhängen, ruft man zuerst super.initColorSequenze auf.
     */
    protected void initColorSequenze() {
        NamedColorList namedColors = new NamedColorListFabric().genrateColorList();

        addColor(namedColors.getHexCodeFromNamedColorByName("red"));
        //addColor("aaaa00"); // yellow = ffff00
                              // das echte Gelb war zu unleserlich.
                              // dies auch
        addColor(namedColors.getHexCodeFromNamedColorByName("blue"));

        addColor("FF6600"); // orange = FF6600
                              // das Widget kam mit "orange" nicht klar
                              // orange ist unten in der Liste ffa500
        addColor(namedColors.getHexCodeFromNamedColorByName("green"));
        addColor(namedColors.getHexCodeFromNamedColorByName("purple"));

        addColor(namedColors.getHexCodeFromNamedColorByName("maroon"));
        addColor(namedColors.getHexCodeFromNamedColorByName("olive"));
        addColor(namedColors.getHexCodeFromNamedColorByName("navy"));
        addColor(namedColors.getHexCodeFromNamedColorByName("teal"));
        //addColor(namedColors.getHexCodeFromColorWithName("gray"));
        //addColor(namedColors.getHexCodeFromColorWithName("silver"));
        //addColor(namedColors.getHexCodeFromColorWithName("lime"));
        addColor(namedColors.getHexCodeFromNamedColorByName("fuchsia"));
        //addColor(namedColors.getHexCodeFromNamedColorByName("aqua"));
        addColor(namedColors.getHexCodeFromNamedColorByName("blueviolet"));
        addColor(namedColors.getHexCodeFromNamedColorByName("cadetblue"));
        addColor(namedColors.getHexCodeFromNamedColorByName("chocolate"));
        addColor(namedColors.getHexCodeFromNamedColorByName("crimson"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkblue"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkcyan"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkgreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkolivegreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkorange"));
        addColor(namedColors.getHexCodeFromNamedColorByName("cornflowerblue"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darksalmon"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkseagreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkviolet"));
        addColor(namedColors.getHexCodeFromNamedColorByName("darkslategray"));
        addColor(namedColors.getHexCodeFromNamedColorByName("firebrick"));
        addColor(namedColors.getHexCodeFromNamedColorByName("forestgreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("indigo"));
        addColor(namedColors.getHexCodeFromNamedColorByName("lightseagreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("midnightblue"));
        addColor(namedColors.getHexCodeFromNamedColorByName("olivedrab"));
        addColor(namedColors.getHexCodeFromNamedColorByName("saddlebrown"));
        addColor(namedColors.getHexCodeFromNamedColorByName("seagreen"));
        addColor(namedColors.getHexCodeFromNamedColorByName("sienna"));
        addColor(namedColors.getHexCodeFromNamedColorByName("tomato"));
        addColor(namedColors.getHexCodeFromNamedColorByName("violet"));
    }

    /** Fügt eine Farbe zur Liste der zyklischen Farben hinzu. */
    protected final void addColor(String hexColor) {
        if (colors.contains(hexColor)) {
            throw new IllegalArgumentException("Farbe " + hexColor +
                    " wird wiederholt in Liste eingefügt!");
        }
        colors.add(hexColor);
    }

    /** Überprüft die Farbsequenz. */
    private boolean isColorSequenzOk() {
        for (String color : colors) {
            if (null == color) {
                return false;
            }
        }
        return true;
    }

    /**
     * Fordert die nächste Farbe als Java-Farbe an. Am Ende der Liste wird wieder die erste Farbe
     * geliefert.
     *
     * @return Farbe
     */
    public Color getNextColor() {
        return hexColorToJavaColor(getNextColorAsHex());
    }

    /**
     * Fordert die nächste Farbe als hexadezimale Farbe an. Am Ende der Liste wird wieder die erste
     * Farbe geliefert.
     *
     * @return Farbe
     */
    public String getNextColorAsHex() {
        String color = colors.get(index);
        ++index;
        if (index == colors.size()) {
            index = 0;
        }
        return color;
    }

    /**
     * Fordert die Farbe mit dem gegebenen Index an. Ein zu großer Index wird in den Bereich [0,
     * Länge der Farbliste) gebracht.
     *
     * @param index
     *            Index der zu ermittelnden Farbe.
     * @return Farbe
     */
    public Color getColor(int index) {
        if (index < 0) {
            throw new IllegalArgumentException("Index darf nicht negativ sein! index = " + index);
        }
        int correctedIndex = index;

        while (correctedIndex >= colors.size()) {
            correctedIndex -= colors.size();
        }

        return hexColorToJavaColor(colors.get(correctedIndex));
    }

    /**
     * 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.
     */
    private Color hexColorToJavaColor(String hexColor) {
        return ColorTool.hexColorToJavaColor(hexColor);
    }

    /** Setzt die Sequenz auf den Anfang zurück. */
    public void restartColorSequenze() {
        index = 0;
    }

    /** Gibt eine Kopie der Liste der Farben heraus. */
    public List<String> getColors() {
        List<String> list = new ArrayList<>();

        for (String color : colors) {
            list.add(color);
        }

        return list;
    }

}
