// klasa reprezentująca koło o niezmiennym położeniu i promieniu
public class Circle implements Comparable<Circle> {
    // pola do przechowywania współrzędnych środka i długości promienia
    // są prywatne ze względu na hermetyzację i finalne ze względu na niezmienność
    private final int x, y, r;

    // podstawowy konstruktor: inicjuje pola określonymi wartościami
    public Circle(int x, int y, int r) {
        if (r < 0) throw new IllegalArgumentException("Ujemny promień." );
        this.x = x; this.y = y; this.r = r;
    }

    // konstruktor kopiujący — przydatna alternatywa dla metody clone()
    public Circle(Circle original) {
        x = original.x;  // kopiuje pola oryginału
        y = original.y;
        r = original.r;
    }

    // publiczne metody dostępu do pól prywatnych
    // stanowią element hermetyzacji danych
    public int getX() { return x; }
    public int getY() { return y; }
    public int getR() { return r; }

    // zwraca reprezentację łańcuchową
    @Override public String toString() {
        return String.format("środek=(%d,%d); promień=%d" , x, y, r);
    }

    // porównuje dwa obiekty
    @Override public boolean equals(Object o) {
        // Identyczne referencje?
        if (o == this) return true;
        // Prawidłowy typ i nie null?
        if (!(o instanceof Circle)) return false;
        Circle that = (Circle) o;  // rzutowanie na nasz typ
        if (this.x == that.x && this.y == that.y && this.r == that.r)
            return true;  // jeśli wszystkie pola pasują
        else
            return false;  // jeśli pola się różnią
    }

    // Wartość skrótu pozwala na użycie obiektu w tablicy skrótów.
    // Równe obiekty muszą mieć takie same skróty. Nierówne obiekty
    // też mogą mieć takie same skróty, ale staramy się tego unikać.
    // Musimy przesłonić tę metodę, ponieważ przesłoniliśmy już equals().
    @Override public int hashCode() {
        int result = 17;         // algorytm obliczania skrótu z książki
        result = 37*result + x;  // Java. Efektywne programowanie Joshuy Blocha
        result = 37*result + y;
        result = 37*result + r;
        return result;
    }

    // Ta metoda jest zdefiniowana przez interfejs Comparable. Porównuje
    // jedno koło z innym. Zwraca wartość < 0, jeśli this < that.
    // Zwraca 0, jeżeli this == that. Zwraca wartość > 0, jeśli this > that.
    // Koła są uporządkowane od góry i od lewej oraz wg promienia.
    public int compareTo(Circle that) {
        // Mniejsze koła mają większą wartość y.
        long result = (long)that.y - this.y;
        // jeśli brak różnicy, porównuje od lewej do prawej
        if (result==0) result = (long)this.x - that.x;
        // jeśli brak różnicy, porównuje promienie
        if (result==0) result = (long)this.r - that.r;

        // Do odejmowania trzeba użyć wartości typu long, ponieważ
        // różnice między dużymi wartościami dodatnimi i dużymi wartościami ujemnymi
        // mogą przekroczyć zakres typu int. Ale nie możemy zwrócić typu long,
        // więc zwracamy tylko znak jako wartość typu int.
        return Long.signum(result);
    }
}
