/home/caleb/ASDV-Java/Semester 2/Assignments/MP2_CalebFontenot/src/main/java/com/calebfontenot/mp2_calebfontenot/Circle2D.java
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.calebfontenot.mp2_calebfontenot;

/**
 *
 * @author caleb
 */
public class Circle2D {

    private double x;
    private double y;
    private double radius;
    private String name;

    /**
     * Get the value of name
     *
     * @return the value of name
     */
    public String getName() {
        return name;
    }

    public Circle2D() {
        this.x = this.y = 0;
        this.radius = 1;
        this.name = "Default Circle";
    }

    public Circle2D(double x, double y, double radius, String name) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.name = name;
    }

    public Circle2D(double x, double y, double radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    /**
     * Get the value of x
     *
     * @return the value of x
     */
    public double getX() {
        return x;
    }

    /**
     * Get the value of y
     *
     * @return the value of y
     */
    public double getY() {
        return y;
    }

    /**
     * Get the value of radius
     *
     * @return the value of radius
     */
    public double getRadius() {
        return radius;
    }

    public double getArea() {
        return Math.PI * this.radius * this.radius;
    }

    public double getPerimeter() {
        return 2 * Math.PI * this.radius;
    }

    @Override
    public String toString() {
        return name + "{" + "x=" + x + ", y=" + y + ", radius=" + radius + " }";
    }

    @Override
    public int hashCode() {
        int hash = 5;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Circle2D other = (Circle2D) obj;
        if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
            return false;
        }
        if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
            return false;
        }
        return Double.doubleToLongBits(this.radius) == Double.doubleToLongBits(other.radius);
    }

    /**
     * Determines if a point is inside the circle.
     *
     * @param x
     * @param y
     * @return true if the specified point (x, y) is inside the circle, otherwise false.
     */
    public boolean contains(Circle2D other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        double distance = Math.sqrt(dx * dx + dy * dy);

        return distance + other.radius <= this.radius;
    }

    /**
     * Determines if this circle overlaps with parameter circle.
     *
     * @param circle to compare for overlapping.
     * @return true
     */
    public boolean overlaps(Circle2D other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        double distance = Math.sqrt(dx * dx + dy * dy);

        return distance <= this.radius + other.radius;
    }

    /**
     *
     * @param x1 x of point 1
     * @param y1 x of point 1
     * @param x2 x of point 1
     * @param y2 x of point 1
     * @return the distance between the two points
     */
    private static double distance(double x1, double y1, double x2, double y2) {
        return Math.sqrt((x1 - x2) * (x1) * (x1 - x2)
                + (y1 - y2) * (y1 - y2));
    }

    /**
     * Sort the array in ascending order by perimeter i=size;
     *
     * @param array the array to be used for sorting, not altered.
     * @return a new sorted array;
     */
    public static Circle2D[] sortCirclesByPerimeter(Circle2D[] oldArray) {
        Circle2D[] array = new Circle2D[oldArray.length];
        System.arraycopy(oldArray, 0, array, 0, oldArray.length);
        for (int i = 0; i < array.length - 1; ++i) {
            for (int j = i + 1; j < array.length; ++j) {
                double perimeter1 = array[i].getPerimeter();
                double perimeter2 = array[j].getPerimeter();
                if (perimeter1 > perimeter2) {
                    Circle2D temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
        return array;
    }

    public static void printPerimeter(Circle2D[] array) {
        for (Circle2D circle : array) {
            System.out.println(circle.name + " " + circle.getPerimeter());
        }
        System.out.println();
    }

    /**
     * Sort the array in ascending order by perimeter size. Returns a new sorted array. You compare every circle with all other circles. If it overlaps with all others it should be placed first.
     *
     * @param array The array used for sorting.
     * @return
     */
    public static int[] circleOverlap(Circle2D[] array) {
        int[] overlapCount = new int[array.length];
        // count the number of times each circle overlaps
        for (int i = 0; i < array.length; ++i) {
            for (int j = 0; j < array.length; ++j) {
                if (i != j && array[i].overlaps(array[j])) {
                    overlapCount[i]++;
                }
            }
        }
        return overlapCount;
    }

    public static Circle2D[] sortCirclesByNumberOfTimesOverlapping(Circle2D[] array) {
        int[] overlapCount = circleOverlap(array);

        // count the number of times each circle overlaps
        for (int i = 0; i < array.length; ++i) {
            for (int j = 0; j < array.length; ++j) {
                if (i != j && array[i].overlaps(array[j])) {
                    overlapCount[i]++;
                }
            }
        }
        for (int i = 0; i < array.length; i++) {
            int min = i;
            for (int j = i + 1; j < array.length; j++) {
                if (overlapCount[j] < overlapCount[min]) {
                    min = j;
                }
                if (overlapCount[j] == overlapCount[min]) {
                    if (array[j].getPerimeter() < array[min].getPerimeter()) {
                        min = j;
                    }
                }
            }
            // swap the elements
            int tmpCount = overlapCount[i];
            overlapCount[i] = overlapCount[min];
            overlapCount[min] = tmpCount;

            Circle2D temp = array[i];
            array[i] = array[min];
            array[min] = temp;
        }
        print(circleOverlap(array));
        return array;
    }

    public static void print(Circle2D[] array) {
        for (Circle2D circle : array) {
            System.out.println(circle);
        }
    }

    public static void print(int[] array) {
        for (int circle : array) {
            System.out.println(circle);
        }
    }

    public static void print(Circle2D[] array, Circle2D c1) {
        for (Circle2D circle : array) {
            System.out.println(circle);
            System.out.println("c1.contains: " + c1.contains(circle));
            System.out.println("c1.overlaps: " + c1.overlaps(circle));
        }
    }

    public static Circle2D[] createArrayOfCircle() {
        Circle2D[] circleArray = new Circle2D[8];
        circleArray[0] = new Circle2D(0, 0, 1, "c1");
        circleArray[1] = new Circle2D(1, 1, 2, "c2");
        circleArray[2] = new Circle2D(3.2, -2.2, 1.2, "c3");
        circleArray[3] = new Circle2D(4.2, 0, 4, "c4");
        circleArray[4] = new Circle2D(-7, 5, 4.5, "c5");
        circleArray[5] = new Circle2D(19, 1, 10, "c6");
        circleArray[6] = new Circle2D(1, 8.8, 3, "c7");
        circleArray[7] = new Circle2D(4.1, 9.1, 1.3, "c8");
        return circleArray;
    }

    public static void main(String[] args) {
        Circle2D c1 = new Circle2D(2, 2, 5.5);
        //System.out.println(c1);
        //System.out.println("Area is " + c1.getArea());
        //System.out.println("Perimeter is " + c1.getPerimeter());
        Circle2D[] circleArray = createArrayOfCircle();
        System.out.println();
        printPerimeter(circleArray);
        Circle2D[] sortedArray = sortCirclesByPerimeter(circleArray);
        printPerimeter(sortedArray);
        print(circleArray);
        System.out.println();
        Circle2D[] overlapArray = Circle2D.sortCirclesByNumberOfTimesOverlapping(circleArray);
        print(overlapArray);

    }

}