package math.curve;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;

public class CurveUtil {

    private CurveUtil() {
    }

    /**
     * Rysuje asteroidę
     *
     * @param g2            Graphics2D - obiekt rysujący
     * @param kolor         Color - kolor krzywej
     * @param r             int - promień krzywej
     * @param liczbaPunktow - liczba punktów rysujących krzywą
     */
    public static void asteroida(Graphics2D g2, Color kolor, int r,
                                 int liczbaPunktow) {
        g2.translate(400, 400);
        //g2.scale(1, -1);
        int x1 = r;
        int y1 = 0;
        int x2;
        int y2;
        g2.setColor(kolor);
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = (int) (r * Math.pow(Math.cos(t), 3));
            y2 = (int) (r * Math.pow(Math.sin(t), 3));
            g2.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }
    }

    /**
     * Rysuje rozetę czterolistną
     *
     * @param g2            Graphics2D - obiekt rysujący
     * @param kolor         Color - kolor krzywej
     * @param size          int - promień krzywej
     * @param liczbaPunktow - liczba punktów rysujących krzywą
     */
    public static void rozeta4listna(Graphics2D g2, Color kolor, int size,
                                     int liczbaPunktow) {
        g2.translate(400, 400);
        double x1 = 0;
        double y1 = 0;
        double x2;
        double y2;
        g2.setColor(kolor);
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = 2 * size * Math.sin(t) * Math.pow(Math.cos(t), 2);
            y2 = 2 * size * Math.cos(t) * Math.pow(Math.sin(t), 2);
            g2.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
            x1 = x2;
            y1 = y2;
        }
    }

    /**
     * Rysuje spiralę Archimedesa
     *
     * @param g2            Graphics2D - obiekt rysujący
     * @param kolor         Color - kolor spirali
     * @param dlugosc       int - dlugosc spirali. Zmiana znaku przed tym parametrem
     *                      zmienia kierunek skrętu spirali
     * @param ciasnosc      int - zmniejsza odstępy między skrętami spirali. Zmiana
     *                      znaku przed tym parametrem zmienia miejsce startu i zakończenia spirali
     * @param liczbaPunktow int liczba punktów do narysowania
     */
    public static void spiralaArchimedesa(Graphics2D g2, Color kolor,
                                          int dlugosc, int ciasnosc, int liczbaPunktow) {
        g2.translate(400, 400);
        g2.scale(1, -1);
        int x1 = 0;
        int y1 = 0;
        int x2;
        int y2;
        g2.setColor(kolor);
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * dlugosc * Math.PI / liczbaPunktow;
            x2 = (int) (ciasnosc * t * Math.cos(t));
            y2 = (int) (ciasnosc * t * Math.sin(t));
            g2.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }
    }

    public static void kardioida(Graphics2D g2, Color kolor, int a,
                                 int liczbaPunktow) {
        g2.setColor(kolor);
        g2.translate(400, 400);
        int x1 = a;
        int y1 = 0;
        int x2;
        int y2;
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = (int) (a * (2 * Math.cos(t) - Math.cos(2 * t)));
            y2 = (int) (a * (2 * Math.sin(t) - Math.sin(2 * t)));
            g2.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }
    }

    public static void lissajous(Graphics2D g2, Color kolor, int A1, int A2,
                                 int w1, int w2, double fi1, double fi2, int liczbaPunktow) {
        g2.setColor(kolor);
        g2.translate(400, 400);
        int x1 = (int) (A1 * Math.cos(fi1));
        int y1 = (int) (A2 * Math.cos(fi2));
        int x2;
        int y2;
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = (int) (A1 * Math.cos(w1 * t + fi1));
            y2 = (int) (A2 * Math.cos(w2 * t + fi2));
            g2.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }
    }

    /**
     * Rysuje epicykloidę
     *
     * @param g2            Graphics2D - obiekt rysujący
     * @param kolor         Color - kolor krzywej
     * @param A             int - promień większego koła
     * @param a             int - promień mniejszego koła
     * @param lambda        double:
     * @param liczbaPunktow rysujących krzywą
     *                      <ul>
     *                      <li> lambda > 1 epicykloida wydłużona
     *                      <li>lambda = 1 epicykloida normalna
     *                      <li>lambda < 1 epicykloida skrócona</ul>
     */
    public static void epicykloida(Graphics2D g2, Color kolor, int A, int a,
                                   double lambda, int liczbaPunktow) {
        g2.translate(400, 400);
        double x1 = A - (lambda - 1) * a;
        double y1 = 0;
        double x2;
        double y2;
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = (A + a) * Math.cos(t) - lambda * a * Math.cos((A + a) * t / a);
            y2 = (A + a) * Math.sin(t) - lambda * a * Math.sin((A + a) * t / a);
            g2.setColor(kolor);
            g2.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
            x1 = x2;
            y1 = y2;
        }
    }

    /**
     * Rysuje hipocykloidę
     *
     * @param g2            Graphics2D - obiekt rysujący
     * @param kolor         Color - kolor krzywej
     * @param A             int - promień większego koła
     * @param a             int - promień mniejszego koła
     * @param lambda        double:
     * @param liczbaPunktow - liczba punktów rysujących krzywą
     *                      <ul>
     *                      <li> lambda > 1 hipocykloida wydłużona
     *                      <li>lambda = 1 hipocykloida normalna
     *                      <li>lambda < 1 hipocykloida skrócona </ul>
     */
    public static void hipocykloida(Graphics2D g2, Color kolor, int A, int a,
                                    double lambda, int liczbaPunktow) {
        g2.translate(400, 400);
        double x1 = A + (lambda - 1) * a;
        double y1 = 0;
        double x2;
        double y2;
        a = -a;
        for (int i = 0; i < liczbaPunktow; i++) {
            double t = i * Math.PI / 360;
            x2 = (A + a) * Math.cos(t) - lambda * a * Math.cos((A + a) * t / a);
            y2 = (A + a) * Math.sin(t) - lambda * a * Math.sin((A + a) * t / a);
            g2.setColor(kolor);
            g2.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
            x1 = x2;
            y1 = y2;
        }
    }

    /**
     * Rysuje kwadrat wpisany w kwadrat
     *
     * @param g2  Graphics2D - obiekt rysujący
     * @param col Color - kolor kwadratów
     * @param nn  int - polowa wyswietlanej liczby kwadratow, n = 2 daje 4
     *            kwadraty
     * @param lg  int - długość pierwszego boku
     * @param xx  int - współrzędna x punktu startowego
     * @param yy  int - współrzędna y punktu startowego
     */
    public static void kwadraty(Graphics2D g2, Color col, int nn, int lg,
                                int xx, int yy) {
        if (nn > 0) {
            g2.setColor(col);
            g2.drawLine(xx, yy, xx + lg, yy);
            g2.drawLine(xx + lg, yy, xx + lg, yy + lg);
            g2.drawLine(xx + lg, yy + lg, xx, yy + lg);
            g2.drawLine(xx, yy + lg, xx, yy + lg / 2);
            g2.drawLine(xx, yy + lg / 2, xx + lg / 2, yy + lg);
            g2.drawLine(xx + lg / 2, yy + lg, xx + lg, yy + lg / 2);
            g2.drawLine(xx + lg, yy + lg / 2, xx + lg / 2, yy);
            g2.drawLine(xx + lg / 2, yy, xx + lg / 4, yy + lg / 4);
            kwadraty(g2, col, nn - 1, lg / 2, xx + lg / 4, yy + lg / 4);
            g2.drawLine(xx + lg / 4, yy + lg / 4, xx, yy + lg / 2);
            g2.drawLine(xx, yy + lg / 2, xx, yy);
        }
    }

    /**
     * Rysuje spiralę kwadratową
     *
     * @param g2   Graphics2D - obiekt rysujący
     * @param col  Color - kolor spirali
     * @param lg   int - długość pierwszego odcinka
     * @param xx   int - wpsółrzędna x punktu startowego
     * @param yy   int - współrzędna y punktu startowego
     * @param alfa int - odleglosc między skrętami
     */
    public static void spiralaKwadratowa(Graphics2D g2, Color col, int lg,
                                         int xx, int yy, int alfa) {
        if (lg > 0) {
            g2.setColor(col);
            g2.drawLine(xx, yy, xx + lg, yy);//1 linia
            g2.drawLine(xx + lg, yy, xx + lg, yy + lg);//2 linia
            g2.drawLine(xx + lg, yy + lg, xx + alfa, yy + lg);//3 linia
            g2.drawLine(xx + alfa, yy + lg, xx + alfa, yy + alfa);//4 linia
            spiralaKwadratowa(g2, col, lg - 2 * alfa, xx + alfa, yy + alfa,
                    alfa);//nastepny segment
        }
    }

    /**
     * Rysuje szachownicę
     *
     * @param comp JComponent - komponent, w którym zostanie narysowana
     *             szachownica
     * @param g2   Graphics2D - obiekt rysujący
     */
    public static void drawChessboard(JComponent comp, Graphics2D g2) {
        comp.setBackground(Color.WHITE);
        double width = comp.getWidth();
        double height = comp.getHeight();
        Rectangle2D r = new Rectangle2D.Double(0, 0, width / 8.0, height / 8.0);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                if ((i + j) % 2 == 0) {
                    g2.draw(r);
                } else {
                    g2.fill(r);
                }
                g2.translate(width / 8.0, 0);
            }
            g2.translate(-width, height / 8.0);
        }
    }
}
