/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2009  Sandro Santilli <strk@kbt.io>
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: original work
 *
 **********************************************************************/

#include "SingleSidedBufferResultMatcher.h"

#include <geos/geom/Geometry.h>
#include <geos/geom/BinaryOp.h>
#include <geos/operation/overlay/OverlayOp.h>
#include <geos/algorithm/distance/DiscreteHausdorffDistance.h>

#include <cmath>

namespace geos {
namespace xmltester {

double SingleSidedBufferResultMatcher::MIN_DISTANCE_TOLERANCE = 1.0e-8;
double SingleSidedBufferResultMatcher::MAX_HAUSDORFF_DISTANCE_FACTOR = 100;

bool
SingleSidedBufferResultMatcher::isBufferResultMatch(const geom::Geometry& actualBuffer,
	                         const geom::Geometry& expectedBuffer,
	                         double distance)
{
	bool aEmpty = actualBuffer.isEmpty();
	bool eEmpty = expectedBuffer.isEmpty();

	// Both empty succeeds
	if (aEmpty && eEmpty) return true;

	// One empty and not the other is a failure
	if (aEmpty || eEmpty)
	{
std::cerr << "isBufferResultMatch failed (one empty and one not)" << std::endl;
		return false;
	}


   // NOTE: we need to test hausdorff distance in both directions

	if (! isBoundaryHausdorffDistanceInTolerance(actualBuffer,
	           expectedBuffer, distance))
	{
std::cerr << "isBoundaryHasudorffDistanceInTolerance failed (actual,expected)" << std::endl;
		return false;
	}

	if (! isBoundaryHausdorffDistanceInTolerance(expectedBuffer,
	           actualBuffer, distance))
	{
std::cerr << "isBoundaryHasudorffDistanceInTolerance failed (expected,actual)" << std::endl;
		return false;
	}

	return true;
}

bool
SingleSidedBufferResultMatcher::isBoundaryHausdorffDistanceInTolerance(
	const geom::Geometry& actualBuffer,
	const geom::Geometry& expectedBuffer, double distance)
{
	typedef std::unique_ptr<geom::Geometry> GeomPtr;

	using geos::algorithm::distance::DiscreteHausdorffDistance;

	GeomPtr actualBdy ( actualBuffer.clone() );
	GeomPtr expectedBdy ( expectedBuffer.clone() );

	DiscreteHausdorffDistance haus(*actualBdy, *expectedBdy);
	haus.setDensifyFraction(0.25);

	double maxDistanceFound = haus.orientedDistance();

	double expectedDistanceTol = fabs(distance) / MAX_HAUSDORFF_DISTANCE_FACTOR;
	if (expectedDistanceTol < MIN_DISTANCE_TOLERANCE)
	{
		expectedDistanceTol = MIN_DISTANCE_TOLERANCE;
	}

	if (maxDistanceFound > expectedDistanceTol)
	{
std::cerr << "maxDistanceFound: " << maxDistanceFound << " tolerated " << expectedDistanceTol << std::endl;
		return false;
	}

	return true;
}

} // namespace geos::xmltester
} // namespace geos
