//
// Test Suite for geos::noding::snapround::MCIndexSnapRounder class.

#include <tut/tut.hpp>
// geos
#include <geos/noding/SegmentNode.h>
#include <geos/noding/Noder.h>
#include <geos/noding/NodedSegmentString.h>
#include <geos/noding/SegmentString.h>
#include <geos/noding/snapround/MCIndexSnapRounder.h>
#include <geos/io/WKTWriter.h>
#include <geos/io/WKBWriter.h>
#include <geos/io/WKTReader.h>
#include <geos/io/WKBReader.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateArraySequenceFactory.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/LineString.h>
#include <geos/geom/MultiLineString.h>
// std
#include <memory>
#include <fstream>
#include <string>
#include <iomanip>
#include <iostream>


namespace tut
{
    //
    // Test Group
    //

    // Common data used by all tests
    struct test_mcidxsnprndr_data
    {

      typedef geos::noding::SegmentString SegmentString;
      typedef geos::noding::NodedSegmentString NodedSegmentString;
      typedef geos::noding::snapround::MCIndexSnapRounder MCIndexSnapRounder;
      typedef geos::noding::Noder Noder;
      typedef geos::io::WKTReader WKTReader;
      typedef geos::io::WKBReader WKBReader;
      typedef geos::io::WKTWriter WKTWriter;
      typedef geos::io::WKBWriter WKBWriter;
      typedef geos::geom::Geometry Geometry;
      typedef geos::geom::PrecisionModel PrecisionModel;
      typedef geos::geom::CoordinateSequence CoordinateSequence;

      typedef std::unique_ptr<CoordinateSequence> CoordSeqPtr;
      typedef std::unique_ptr<Geometry> GeomPtr;

      typedef std::vector<SegmentString*> SegStrVct;
      typedef std::vector<Geometry*> GeomVct;

      const geos::geom::GeometryFactory *gf_;

      test_mcidxsnprndr_data()
            : gf_(geos::geom::GeometryFactory::getDefaultInstance())
      {}

      GeomPtr getGeometry(SegStrVct& vct)
      {
        GeomVct *lines = new GeomVct;
        for (SegStrVct::size_type i=0, n=vct.size(); i<n; ++i)
        {
          SegmentString* ss = vct[i];
          lines->push_back( gf_->createLineString(*(ss->getCoordinates())) );
        }
        return GeomPtr(gf_->createMultiLineString(lines));
      }

      void getSegmentStrings(const Geometry& g, SegStrVct& vct)
      {
        CoordSeqPtr s ( g.getCoordinates() );
        vct.push_back( new NodedSegmentString(s.release(), nullptr) );
      }

      GeomPtr readGeometry(const std::string& wkt)
      {
        GeomPtr g;
        if ( wkt[0] == '0' || wkt[0] == '1' ) {
          WKBReader r;
          std::istringstream is(wkt);
          g.reset( r.readHEX(is) );
        } else {
          WKTReader r;
          g.reset( r.read(wkt) );
        }
        return g;
      }

      void getSegmentStrings(const std::string& wkt, SegStrVct& vct)
      {
        GeomPtr g = readGeometry(wkt);
        getSegmentStrings(*g, vct);
      }

      void freeSegmentStrings(SegStrVct& vct)
      {
        for (SegStrVct::size_type i=0, n=vct.size(); i<n; ++i)
          delete vct[i];
      }

    private:
        test_mcidxsnprndr_data(test_mcidxsnprndr_data const&); // = delete
        test_mcidxsnprndr_data& operator=(test_mcidxsnprndr_data const&); // = delete
    };


    typedef test_group<test_mcidxsnprndr_data> group;
    typedef group::object object;

    group test_mcidxsnprndr_group(
      "geos::noding::snapround::MCIndexSnapRounder"
    );

    //
    // Test Cases
    //

    // This test would fail before fix in r3528
    template<>
    template<>
    void object::test<1>()
    {
      std::string wkt0("LINESTRING(99739.70596 -2239218.0625,99739.85604 -2239218.21258,99739.85605 -2239218.21258, 99739.85605 -2239218.21258,99739.86851 -2239218.21258,99739.86851 -2239218.20012, 99739.86851 -2239218.20012,99739.86851 -2239218.04, 99739.95848 -2239218.11015,99739.86851 -2239218.20012, 99739.86851 -2239218.20012,99739.85605 -2239218.21258, 99739.85605 -2239218.21258,99739.80901 -2239218.25961, 99739.80901 -2239218.25961,99739.68863 -2239218.38, 99739.86204 -2239218.31264,99739.80901 -2239218.25961, 99739.80901 -2239218.25961,99739.66841 -2239218.11901)");
      SegStrVct nodable;
      getSegmentStrings(wkt0, nodable);
      ensure_equals( nodable.size(), 1u );

      PrecisionModel pm(1e-5);
      MCIndexSnapRounder noder(pm);

      ensure_equals( nodable.size(), 1u );
      noder.computeNodes(&nodable);
      std::unique_ptr<SegStrVct> noded ( noder.getNodedSubstrings() );

      ensure_equals( "1e-5", noded->size(), 178u );

      freeSegmentStrings(*noded);
      freeSegmentStrings(nodable);
    }


} // namespace tut
