package fgis.server.support.geojson;

import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonStructure;
import javax.json.JsonValue;
import javax.json.stream.JsonGenerator;
import org.geolatte.geom.Envelope;
import org.geolatte.geom.Geometry;
import org.geolatte.geom.codec.Wkt;
import org.geolatte.geom.codec.Wkt.Dialect;
import org.geolatte.geom.crs.CrsId;
import org.geolatte.geom.crs.CrsRegistry;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class GeoJsonWriterTest
{
  @Test
  public void emitPointGeometry()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final GjElement e = new GjGeometry( geometry, null, null, null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson = "{\"type\":\"Point\",\"coordinates\":[1.0,1.0]}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitGeometryWithBBox()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final GjElement e = new GjGeometry( geometry, null, new Envelope( 0, 0, 2, 2 ), null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson = "{\"type\":\"Point\",\"bbox\":[0.0,0.0,2.0,2.0],\"coordinates\":[1.0,1.0]}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitGeometryWithAdditionalAttributes()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final HashMap<String, JsonValue> additionalProperties = new HashMap<>();
    additionalProperties.put( "Foo", JsonValue.FALSE );
    additionalProperties.put( "Bar", JsonValue.NULL );
    final GjElement e = new GjGeometry( geometry, null, null, additionalProperties );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson = "{\"type\":\"Point\",\"Foo\":false,\"Bar\":null,\"coordinates\":[1.0,1.0]}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitGeometryWithCrs()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final CrsId crsId = CrsRegistry.getCrsIdForEPSG( 3111 );
    final GjElement e = new GjGeometry( geometry, crsId, null, null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson =
      "{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3111\"}},\"coordinates\":[1.0,1.0]}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitGeometryCollection()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final GjGeometry g = new GjGeometry( geometry, null, null, null );
    final GjElement e = new GjGeometryCollection( Arrays.asList( g ), null, null, null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson =
      "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,1.0]}]}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitFeature()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final GjGeometry g = new GjGeometry( geometry, null, null, null );
    final GjElement e = new GjFeature( null, g, null, null, null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson =
      "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[1.0,1.0]},\"properties\":{}}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  @Test
  public void emitFeatureWithId()
  {
    final Geometry geometry = fromWkT( "POINT (1 1)" );
    final GjGeometry g = new GjGeometry( geometry, null, null, null );
    final GjElement e = new GjFeature( JsonValue.TRUE, g, null, null, null );

    final JsonStructure result = writeAndRead( e );

    final String expectedJson =
      "{\"type\":\"Feature\",\"id\":true,\"geometry\":{\"type\":\"Point\",\"coordinates\":[1.0,1.0]},\"properties\":{}}";
    final JsonObject expected = (JsonObject) parse( expectedJson );
    assertEquals( result, expected );
  }

  private JsonStructure writeAndRead( final GjElement e )
  {
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final JsonGenerator g = Json.createGenerator( baos );

    new GeoJsonWriter().emit( g, e );

    g.flush();

    return parse( baos.toByteArray() );
  }

  private JsonStructure parse( final byte[] bytes )
  {
    return parse( new String( bytes, Charset.forName( "US-ASCII" ) ) );
  }

  private JsonStructure parse( final String json )
  {
    return new JsonReader( new StringReader( json ) ).read();
  }


  @SuppressWarnings( "unchecked" )
  public final <T extends Geometry> T fromWkT( final String wkt )
  {
    return (T) Wkt.newDecoder( Dialect.POSTGIS_EWKT_1 ).decode( wkt );
  }
}

@@ -4493,32 +4493,814 @@
 xpected );%0A  %7D%0A%0A
+  @Test%0A  public void emitFeatureWithAdditionalProperties()%0A  %7B%0A    final Geometry geometry = fromWkT( %22POINT (1 1)%22 );%0A    final GjGeometry g = new GjGeometry( geometry, null, null, null );%0A    final HashMap%3CString, JsonValue%3E additionalProperties = new HashMap%3C%3E();%0A    additionalProperties.put( %22Foo%22, JsonValue.FALSE );%0A    additionalProperties.put( %22Bar%22, JsonValue.NULL );%0A    final GjElement e = new GjFeature( null, g, null, null, additionalProperties );%0A%0A    final JsonStructure result = writeAndRead( e );%0A%0A    final String expectedJson =%0A      %22%7B%5C%22type%5C%22:%5C%22Feature%5C%22,%5C%22id%5C%22:true,%5C%22geometry%5C%22:%7B%5C%22type%5C%22:%5C%22Point%5C%22,%5C%22coordinates%5C%22:%5B1.0,1.0%5D%7D,%5C%22properties%5C%22:%7B%7D%7D%22;%0A    final JsonObject expected = (JsonObject) parse( expectedJson );%0A    assertEquals( result, expected );%0A  %7D%0A%0A
   private JsonSt

Test feature with properties