/*private*/
void
DouglasPeuckerLineSimplifier::simplifySection(
    std::size_t i,
    std::size_t j)
{
    if((i + 1) == j) {
        return;
    }

    geos::geom::LineSegment seg(pts[i], pts[j]);
    double maxDistance = -1.0;

    std::size_t maxIndex = i;

    for(std::size_t k = i + 1; k < j; k++) {
        double distance = seg.distance(pts[k]);
        if(distance > maxDistance) {
            maxDistance = distance;
            maxIndex = k;
        }
    }
    if(maxDistance <= distanceTolerance) {
        for(std::size_t k = i + 1; k < j; k++) {
            usePt->operator[](k) = false;
        }
    }
    else {
        simplifySection(i, maxIndex);
        simplifySection(maxIndex, j);
    }
}
/*public*/
void
TaggedLineStringSimplifier::simplify(TaggedLineString* nLine)
{
	assert(nLine);
	line = nLine;

	linePts = line->getParentCoordinates();
	assert(linePts);

#if GEOS_DEBUG
	std::cerr << "TaggedLineStringSimplifier[" << this << "] "
	     << " TaggedLineString[" << line << "] "
	     << " has " << linePts->size() << " coords in input"
	     << std::endl;
#endif

	simplifySection(0, linePts->size() - 1, 0);

}
/*public*/
DouglasPeuckerLineSimplifier::CoordsVectAutoPtr
DouglasPeuckerLineSimplifier::simplify()
{
    CoordsVectAutoPtr coordList(new CoordsVect());

    // empty coordlist is the simplest, won't simplify further
    if(! pts.size()) {
        return coordList;
    }

    usePt = BoolVectAutoPtr(new BoolVect(pts.size(), true));
    simplifySection(0, pts.size() - 1);

    for(std::size_t i = 0, n = pts.size(); i < n; ++i) {
        if(usePt->operator[](i)) {
            coordList->push_back(pts[i]);
        }
    }

    // unique_ptr transfer ownership to its
    // returned copy
    return coordList;
}
/*private*/
void
TaggedLineStringSimplifier::simplifySection(size_t i,
		size_t j, size_t depth)
{
	depth += 1;

#if GEOS_DEBUG
	std::cerr << "TaggedLineStringSimplifier[" << this << "] "
	          << " simplifying section " << i << "-" << j
	          << std::endl;
#endif

	vector<size_t> sectionIndex(2);

	if((i+1) == j)
	{

#if GEOS_DEBUG
		std::cerr << "single segment, no flattening" 
		          << std::endl;
#endif

		auto_ptr<TaggedLineSegment> newSeg(new
			TaggedLineSegment(*(line->getSegment(i))));

		line->addToResult(newSeg);
		// leave this segment in the input index, for efficiency
		return;
	}

	bool isValidToSimplify = true;

	/**
	 * Following logic ensures that there is enough points in the
	 * output line.
	 * If there is already more points than the minimum, there's
	 * nothing to check.
	 * Otherwise, if in the worst case there wouldn't be enough points,
	 * don't flatten this segment (which avoids the worst case scenario)
	 */
	if (line->getResultSize() < line->getMinimumSize())
	{
		size_t worstCaseSize = depth + 1;
		if (worstCaseSize < line->getMinimumSize())
			isValidToSimplify = false;
	}

	double distance;

	// pass distance by ref
	size_t furthestPtIndex = findFurthestPoint(linePts, i, j, distance);

#if GEOS_DEBUG
	std::cerr << "furthest point " << furthestPtIndex 
	          << " at distance " << distance
	          << std::endl;
#endif

	// flattening must be less than distanceTolerance
	if ( distance > distanceTolerance ) isValidToSimplify = false;

	// test if flattened section would cause intersection
	LineSegment candidateSeg(linePts->getAt(i), linePts->getAt(j));

	sectionIndex[0] = i;
	sectionIndex[1] = j;

	if (hasBadIntersection(line, sectionIndex, candidateSeg))
			isValidToSimplify = false;

	if (isValidToSimplify)
	{

		auto_ptr<TaggedLineSegment> newSeg = flatten(i, j);

#if GEOS_DEBUG
		std::cerr << "isValidToSimplify, adding seg " 
			  << newSeg->p0 << ", " << newSeg->p1
			  << " to TaggedLineSegment["<<line<<"] result "
			  << std::endl;
#endif

		line->addToResult(newSeg);
		return;
	}

	simplifySection(i, furthestPtIndex, depth);
	simplifySection(furthestPtIndex, j, depth);
 
}