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.awt.Component;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.text.JTextComponent;

import de.duehl.swing.ui.GuiTools;

/**
 * Diese Klasse hält die Standardfarben der Oberfläche und bietet Methoden,
 * diese sowie spezielle Einfärbungen von Oberflächenkomponenten durchzuführen.
 *
 * @see hr.messenger.client.ui.MessengerColorizer
 *
 * @version 1.01     2020-01-17
 * @author Christian Dühl
 */

public class Colorizer {

    /* Hier verwendete Farben: */
    public static final String GENERAL   = "GENERAL";
    public static final String RIGHT     = "RIGHT";
    public static final String WRONG     = "WRONG";
    public static final String WARN      = "WARN";
    public static final String WARN_HIGH = "WARN_HIGH";
    public static final String GREY      = "GREY";

    /** Verzeichnis der Farben. */
    private Map<String, ElementColors> colors;

    /** Konstruktor. */
    public Colorizer() {
        colors = new HashMap<>();
        initColors();
    }

    /**
     * Standardfarben erzeugen. Diese Methode kann überschrieben werden, dann
     * sollte allerdings super.initColors() dort aufgerufen werden.
     */
    protected void initColors() {
        {
            Color fg  = new Color(  0,   0, 150); // Color.GREEN
            Color bg  = new Color(230, 230, 255); // Color.RED
            ElementColors general = new ElementColors(fg, bg);
            addNewColortype(GENERAL, general);
        }

        /* Farben für "richtig" erzeugen: */
        {
            Color fg  = new Color(  0, 150,   0);
            Color bg  = new Color(230, 255, 230);
            ElementColors right = new ElementColors(fg, bg);
            addNewColortype(RIGHT, right);
        }

        /* Farben für "falsch" erzeugen: */
        {
            Color fg  = new Color(150,   0,   0);
            Color bg  = new Color(255, 230, 230);
            ElementColors wrong = new ElementColors(fg, bg);
            addNewColortype(WRONG, wrong);
        }

        /* Farben für "Warnung" erzeugen: */
        {
            Color fg  = new Color(150, 150,   0);
            Color bg  = new Color(255, 255, 230);
            ElementColors warn = new ElementColors(fg, bg);
            addNewColortype(WARN, warn);
        }

        /* Farben für "hohe Warnung" erzeugen: */
        {
            Color fg  = new Color(200, 200,   0);
            Color bg  = new Color(255, 255, 230);
            ElementColors warn = new ElementColors(fg, bg);
            addNewColortype(WARN_HIGH, warn);
        }

        /* Farben für "grau" erzeugen: */
        {
            Color fg  = new Color(150, 150, 150);
            Color bg  = new Color(255, 255, 255);
            ElementColors grey = new ElementColors(fg, bg);
            addNewColortype(GREY, grey);
        }
    }

    /**
     * Erzeugt eine neue Elementfärbung zum gegebenen Farbtyp.
     *
     * @param type
     *            Farbtyp.
     * @param elementColors
     *            Elementfarben
     * @return true: wurde erfolgreich eingetragen, false: type schon verwendet.
     */
    public boolean addNewColortype(String type, ElementColors elementColors) {
        if (colors.containsKey(type)) {
            return false;
        }
        else {
            colors.put(type, elementColors);
            return true;
        }
    }

