/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * 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: operation/buffer/BufferSubgraph.java r378 (JTS-1.12)
 *
 **********************************************************************/

#pragma once

#include <geos/export.h>

#include <geos/operation/buffer/RightmostEdgeFinder.h> // for composition

#include <vector>
#include <set>

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
#endif

// Forward declarations
namespace geos {
namespace geom {
class Coordinate;
class Envelope;
}
namespace algorithm {
class CGAlgorithms;
}
namespace geomgraph {
class DirectedEdge;
class Node;
}
}

namespace geos {
namespace operation { // geos.operation
namespace buffer { // geos.operation.buffer

/**
 * \brief
 * A connected subset of the graph of DirectedEdge and geomgraph::Node.
 *
 * Its edges will generate either
 * - a single polygon in the complete buffer, with zero or more holes, or
 * -  ne or more connected holes
 */
class GEOS_DLL BufferSubgraph {
private:
    RightmostEdgeFinder finder;

    std::vector<geomgraph::DirectedEdge*> dirEdgeList;

    std::vector<geomgraph::Node*> nodes;

    geom::Coordinate* rightMostCoord;

    geom::Envelope* env;

    /** \brief
     * Adds all nodes and edges reachable from this node to the subgraph.
     *
     * Uses an explicit stack to avoid a large depth of recursion.
     *
     * @param startNode a node known to be in the subgraph
     */
    void addReachable(geomgraph::Node* startNode);

    /// Adds the argument node and all its out edges to the subgraph
    ///
    /// @param node the node to add
    /// @param nodeStack the current set of nodes being traversed
    ///
    void add(geomgraph::Node* node, std::vector<geomgraph::Node*>* nodeStack);

    void clearVisitedEdges();

    /** \brief
     * Compute depths for all dirEdges via breadth-first traversal
     * of nodes in graph
     *
     * @param startEdge edge to start processing with
     */
    // <FIX> MD - use iteration & queue rather than recursion, for speed and robustness
    void computeDepths(geomgraph::DirectedEdge* startEdge);

    void computeNodeDepth(geomgraph::Node* n);

    void copySymDepths(geomgraph::DirectedEdge* de);

    bool contains(std::set<geomgraph::Node*>& nodes, geomgraph::Node* node);

public:

    friend std::ostream& operator<< (std::ostream& os, const BufferSubgraph& bs);

    BufferSubgraph();

    ~BufferSubgraph();

    std::vector<geomgraph::DirectedEdge*>* getDirectedEdges();

    std::vector<geomgraph::Node*>* getNodes();

    /** \brief
     * Gets the rightmost coordinate in the edges of the subgraph
     */
    geom::Coordinate* getRightmostCoordinate();

    /** \brief
     * Creates the subgraph consisting of all edges reachable from
     * this node.
     *
     * Finds the edges in the graph and the rightmost coordinate.
     *
     * @param node a node to start the graph traversal from
     */
    void create(geomgraph::Node* node);

    void computeDepth(int outsideDepth);

    /** \brief
     * Find all edges whose depths indicates that they are in the
     * result area(s).
     *
     * Since we want polygon shells to be
     * oriented CW, choose dirEdges with the interior of the result
     * on the RHS.
     * Mark them as being in the result.
     * Interior Area edges are the result of dimensional collapses.
     * They do not form part of the result area boundary.
     */
    void findResultEdges();

    /** \brief
     * BufferSubgraphs are compared on the x-value of their rightmost
     * Coordinate.
     *
     * This defines a partial ordering on the graphs such that:
     *
     * g1 >= g2 <==> Ring(g2) does not contain Ring(g1)
     *
     * where Polygon(g) is the buffer polygon that is built from g.
     *
     * This relationship is used to sort the BufferSubgraphs so
     * that shells are guaranteed to
     * be built before holes.
     */
    int compareTo(BufferSubgraph*);

    /** \brief
     * Computes the envelope of the edges in the subgraph.
     * The envelope is cached after being computed.
     *
     * @return the envelope of the graph.
     */
    geom::Envelope* getEnvelope();
};

std::ostream& operator<< (std::ostream& os, const BufferSubgraph& bs);

// INLINES
inline geom::Coordinate*
BufferSubgraph::getRightmostCoordinate()
{
    return rightMostCoord;
}

inline std::vector<geomgraph::Node*>*
BufferSubgraph::getNodes()
{
    return &nodes;
}

inline std::vector<geomgraph::DirectedEdge*>*
BufferSubgraph::getDirectedEdges()
{
    return &dirEdgeList;
}

bool BufferSubgraphGT(BufferSubgraph* first, BufferSubgraph* second);

} // namespace geos::operation::buffer
} // namespace geos::operation
} // namespace geos

#ifdef _MSC_VER
#pragma warning(pop)
#endif