package cse1030.test1;

import static org.junit.Assert.*;

import org.junit.Test;

import cse1030.drawing.IPoint2D;

public class CircleTester {

  @Test
  public void testBadRadius() {
    try {
      Circle c = new Circle(new IPoint2D(), 0.0);
      fail("radius must be bigger than zero");
    }
    catch (IllegalArgumentException ex) {
    }
    try {
      Circle c = new Circle(new IPoint2D(), -Double.MIN_NORMAL);
      fail("radius must not be negative");
    }
    catch (IllegalArgumentException ex) {
    }
  }

  @Test
  public void testDefaultCtor() {
    Circle c = new Circle();
    assertTrue("circle center is not (0.0, 0.0)", c.getCenter().equals(new IPoint2D()));
    assertTrue("circle radius is not 1.0", c.getRadius() == 1.);
  }

  @Test
  public void testCopyCtor() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 3.1;
    Circle other = new Circle(center, r);
    Circle c = new Circle(other);
    assertTrue("circle center not copied correctly", c.getCenter().equals(center));
    assertTrue("circle radius not copied correctly", c.getRadius() == r);
  }

  @Test
  public void testGetCenter() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 3.1;
    Circle c = new Circle(center, r);
    assertTrue("circle center not set correctly", c.getCenter().equals(center));
  }

  @Test
  public void testGetRadius() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 3.1;
    Circle c = new Circle(center, r);
    assertTrue("circle radius not set correctly", c.getRadius() == r);
  }

  @Test
  public void testCompareTo() {
    final IPoint2D center1 = new IPoint2D(-1.0, 2.0);
    final double r1 = 3.1;
    Circle c1 = new Circle(center1, r1);
    
    final IPoint2D center2 = new IPoint2D(1.1, -2.1);
    final double r2 = r1 + Math.ulp(r1);
    Circle c2 = new Circle(center2, r2);
    
    final IPoint2D center3 = new IPoint2D(-1.5, 2.3);
    final double r3 = r2 + Math.ulp(r2);
    Circle c3 = new Circle(center3, r3);
    
    final IPoint2D center4 = new IPoint2D(-1.5, 2.3);
    final double r4 = r1;
    Circle c4 = new Circle(center4, r4);
    
    assertTrue("compareTo failed to return a negative value", c1.compareTo(c2) < 0);
    assertTrue("compareTo failed to return a negative value", c2.compareTo(c3) < 0);
    assertTrue("compareTo failed to return a negative value", c1.compareTo(c3) < 0);
    
    assertTrue("compareTo failed to return a positive value", c3.compareTo(c1) > 0);
    assertTrue("compareTo failed to return a positive value", c3.compareTo(c2) > 0);
    assertTrue("compareTo failed to return a positive value", c2.compareTo(c1) > 0);
    
    assertTrue("compareTo failed to return zero", c1.compareTo(c4) == 0);
    assertTrue("compareTo failed to return zero", c1.compareTo(c1) == 0);
    assertTrue("compareTo failed to return zero", c2.compareTo(c2) == 0);
    assertTrue("compareTo failed to return zero", c3.compareTo(c3) == 0);
  }

  @Test
  public void testEqualsObject() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 3.1;
    Circle c = new Circle(center, r);
    try {
      assertFalse("c.equals(null) returned true", c.equals(null));
    }
    catch (Exception ex) {
      fail("equals must not throw an exception");
    }
    
    try {
      assertFalse("c.equals(\"\") returned true", c.equals(""));
    }
    catch (Exception ex) {
      fail("equals must not throw an exception");
    }
    
    Circle c2 = new Circle(center, r);
    assertTrue("equals returned false for two identical circles", c.equals(c));
    assertTrue("equals returned false for two identical circles", c.equals(c2));
    assertTrue("equals returned false for two identical circles", c2.equals(c));
    
    Circle c3 = new Circle(center, r + 1.);
    assertFalse("equals returned true for two different radii", c.equals(c3));
    assertFalse("equals returned true for two different radii", c3.equals(c));
    
    Circle c4 = new Circle(new IPoint2D(5., 5.), r);
    assertFalse("equals returned true for two different center points", c.equals(c4));
    assertFalse("equals returned true for two different center points", c4.equals(c));
    
    Circle c5 = new Circle(new IPoint2D(5., 5.), r + 1.);
    assertFalse("equals returned true for two different circles", c.equals(c5));
    assertFalse("equals returned true for two different circles", c5.equals(c));
  }

  @Test
  public void testToString() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 3.1;
    Circle c = new Circle(center, r);
    String expected = center + ", " + r;
    assertTrue("toString returned: " + c.toString() + " but expected: " + expected, expected.equals(c.toString()));
  }

  @Test
  public void testWithDiameter() {
    final IPoint2D center = new IPoint2D(-1.0, 2.0);
    final double r = 4.;
    Circle d = Circle.withDiameter(center, 2 * r);
    assertTrue("withDiameter returned a circle with the wrong center", center.equals(d.getCenter()));
    assertTrue("withDiameter returned a circle with the wrong radius", r == d.getRadius());
  }

}
