content: package net.gcdc.geonetworking;
  
  import static net.gcdc.geonetworking.AreaTest.Support.areaParamToBytes;
  import static net.gcdc.geonetworking.AreaTest.Support.asBinaryString;
  import static net.gcdc.geonetworking.AreaTest.Support.getAreaByteBuffer;
  import static org.junit.Assert.assertArrayEquals;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;
  
  import java.nio.ByteBuffer;
  import nl.jqno.equalsverifier.EqualsVerifier;
  import org.junit.Test;
  
  public class AreaTest {
  
    private static final boolean LOGGING = false;
  
    @Test
    public void testArea() {
      // check lat position
      for (int i = 0; i < 180; i++) {
        int lat = i - 90;
        testAreaPosition(lat, 0);
      }
  
      // check lon position
      for (int i = 0; i < 360; i++) {
        int lon = i - 180;
        testAreaPosition(0, lon);
      }
  
      // check distance
      for (int distance = 0; distance <= 65535; distance++) {
        testAreaDistance(distance);
      }
  
      // check degrees
      for (int degrees = 0; degrees < 359; degrees++) {
        testAreaDegrees(degrees);
      }
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testAreaDegreesMaxOver() {
      int degrees = 361;
      testAreaDegrees(degrees);
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testAreaDegreesMinOver() {
      int degrees = -1;
      testAreaDegrees(degrees);
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testAreaDistanceMaxOver() {
      int distance = 65536;
      testAreaDistance(distance);
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testAreaDistanceMinUnder() {
      int distance = -1;
      testAreaDistance(distance);
    }
  
    @Test
    public void testAreaTypes() {
      // Position slottsberget   = new Position(57.702878, 11.927723);
      // Position damen          = new Position(57.703864, 11.945876);
      Position sannegordshamn = new Position(57.708769, 11.927088);
      Position semcon         = new Position(57.709526, 11.943996);
      Position teater         = new Position(57.705714, 11.934608);
      Position jarntorget     = new Position(57.699786, 11.953191);
      Position kuggen         = new Position(57.706700, 11.938955);
  
      Area teaterSemcon = Area.ellipse(teater, 800, 400, 52);
      assertTrue(teaterSemcon.contains(semcon));
      assertFalse(teaterSemcon.contains(jarntorget));
  
      Area teaterTowardsKuggen = Area.ellipse(teater, 285, 50, 66);
      assertTrue(teaterTowardsKuggen.contains(kuggen));
      assertFalse(teaterTowardsKuggen.contains(semcon));
  
      Area teaterTowardsKuggenRect = Area.rectangle(teater, 285, 50, 66);
      assertTrue(teaterTowardsKuggenRect.contains(kuggen));
      assertFalse(teaterTowardsKuggenRect.contains(semcon));
      assertFalse(teaterTowardsKuggenRect.contains(sannegordshamn));
  
      Area aroundTeaterUpToKuggen = Area.circle(teater, 285);
      // assertTrue(aroundTeaterUpToKuggen.contains(kuggen));
      assertFalse(aroundTeaterUpToKuggen.contains(semcon));
    }
  
    @Test
    public void testEquality() {
      EqualsVerifier.forClass(Area.class).verify();
    }
  
    @Test
    public void testType() {
      assertEquals(Area.Type.CIRCLE, Area.Type.fromCode(0));
      assertEquals(Area.Type.RECTANGLE, Area.Type.fromCode(1));
      assertEquals(Area.Type.ELLIPSE, Area.Type.fromCode(2));
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testTypeUnknownMaxAbove() {
      Area.Type.fromCode(3);
    }
  
    @Test(expected = IllegalArgumentException.class)
    public void testTypeUnknownMinBelow() {
      Area.Type.fromCode(-1);
    }
  
    private void testAreaDegrees(int degrees) {
      Position center = new Position(51, 0);
      int distanceA = 100;
      int distanceB = 300;
      verifyArea(center, distanceA, distanceB, degrees);
    }
  
    private void testAreaDistance(int distance) {
      Position center = new Position(51, 0);
      int degrees = 45;
      verifyArea(center, distance, distance, degrees);
    }
  
    private void testAreaPosition(int lat, int lon) {
      Position center = new Position(lat, lon);
      int distanceA = 100;
      int distanceB = 300;
      int degrees = 45;
      verifyArea(center, distanceA, distanceB, degrees);
    }
  
    private void verifyArea(Position center, int distanceA, int distanceB, int degrees) {
      Area rect = Area.rectangle(center, distanceA, distanceB, degrees);
      verifyAreaRectangleBytes(rect, center, distanceA, distanceB, degrees);
      verifyAreaRectangleReturnTypes(rect, center);
      verifyAreaRectangleString(rect, center, distanceA, distanceB, degrees);
    }
  
    private void verifyAreaRectangleReturnTypes(Area rect, Position center) {
      assertEquals(Area.Type.RECTANGLE, rect.type());
      assertEquals(center, rect.center());
    }
  
    private void verifyAreaRectangleBytes(Area rectangle, Position center, int distanceA,
                                          int distanceB, int degrees) {
      ByteBuffer actualByteBuffer = getAreaByteBuffer();
      rectangle.putTo(actualByteBuffer);
  
      byte[] actual = actualByteBuffer.array();
      byte[] expected = areaParamToBytes(center, distanceA, distanceB, degrees);
      if (LOGGING) {
        System.out.println("Expected:");
        asBinaryString(expected);
        System.out.println("Actual:");
        asBinaryString(actual);
      }
  
      assertArrayEquals(expected, actual);
  
      Area actualArea = Area.getFrom(ByteBuffer.wrap(expected), Area.Type.RECTANGLE);
      assertEquals(rectangle, actualArea);
    }
  
    private void verifyAreaRectangleString(Area rectangle, Position center, int distanceA,
                                           int distanceB, int degrees) {
      String expected = "Area [center=" + center + ", distanceAmeters=" + distanceA
          + ", distanceBmeters=" + distanceB + ", angleDegreesFromNorth="+ degrees
          + ", type=RECTANGLE]";
      String actual = rectangle.toString();
      assertEquals(expected, actual);
    }
  
    static class Support {
  
      private static final double TENTH_MICRODEGREE_MULTIPLIER = 1E7;
  
      static void asBinaryString(byte[] bytes) {
        for (byte b : bytes) {
          System.out.println(Integer.toBinaryString(b & 255 | 256).substring(1));
        }
      }
  
      static byte[] areaParamToBytes(Position center, int distanceA, int distanceB, int degrees) {
        int latBytes = (int) (center.lattitudeDegrees() * TENTH_MICRODEGREE_MULTIPLIER);
        int lonBytes = (int) (center.longitudeDegrees() * TENTH_MICRODEGREE_MULTIPLIER);
  
        ByteBuffer expectedBuffer = getAreaByteBuffer();
        expectedBuffer.putInt(latBytes);
        expectedBuffer.putInt(lonBytes);
        expectedBuffer.putShort((short) distanceA);
        expectedBuffer.putShort((short) distanceB);
        expectedBuffer.putShort((short) degrees);
        return expectedBuffer.array();
      }
  
      static ByteBuffer getAreaByteBuffer() {
        return ByteBuffer.allocate(14);
      }
    }
  
  }
  