//
// Test Suite for geos::algorithm::PointLocator
// Ported from JTS junit/algorithm/PointLocator.java

#include <tut/tut.hpp>
// geos
#include <geos/io/WKTReader.h>
#include <geos/algorithm/PointLocator.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Geometry.h> // required for use in unique_ptr
#include <geos/geom/Coordinate.h>
// std
#include <sstream>
#include <string>
#include <memory>

namespace geos {
	namespace geom {
		class Geometry;
	}
}

using namespace geos::geom; // for Location

namespace tut
{
	//
	// Test Group
	//

	// dummy data, not used
	struct test_pointlocator_data {};

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

	group test_pointlocator_group("geos::algorithm::PointLocator");

	// These are static to avoid namespace pollution
	// The struct test_*_data above is probably there
	// for the same reason...
	//
	static PrecisionModel pm;
	static GeometryFactory::Ptr gf = GeometryFactory::create(&pm);
	static geos::io::WKTReader reader(gf.get());

	typedef std::unique_ptr<Geometry> GeomPtr;

	void runPtLocator(int expected, const Coordinate& pt,
			const std::string& wkt)
	{
		GeomPtr geom(reader.read(wkt));
		geos::algorithm::PointLocator pointLocator;
		int loc = pointLocator.locate(pt, geom.get());
		ensure_equals(loc, expected);
	}


	//
	// Test Cases
	//

	// 1 - Test box
	template<>
	template<>
	void object::test<1>()
	{
		runPtLocator(Location::INTERIOR, Coordinate(10, 10),
		    "POLYGON ((0 0, 0 20, 20 20, 20 0, 0 0))");
	}

	// 2 - Test complex ring
	template<>
	template<>
	void object::test<2>()
	{
		runPtLocator(Location::INTERIOR, Coordinate(0, 0),
			"POLYGON ((-40 80, -40 -80, 20 0, 20 -100, 40 40, 80 -80, 100 80, 140 -20, 120 140, 40 180,     60 40, 0 120, -20 -20, -40 80))");
	}

	// 3 - Test PointLocator LinearRing LineString
	template<>
	template<>
	void object::test<3>()
	{
		runPtLocator(Location::BOUNDARY, Coordinate(0, 0),
                     "GEOMETRYCOLLECTION( LINESTRING(0 0, 10 10), LINEARRING(10 10, 10 20, 20 10, 10 10))");
	}

	// 4 - Test PointLocator Point inside LinearRing
	template<>
	template<>
	void object::test<4>()
	{
	    runPtLocator(Location::EXTERIOR, Coordinate(11, 11),
	                     "LINEARRING(10 10, 10 20, 20 10, 10 10)");
	}

	// 5 - TestPointLocator Point inside MultiPoint
	template<>
	template<>
	void object::test<5>()
	{
		runPtLocator(Location::INTERIOR, Coordinate(0, 0),
				"MULTIPOINT ((1 1), (0 0))");
	}

} // namespace tut

