package de.duehl.swing.ui.elements.arrowselector;

/*
 * Copyright 2016 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.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ButtonGroup;
import javax.swing.JPanel;

/**
 * Diese Klasse stellt eine Komponente dar, auf der man eine Pfeiltaste
 * auswählen kann. In der Mitte steht ein Rechteck zur Verfügung.
 *
 * Siehe http://forum.byte-welt.net/threads/12503-Eigene-Checkbox-erstellen
 * den Post von Timothy_Truckle.
 *
 * @version 1.01     2014-07-24
 * @author Christian Dühl
 */

public class ArrowSelector extends JPanel {

    private static final long serialVersionUID = -5111966252366706268L;

    /** Defaultfarbe für selektierte Pfeile. */
    static final Color SELECTED_COLOR = Color.YELLOW;

    /** Defaultfarbe für nicht selektierte Pfeile. */
    static final Color NOT_SELECTED_COLOR = Color.BLUE;

    /** Maximale Anzahl an Pfeilen pro Seite. */
    static final int MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE = 9;

    /** Farbe für selektierte Pfeile. */
    private final Color selectedColor;

    /** Farbe für nicht selektierte Pfeile. */
    private final Color notSelectedColor;

    /**
     * Platz des Pfeils der am weitesten links ist (negative Zahl, wenn Pfeile
     * links da sein sollen).
     */
    private final int leftestArrowPlace;

    /**
     * Platz des Pfeils der am weitesten rechts ist (positive Zahl, wenn Pfeile
     * rechts da sein sollen).
     */
    private final int rightetsArrowPlace;

    /** Verwaltung der Listener. */
    private final List<ArrowSelectorListener> listeners;

    /** Konstruktor. */
    public ArrowSelector() {
        this(SELECTED_COLOR, NOT_SELECTED_COLOR,
                -MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE,
                MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE);
    }

    /**
     * Konstruktor.
     *
     * @param selectedColor
     *            Farbe für selektierte Pfeile.
     * @param notSelectedColor
     *            Farbe für nicht selektierte Pfeile.
     */
    public ArrowSelector(final Color selectedColor,
            final Color notSelectedColor) {
        this(selectedColor, notSelectedColor,
                -MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE,
                MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE);
    }

    /**
     * Konstruktor.
     *
     * @param leftestArrowPlace
     *            Platz des Pfeils der am weitesten links ist (negative Zahl,
     *            wenn Pfeile links da sein sollen).
     * @param rightetsArrowPlace
     *            Platz des Pfeils der am weitesten rechts ist (positive Zahl,
     *            wenn Pfeile rechts da sein sollen).
     */
    public ArrowSelector(final int leftestArrowPlace,
            final int rightetsArrowPlace) {
        this(SELECTED_COLOR, NOT_SELECTED_COLOR,
                leftestArrowPlace, rightetsArrowPlace);
    }

    /**
     * Konstruktor.
     *
     * @param selectedColor
     *            Farbe für selektierte Pfeile.
     * @param notSelectedColor
     *            Farbe für nicht selektierte Pfeile.
     * @param leftestArrowPlace
     *            Platz des Pfeils der am weitesten links ist (negative Zahl,
     *            wenn Pfeile links da sein sollen).
     * @param rightetsArrowPlace
     *            Platz des Pfeils der am weitesten rechts ist (positive Zahl,
     *            wenn Pfeile rechts da sein sollen).
     */
    public ArrowSelector(final Color selectedColor,
            final Color notSelectedColor, final int leftestArrowPlace,
            final int rightetsArrowPlace) {
        super(new GridLayout(1, 0));

        this.selectedColor = selectedColor;
        this.notSelectedColor = notSelectedColor;
        this.leftestArrowPlace = leftestArrowPlace;
        this.rightetsArrowPlace = rightetsArrowPlace;
        listeners = new ArrayList<>();

        if (-leftestArrowPlace > MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE) {
            throw new IllegalArgumentException("Zu viele Pfeile links "
                    + "gewählt. Maximal sind "
                    + MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE
                    + " erlaubt, gewählt wurden " + (-leftestArrowPlace) + ".");
        }
        if (rightetsArrowPlace > MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE) {
            throw new IllegalArgumentException("Zu viele Pfeile rechts "
                    + "gewählt. "
                    + "Maximal sind " + MAXIMAL_NUMBER_OF_ARROWS_PER_SIDE
                    + " erlaubt, gewählt wurden " + rightetsArrowPlace + ".");
        }

        createArrows();
        setPreferredSize(new Dimension(4 * 190, 4 * 10));
    }

    /** Erstellt die anzuzeigenden Pfeile. */
    private void createArrows() {
        ButtonGroup buttonGroup = new ButtonGroup();
        for (int place = leftestArrowPlace;
                place <= rightetsArrowPlace; place++) {
            addButton(buttonGroup, place);
        }
    }

    /**
     * Erzeugt einen Pfeil.
     *
     * @param buttonGroup
     *            Gruppe, zu der der Pfeil-Button hinzugefügt wird.
     * @param place
     *            Platz des Pfeiles.
     */
    private void addButton(final ButtonGroup buttonGroup, final int place) {
        ArrowButton button = new ArrowButton(this, place,
                selectedColor, notSelectedColor);
        button.setName(String.format("%s", place));
        button.setRolloverEnabled(false);
        button.setPressedIcon(null);
        button.setSelectedIcon(null);
        button.setPressedIcon(null);
        add(button);
        buttonGroup.add(button);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (ArrowSelectorListener listener : listeners) {
                    listener.reactOnButtonSelection(place);
                }
            }
        });
    }

    /**
     * Fügt einen Listener zu der Liste der Listener hinzu.
     *
     * @param listener
     *            Hinzuzufügender Listener.
     */
    public void addArrowSelectorListener(
             final ArrowSelectorListener listener) {
        listeners.add(listener);
    }

}
