/*******************************************************************************
 * Copyright (c) 2015 Voyager Search and MITRE
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0 which
 * accompanies this distribution and is available at
 *    http://www.apache.org/licenses/LICENSE-2.0.txt
 ******************************************************************************/

package org.locationtech.spatial4j.io;

import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.shape.Point;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
 * Tests for {@link GeohashUtils}
 */
public class TestGeohashUtils {
  SpatialContext ctx = SpatialContext.GEO;

  /**
   * Pass condition: lat=42.6, lng=-5.6 should be encoded as "ezs42e44yx96",
   * lat=57.64911 lng=10.40744 should be encoded as "u4pruydqqvj8"
   */
  @Test
  public void testEncode() {
    String hash = GeohashUtils.encodeLatLon(42.6, -5.6);
    assertEquals("ezs42e44yx96", hash);

    hash = GeohashUtils.encodeLatLon(57.64911, 10.40744);
    assertEquals("u4pruydqqvj8", hash);
  }

  /**
   * Pass condition: lat=52.3738007, lng=4.8909347 should be encoded and then
   * decoded within 0.00001 of the original value
   */
  @Test
  public void testDecodePreciseLongitudeLatitude() {
    String hash = GeohashUtils.encodeLatLon(52.3738007, 4.8909347);

    Point point = GeohashUtils.decode(hash,ctx);

    assertEquals(52.3738007, point.getY(), 0.00001D);
    assertEquals(4.8909347, point.getX(), 0.00001D);
  }

  /**
   * Pass condition: lat=84.6, lng=10.5 should be encoded and then decoded
   * within 0.00001 of the original value
   */
  @Test
  public void testDecodeImpreciseLongitudeLatitude() {
    String hash = GeohashUtils.encodeLatLon(84.6, 10.5);

    Point point = GeohashUtils.decode(hash, ctx);

    assertEquals(84.6, point.getY(), 0.00001D);
    assertEquals(10.5, point.getX(), 0.00001D);
  }

  /*
   * see https://issues.apache.org/jira/browse/LUCENE-1815 for details
   */
  @Test
  public void testDecodeEncode() {
    String geoHash = "u173zq37x014";
    assertEquals(geoHash, GeohashUtils.encodeLatLon(52.3738007, 4.8909347));
    Point point = GeohashUtils.decode(geoHash,ctx);
    assertEquals(52.37380061d, point.getY(), 0.000001d);
    assertEquals(4.8909343d, point.getX(), 0.000001d);

    assertEquals(geoHash, GeohashUtils.encodeLatLon(point.getY(), point.getX()));

    geoHash = "u173";
    point = GeohashUtils.decode("u173",ctx);
    geoHash = GeohashUtils.encodeLatLon(point.getY(), point.getX());
    final Point point2 = GeohashUtils.decode(geoHash, ctx);
    assertEquals(point.getY(), point2.getY(), 0.000001d);
    assertEquals(point.getX(), point2.getX(), 0.000001d);
  }

  /** see the table at http://en.wikipedia.org/wiki/Geohash */
  @Test
  public void testHashLenToWidth() {
    //test odd & even len
    double[] boxOdd = GeohashUtils.lookupDegreesSizeForHashLen(3);
    assertEquals(1.40625,boxOdd[0],0.0001);
    assertEquals(1.40625,boxOdd[1],0.0001);
    double[] boxEven = GeohashUtils.lookupDegreesSizeForHashLen(4);
    assertEquals(0.1757,boxEven[0],0.0001);
    assertEquals(0.3515,boxEven[1],0.0001);
  }

  /** see the table at http://en.wikipedia.org/wiki/Geohash */
  @Test
  public void testLookupHashLenForWidthHeight() {
    assertEquals(1, GeohashUtils.lookupHashLenForWidthHeight(999,999));

    assertEquals(1, GeohashUtils.lookupHashLenForWidthHeight(999,46));
    assertEquals(1, GeohashUtils.lookupHashLenForWidthHeight(46,999));

    assertEquals(2, GeohashUtils.lookupHashLenForWidthHeight(44,999));
    assertEquals(2, GeohashUtils.lookupHashLenForWidthHeight(999,44));
    assertEquals(2, GeohashUtils.lookupHashLenForWidthHeight(999,5.7));
    assertEquals(2, GeohashUtils.lookupHashLenForWidthHeight(11.3,999));

    assertEquals(3, GeohashUtils.lookupHashLenForWidthHeight(999,5.5));
    assertEquals(3, GeohashUtils.lookupHashLenForWidthHeight(11.1,999));

    assertEquals(GeohashUtils.MAX_PRECISION, GeohashUtils.lookupHashLenForWidthHeight(10e-20,10e-20));
  }
}