    /**
     * Überschreibt einen vorhandenen Farbtyp.
     *
     * @param type
     *            Farbtyp.
     * @param elementColors
     *            Elementfarben
     * @return true: wurde erfolgreich überschrieben, false: type unbekannt.
     */
    public boolean overwriteColortype(String type, ElementColors elementColors) {
        if (colors.containsKey(type)) {
            colors.put(type, elementColors);
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * Setzen von Farben für verschiedene Farbarten. Auf diese Weise kann ein
     * Aufrufer die Defaultfarben, die im Konstruktor vergeben werden, ändern.
     *
     * @param type
     *            Art der Einfärbung.
     * @param elementColors
     *            Die Farben eines Elements der grafischen Benutzeroberfläche.
     */
    public void setColorsForType(String type, ElementColors elementColors) {
        colors.put(type, elementColors);
    }

    /** Getter für die Standard-Vordergrundfarbe. */
    public Color getForegroundColor() {
        return colors.get(GENERAL).getForegroundColor();
    }

    /** Getter für die Standard-Hintergrundfarbe. */
    public Color getBackgroundColor() {
        return colors.get(GENERAL).getBackgroundColor();
    }

    /**
     * Getter für eine bestimmte Vordergrundfarbe.
     *
     * @param type
     *            Art der Einfärbung.
     */
    public Color getForegroundColor(String type) {
        ElementColors elementColors = colors.get(type);
        Color foregroundColor = elementColors.getForegroundColor();
        return foregroundColor;
    }

    /**
     * Getter für eine bestimmte Hintergrundfarbe.
     *
     * @param type
     *            Art der Einfärbung.
     */
    public Color getBackgroundColor(String type) {
        ElementColors elementColors = colors.get(type);
        Color backgroundColor = elementColors.getBackgroundColor();
        return backgroundColor;
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben auf die Standardwerte.
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColors(Component component) {
        setColorsOfComponentByType(GENERAL, component);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben für richtige Dinge (grün).
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsRight(Component component) {
        setColorsOfComponentByType(RIGHT, component);
    }


    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben für falsche Dinge (rot).
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsWrong(Component component) {
        setColorsOfComponentByType(WRONG, component);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben für fragliche Dinge (gelb).
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsWarn(Component component) {
        setColorsOfComponentByType(WARN, component);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben für sehr fragliche Dinge (orange).
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsWarnHigh(Component component) {
        setColorsOfComponentByType(WARN_HIGH, component);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben für graue Dinge (grau).
     *
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsGrey(Component component) {
        setColorsOfComponentByType(GREY, component);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben entsprechend dem Farbtyp.
     *
     * @param type
     *            Art der Einfärbung.
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setColorsOfComponentByType(String type, Component component) {
        ElementColors elementColors = colors.get(type);

        Color foregroundColor = elementColors.getForegroundColor();
        Color backgroundColor = elementColors.getBackgroundColor();

        component.setForeground(foregroundColor);
        component.setBackground(backgroundColor);
    }

    /**
     * Setzt in der übergebenen Komponente die Vordergrund- und
     * Hintergrundfarben invers entsprechend dem Farbtyp, d.h. das Vorder-
     * und Hintergrundfarbe vertauscht wird.
     *
     * @param type
     *            Art der Einfärbung.
     * @param component
     *            Zu bearbeitende Komponente.
     */
    public void setInverseColorsOfComponentByType(String type, Component component) {
        ElementColors elementColors = colors.get(type);

        Color foregroundColor = elementColors.getBackgroundColor();
        Color backgroundColor = elementColors.getForegroundColor();

        component.setForeground(foregroundColor);
        component.setBackground(backgroundColor);
    }

    /**
     * Setzt einen Standardrahmen mit Titel eines Panels in der richtigen Farbe.
     *
     * @param panel
     *            Der zu bearbeitende Panel.
     * @param title
     *            Titel des Panels.
     */
    public void setStandardBorder(JPanel panel, String title) {
        Color color = getForegroundColor();
        GuiTools.createTitle(title, panel, color);
    }

    /**
     * Bildet aus einer Java-Farbe einen HTML-Farbwert in der Form #FFF00.
     *
     * @param color
     *            Java-Farbe.
     * @return HTML-Farbwert
     */
    public String getHTMLColor(Color color) {
        String result = "#" + ColorTool.javaColorToHexColor(color);
        return result;
    }

    /**
     * Setzt für ein Textfeld die Farben.
     *
     * @param field
     *            Textfeld.
     */
    public void setEditFieldColors(JTextComponent field) {
        GuiTools.setEditFieldColors(field);
        // Kann gern überschrieben werden!
    }

    /**
     * Setzt für eine Textarea die Farben und die Schriftart auf Monospaced und 14 Punkt.
     *
     * @param area
     *            Textarea.
     */
    public void setEditAreaColors(JTextArea textArea) {
        GuiTools.setEditAreaColors(textArea);
        // Kann gern überschrieben werden!
    }

}
