/******************************************************************************  		
 * Company:         SINED GmbH 
 * Author:          Andriy Kurhanevych
 * Created:         4.10.2004
 * Last modified:   $Modtime: 16.02.13 23:40 $
 * Purpose:         Declaration of the Topology class
 ******************************************************************************/
#ifndef POLYGONLIBRARY_TOPOLOGY_H
#define POLYGONLIBRARY_TOPOLOGY_H

namespace PolygonLibrary
{
	class  Point;
	class  Rectangle;
	class  Node;
	class  PolygonLayer;
	class  PolylineLayer;
	class  TopologyImpl;
	
	//////////////////////////////////////////////////////////////////////////
	/// A container of Polygon and Polyline objects that share Node objects 
	/// representing vertices of the geometries.  
	/// Each Node is unique in the Topology (there is no other Node with 
	/// the same coordinates)and is referenced by one or many geometric objects.
	/// 
	/// A Node is automatically created during adding 
	/// a vertex to a geometric object, if the Topology does not contain a Node
	/// with the specified coordinates. The Node is deleted during removing a 
	/// vertex from a geometric object, if the Node is not more referenced 
	/// by a geometric object. 
	//////////////////////////////////////////////////////////////////////////
	class Topology
	{
	
	// ----------------------------- Interface ------------------------------
	public:
		// --- Construction, destruction ---

		/// Creates a Topology object and returns pointer to it.
		/// @exception Exceptions::InvalidOperationException - if the maximal allowed number 
		/// of Topology objects is reached
		static Topology* CreateTopology();
		
		/// Deletes the specified Topology object.
		/// @exception Exceptions::InvalidOperationException - if a Polygon of the Topology
		/// cannot be deleted because is contained in the Parents collection of a Polygon of an other Topology 
		static void      DeleteTopology(Topology* pTopology);
		
		// --- Attributes ---

		/// Moves the specified node to the specified point.  
		/// If there is a node at the specified target location, 
		/// the moved Node is replaced with the Node in the geometric objects. 
		/// Returns pointer to the Node at the specified target location.
		/// @exception Exceptions::ArgumentException - if the Node is not contained in this Topology
		/// @exception Exceptions::InvalidOperationException - if a Polygon containing the Node
		/// cannot be changed because is contained in the Parents collection of an other Polygon.
		Node*     MoveNode(Node* pNode, Point ptLocation);

		/// Returns the bounding box of all geometric objects of this Topology.
		Rectangle Bounds() const;
		
		// --- Operations ---
		
		/// Gets bounding box of polygon segments that start/end at the specified node.
		/// @exception Exceptions::ArgumentException - if the Node is not contained in this Topology
		Rectangle EdgesBounds(Node* pNode) const;

		/// Locates the node closest to the specified point 
		/// and being within the specified tolerance distance from the point.
		/// Returns pointer to the located Node 
		/// or NULL pointer if there is no Node in the specified circular area.
		/// @exception Collections::InvalidArgumentException - if dToleranceDistance is negative
		Node*     NodeAtLocation(const Point& point, double dToleranceDistance) const;

		/// Creates a PolygonLayer object with the specified value of the AllowsOverlap attribute 
		/// and adds to this Topology. Returns pointer to the created PolygonLayer.
		PolygonLayer* CreatePolygonLayer(bool bAllowsOverlap);

		/// Creates a PolygonLayer representing the set-theoretic union of the 
		/// specified polygon layers by minimal count of not overlapping polygons representing the origin polygons 
		/// as far as possible (overlapping polygons are merged).
		/// Adds the created PolygonLayer to this Topology and returns pointer to the created object.
		PolygonLayer* CreatePolygonLayersUnion(PolygonLayer* pFirstPolygonLayer, PolygonLayer* pSecondPolygonLayer, bool bSetParents);

		/// Creates a PolygonLayer representing the set-theoretic union of the 
		/// specified polygon layers by maximal count of not overlapping polygons representing the origin polygons 
		/// as far as possible: overlaps between polygons of the layers and not empty results of their subtraction 
		/// from the polygons.
		/// Adds the created PolygonLayer to this Topology and returns pointer to the created object.
		PolygonLayer* CreatePolygonLayersJoin(PolygonLayer* pFirstPolygonLayer, PolygonLayer* pSecondPolygonLayer, bool bSetParents);

		/// Creates a PolygonLayer representing the set-theoretic intersection of the 
		/// specified polygon layers by maximal count of polygons: not empty intersections between each polygon of the 
		/// first layer and each polygon of the second layer.
		/// Adds the created PolygonLayer to this Topology and returns pointer to the created object.
		PolygonLayer* CreatePolygonLayersIntersection(PolygonLayer* pFirstPolygonLayer, PolygonLayer* pSecondPolygonLayer, bool bSetParents);

		/// Creates a PolygonLayer representing the set-theoretic difference between the 
		/// specified polygon layers by not empty results of subtraction of the second layer from the polygons of the first layer.
		/// Adds the created PolygonLayer to this Topology and returns pointer to the created object.
		PolygonLayer* CreatePolygonLayersDifference(PolygonLayer* pFirstPolygonLayer, PolygonLayer* pSecondPolygonLayer, bool bSetParents);


		/// Deletes the specified PolygonLayer of this Topology.
		/// @exception Exceptions::ArgumentException         - if the specified PolygonLayer is not contained in the Topology
		/// @exception Exceptions::InvalidoperationException - if a Polygon of the PolygonLayer
		/// cannot be deleted because is contained in the Parents collection of a Polygon of an other PolygonLayer
		void          DeletePolygonLayer(PolygonLayer* pPolygonLayer);
		
		/// Creates a PolylineLayer object, adds it to this Topology and returns pointer to it.
		PolylineLayer* CreatePolylineLayer();

		/// Deletes the specified PolylineLayer of this Topology.
		/// @exception Exceptions::ArgumentException - if the specified PolylineLayer is not contained in the Topology
		void          DeletePolylineLayer(PolylineLayer* pPolylineLayer);

		/// Commits all changes made since last successful call of this method: 
		/// calls AcceptChanges() of changed PolygonLayer and PolylineLayer objects.
		/// @exception InvalidPolygonException  - if a Polygon of this Topology is not valid 
		/// @exception PolygonsOverlapException - if some polygons of a PolygonLayer overlap and the PolygonLayer does not allow overlap  
		void          AcceptChanges();
				
	
	// --------------------------- Implementation -----------------------------
	private:
		
		friend class PolylineImpl;
		friend class PolygonLayerImpl;
		friend class LayerImpl;
						
		explicit Topology();
		~Topology();

		// disable copying and assignment
		Topology(const Topology&);
		Topology& operator=(const Topology&);
		
		// pointer to the implementation part
		const TopologyImpl* impl() const; 
		TopologyImpl*       impl();

		TopologyImpl*       m_pimpl;
	};
}
#endif