package math.prime;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

/**
 * kreslenie spirali kwadratowej;
 */
public class SpiralaUlama extends JPanel {
    private final int h;
    private final int w;
    private static final long serialVersionUID = 4145929212344860830L;
    private static final Font font = new Font("Dialog", Font.PLAIN, 9);

    public SpiralaUlama(int w, int h) {
        this.w = w;
        this.h = h;
        setPreferredSize(new Dimension(w, h));
        setBounds(0, 0, w, h);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        spiralaKwadratowa(g2, Color.BLUE, 20);
    }

    /**
     * Rysuje spiralę kwadratową
     *
     * @param g2  Graphics2D - obiekt rysujący
     * @param col Color - kolor spirali
     * @param lg  int - długość pierwszego odcinka
     */
    public void spiralaKwadratowa(Graphics2D g2, Color col, int lg) {
        Point2D.Float point = new Point2D.Float(this.w / 2.0f, (this.h / 2.0f));
        int i = 1;
        int counter = 1;
        g2.setColor(Color.RED);
        g2.setFont(font);
        Point2D.Float old;
        while ((i + 1) * lg < this.w - 60) {
            old = new Point2D.Float(point.x, point.y);
            point = drawLine(g2, col, point, 1, i * lg);
            counter = drawPoints(g2, Color.RED, old, 1, i * lg, lg, counter);
            old = new Point2D.Float(point.x, point.y);
            point = drawLine(g2, col, point, 2, i * lg);
            counter = drawPoints(g2, Color.RED, old, 2, i * lg, lg, counter);
            old = new Point2D.Float(point.x, point.y);
            point = drawLine(g2, col, point, 3, (i + 1) * lg);
            counter = drawPoints(g2, Color.RED, old, 3, (i + 1) * lg, lg,
                    counter);
            old = new Point2D.Float(point.x, point.y);
            point = drawLine(g2, col, point, 4, (i + 1) * lg);
            counter = drawPoints(g2, Color.RED, old, 4, (i + 1) * lg, lg,
                    counter);
            i += 2;
        }
    }

    public int drawPoints(Graphics2D g2, Color color, Point2D.Float point,
                          int dir, int len, int lg, int counter) {
        g2.setColor(color);
        g2.setFont(font);
        float x1;
        float y1;
        int ile = len / lg;
        switch (dir) {
            case 1:
                for (int i = 1; i < ile + 1; i++) {
                    counter++;
                    x1 = point.x + i * lg;
                    y1 = point.y;
                    g2.drawString(PrimeUtil.isPrime(counter)
                            ? String.valueOf(counter)
                            : "", x1, y1);
                }
                break;
            case 2:
                for (int i = 1; i < ile + 1; i++) {
                    counter++;
                    x1 = point.x;
                    y1 = point.y - i * lg;
                    g2.drawString(PrimeUtil.isPrime(counter)
                            ? String.valueOf(counter)
                            : "", x1, y1);
                }
                break;
            case 3:
                for (int i = 1; i < ile + 1; i++) {
                    counter++;
                    x1 = point.x - i * lg;
                    y1 = point.y;
                    g2.drawString(PrimeUtil.isPrime(counter)
                            ? String.valueOf(counter)
                            : "", x1, y1);
                }
                break;
            case 4:
                for (int i = 1; i < ile + 1; i++) {
                    counter++;
                    x1 = point.x;
                    y1 = point.y + i * lg;
                    g2.drawString(PrimeUtil.isPrime(counter)
                            ? String.valueOf(counter)
                            : "", x1, y1);
                }
                break;
        }
        return counter;
    }

    public Point2D.Float drawLine(Graphics2D g2, Color color,
                                  Point2D.Float point, int dir, int len) {
        g2.setColor(color);
        float x1 = 0;
        float y1 = 0;
        switch (dir) {
            case 1:
                x1 = point.x + len;
                y1 = point.y;
                break;
            case 2:
                x1 = point.x;
                y1 = point.y - len;
                break;
            case 3:
                x1 = point.x - len;
                y1 = point.y;
                break;
            case 4:
                x1 = point.x;
                y1 = point.y + len;
                break;
        }
        Line2D.Float line = new Line2D.Float(point.x, point.y, x1, y1);
        g2.draw(line);
        return new Point2D.Float(x1, y1);
    }
}
