package de.duehl.swing.ui.buttons.painted.state;

/*
 * Copyright 2025 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.BasicStroke;
import java.awt.Color;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.List;

import de.duehl.swing.ui.geometry.PixelPoint;

/**
 * Diese Klasse stellt einen kleinen Schalter dar, der einen Stern darstellt.
 *
 * Er kann zwei Zustände darstellen, ausgewählt und nicht ausgewählt. Ist der Zustand aktiviert,
 * wird der Stern ausgefüllt, anderenfalls ist nur dessen Rand zu sehen.
 *
 * @version 1.01     2025-07-24
 * @author Christian Dühl
 */

final public class StarButton extends PaintedStateButton {

    private static final long serialVersionUID = 1L;

    private static final int LINE_WIDTH = 1;
    private static final boolean SHOW_AREA_RECTANGLE = false;
    private static final double INNER_FROM_OUTER_RATION = 40.0d/100.0d;
    private static final int CORRECTION_TO_RADIUS = 2;
    private static final int CORRECTION_TO_CENTER_X = 0;
    private static final int CORRECTION_TO_CENTER_Y = 0;


    /** Die Anzahl der dargestellten Zacken des Sterns. */
    private int spikeNumber;

    /** Konstruktor mit schwarzer Farbe und fünf Ecken. */
    public StarButton() {
        this(5);
    }

    /**
     * Konstruktor mit schwarzer Farbe.
     *
     * @param number
     *            Die Anzahl der dargestellten Ecken.
     */
    public StarButton(int number) {
        this(Color.BLACK, number);
    }

    /**
     * Konstruktor.
     *
     * @param color
     *            Die Farbe.
     * @param number
     *            Die Anzahl der dargestellten Ecken.
     */
    public StarButton(Color color, int number) {
        super(color);
        this.spikeNumber = number;
    }

    /** Zeichnet das Symbol in horizontaler und rechteckiger Anordnung. */
    @Override
    protected void paintHorizontalSymbolRectangle() {
        paintSymbol();
    }

    /** Zeichnet das Symbol in vertikaler und rechteckiger Anordnung. */
    @Override
    protected void paintVerticalSymbolRectangle() {
        paintSymbol();
    }

    /** Zeichnet das Symbol in horizontaler und quadratischer Anordnung. */
    @Override
    protected void paintHorizontalSymbolSquare() {
        paintSymbol();
    }

    /** Zeichnet das Symbol in vertikaler und quadratischer Anordnung. */
    @Override
    protected void paintVerticalSymbolSquare() {
        paintSymbol();
    }

    /**
     * Zeichnet den Stern. Da es dabei egal ist, ob horizontal oder vertikal, wird es in beiden
     * Fällen verwendet.
     */
    private void paintSymbol() {
        int width = getWidth();
        int height = getHeight();

        if (isForceSquare()) {
            width = Math.min(width, height);
            height = width;
        }

        int delta = 6;

        int firstLeftPixel = (getWidth() - width)/2;
        int left = firstLeftPixel + delta;

        int lastRightPixel = firstLeftPixel + width - 1;
        int right = lastRightPixel - delta;

        int firstUpperPixel = (getHeight() - height)/2;
        int upper = firstUpperPixel + delta;

        int lastLowerPixel = firstUpperPixel + height - 1;
        int lower = lastLowerPixel - delta;

        if (SHOW_AREA_RECTANGLE) {
            paintLine(new PixelPoint(left, upper), new PixelPoint(right, upper));
            paintLine(new PixelPoint(right, upper), new PixelPoint(right, lower));
            paintLine(new PixelPoint(left, upper), new PixelPoint(left, lower));
            paintLine(new PixelPoint(left, lower), new PixelPoint(right, lower));
        }

        int innerWidth = right - left;
        int innerHeight = lower - upper;
        int centerX = CORRECTION_TO_CENTER_X + left + innerWidth / 2;
        int centerY = CORRECTION_TO_CENTER_Y + upper + innerHeight / 2;

        int halfSmallerWidthOrHeight = Math.min(width, height) / 2;
        int outerRadius = CORRECTION_TO_RADIUS + halfSmallerWidthOrHeight - delta;
        int innerRadius = (int) (outerRadius * INNER_FROM_OUTER_RATION);


        double angle = Math.toRadians(-90); // Start oben
        double angleStep = Math.PI / spikeNumber;

        List<PixelPoint> points = new ArrayList<>();
        for (int i = 0; i < spikeNumber * 2; i++) {
            double radius = (i % 2 == 0) ? outerRadius : innerRadius;
            double x = centerX + Math.cos(angle) * radius;
            double y = centerY + Math.sin(angle) * radius;

            points.add(new PixelPoint((int) x, (int) y));
            angle += angleStep;
        }

        // Glättung aktivieren
        graphics2.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON));
        graphics2.setStroke(
                new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));

        if (isElected()) {
            paintPolygon(points);
        }
        else {
            paintHollowPolygon(points);
        }
    }

}
