text: //
  //////////////////////////////////////////////////////////////////////////////
  //
  //  Copyright 2014 Autodesk, Inc.  All rights reserved.
  //
  //  Use of this software is subject to the terms of the Autodesk license 
  //  agreement provided at the time of installation or download, or which 
  //  otherwise accompanies this software in either electronic or hard copy form.   
  //
  //////////////////////////////////////////////////////////////////////////////
  //
  // CREATED BY: Pei Zhan                                 March 2011
  //
  //////////////////////////////////////////////////////////////////////////////
  #pragma once
  #pragma pack (push, 8)
  
  #include "AcGraphNode.h"
  #include <map>
  
  class AcImpGraph;
  class AcDbObject;
  
  typedef std::map<AcGraphNode::Id, AcGraphNode*> NodeIdToPtrMap;
  
  /// <summary>
  /// This class represents a graph which manages a set of AcGraphNode with a unique id.
  /// </summary>
  ///
  class ACDB_PORT AcGraph : public AcRxObject
  {
  public:
  
      ACRX_DECLARE_MEMBERS(AcGraph);
  
      enum PartialUndoCode
      {
          /// <summary>
          /// Event of adding a node to the graph.
          /// </summary>
          ///
          kAddNodePartialUndoCode = 0,
  
          /// <summary>
          /// Event of removing a node from the graph.
          /// </summary>
          ///
          kRemoveNodePartialUndoCode,
  
          /// <summary>
          /// Event of modifying a node in the graph.
          /// </summary>
          ///
          kModifyNodePartialUndoCode,
  
          /// <summary>
          /// Event of changing the value of node Id for the next new node.
          /// </summary>
          ///
          kModifyNextNewNodeIdPartialUndoCode,
      };
  
  typedef NodeIdToPtrMap::iterator iterator;
  typedef NodeIdToPtrMap::const_iterator const_iterator;
  
      /// <summary> Default constructor. </summary>
      ///
      explicit AcGraph(bool bCreateImp = true);
  
      /// <summary> Default destructor. </summary>
      ///
      virtual ~AcGraph();
  
      /// <summary> 
      /// This function returns the owning object of the graph
      /// </summary>
      /// <returns> AcDbObject*. </returns>
      AcDbObject* owningObject() const;
  
      /// <summary> 
      /// This function set the owning object of the graph. Client code needs to
      /// ensure the validity of AcDbObject* throughout the whole lifetime of AcGraph. In the 
      /// AcGraph class the owning object is mainly used for partial undo purpose
      /// </summary>
      /// <returns> None. </returns>
      void setOwningObject(AcDbObject* pObj);
  
      /// <summary> 
      /// This function restores state of AcGraph during partial undo. Normally it is called
      /// from the applyPartialUndo method in owning object. In AcGraph, partial undo information
      /// is automatically recorded when a change is made to an AcGraph, the partial undo info
      /// that is written out includes (with order): address of class descriptor object of owingObject(), undo code
      /// and corresponding data for each specific undo operation. In client's code, applyPartialUndo needs to
      /// be implement for owningObject, which has to read the data in the same order, and then call 
      /// AcGraph::applyPartialUndo with the PartialUndoCode info
      /// </summary>
      /// <param name="pUndoFiler">   Input undo filer, normally from the object that owns this graph. </param>
      /// <param name="code">   code for undo operation. </param>
      /// <param name="nodeId">   the id of the AcGraphNode that was affected during the undo operation, 
      /// For following undo codes: 
      /// kAddNodePartialUndoCode: the id of the node that was added, note the returned nodeId is no longer valid as it has been removed from the graph. 
      /// kRemoveNodePartialUndoCode: the id of the node that was removed
      /// kModifyNodePartialUndoCode: the id of the node that was modified
      /// kModifyNextNewNodeIdPartialUndoCode: the new node id that was generated
      /// </param>
      /// <returns> Acad::ErrorStatus </returns>
      virtual Acad::ErrorStatus applyPartialUndo(AcDbDwgFiler* pUndoFiler,
                                                 PartialUndoCode code,
                                                 AcGraphNode::Id &nodeId); 
  
      /// <summary> 
      /// This function adds a node to the graph, a new node id is automatically assigned to the new node.
      /// It returns an error if the new node already has an owner graph that is different from this one,
      /// or the new node already has a non-null node Id in the same graph
      /// </summary>
      /// <param name="pNewNode"> new node to be added to this graph. </param>
      /// <returns> Acad::ErrorStatus </returns>
      Acad::ErrorStatus addGraphNode(AcGraphNode* pNewNode);
  
      /// <summary> 
      /// This function adds a node to the graph, it uses input nodeId for the new node. 
      /// It's caller's responsibility to ensure the nodeId is unused, other wise an error will
      /// be returned.
      /// It returns an error if the new node already has an owner graph that is different from this one,
      /// or nodeId has already been used in the this AcGraph
      /// </summary>
      /// <param name="pNewNode"> new node to be added to this graph. </param>
      /// <param name="nodeId"> nodeId to be assigned to the new node. </param>
      /// <returns> Acad::ErrorStatus </returns>
      Acad::ErrorStatus addGraphNode(AcGraphNode* pNewNode, AcGraphNode::Id nodeId);
  
      /// <summary> 
      /// This function removes a node from the graph, it returns an error if the node is still connected
      /// to other nodes. This function will also delete the node pointer if bDelete is true.
      /// </summary>
      /// <param name="pNode"> node to be removed from this graph. </param>
      /// <param name="bDelete"> if the node is to be deleted. </param>
      /// <returns> Acad::ErrorStatus </returns>
  
      Acad::ErrorStatus removeGraphNode(AcGraphNode* pNode, bool bDelete = true);
  
      /// <summary> 
      /// Given a node id, this function returns a pointer to the AcGraphNode. 
      /// Returns NULL if no match is found for the id
      /// </summary>
      /// <param name="nodeId"> the id of the returned node pointer. </param>
      /// <returns> pointer to the AcGraphNode  </returns>
      AcGraphNode* getGraphNodePtr(AcGraphNode::Id nodeId) const;
  
      /// <summary> 
      /// Disconnect an array of AcGraphNodes from their original owning graph and move them to this graph. 
      /// All other nodes that are directly or indirectly connected to these nodes will be
      /// moved as well. A new node id will be assigned to each of the node after it is moved.
      /// During the process, when each of the nodes is moved, method AcGraphNode::nodeToBeMovedNotification
      /// will be called to notify this event, which can be overriden to customize the behavior
      /// (see AcGraphNode::nodeToBeMoved for more details)
      /// </summary>
      /// <param name="nodesToMove">  input array of nodes to be moved to this graph. </param>
      /// <returns> Acad::ErrorStatus </returns>
      Acad::ErrorStatus moveAndMerge(const AcArray<AcGraphNode*> & nodesToMove);
  
      /// <summary> 
      /// Merge a graph into this graph, all the nodes will be unconditionally moved to this graph.  
      /// A new node id will be assigned to each of the node after it is moved.
      /// </summary>
      /// <param name="graph">  input graph that is to be merged to this graph. </param>
      /// <returns> Acad::ErrorStatus </returns>
      Acad::ErrorStatus merge(const AcGraph &graph);
  
      /// <summary> 
      /// Given an array of nodes, return all the related nodes that are directly or indirectly connected
      /// to them.
      /// </summary>
      /// <param name="nodes">  input nodes. </param>
      /// <param name="nodes">  output related nodes. </param>
      /// <returns> Acad::ErrorStatus </returns>
      Acad::ErrorStatus getRelatedNodes(const AcArray<AcGraphNode *> &nodes, AcArray<AcGraphNode *> &relatedNodes) const;
  
      /// <summary> 
      /// This function returns an iterator at the beginning of the iterated range
      /// </summary>
      /// <returns> AcGraph::iterator </returns>
      iterator begin();  
  
      /// <summary> 
      /// This function returns a cons_iterator at the beginning of the iterated range
      /// </summary>
      /// <returns> AcGraph::const_iterator </returns>
      const_iterator begin() const;
  
      /// <summary> 
      /// This function returns an iterator at the end of the iterated range
      /// </summary>
      /// <returns> AcGraph::iterator </returns>
      iterator end();
  
      /// <summary> 
      /// This function returns a cons_iterator at the end of the iterated range
      /// </summary>
      /// <returns> AcGraph::const_iterator </returns>
      const_iterator end() const;
  
      /// <summary> 
      /// This function returns the size(number) of nodes in the graph
      /// </summary>
      /// <returns> size_t </returns>
      size_t size() const;
  
      /// <summary> 
      /// This function removes all the nodes in the graph, it also optionally deletes the pointer 
      /// of each AcGraphNode in the AcGraph
      /// <param name="bDelete"> if the nodes are to be deleted. </param>
      /// </summary>
      /// <returns> none </returns>
      void clear(bool bDelete);
  
      /// <summary> 
      /// This function is called by dwgOut(). Its purpose is to allow the object to write out its data.
      /// </summary>
      /// <returns> Acad::ErrorStatus </returns>
      virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler *pFiler) const;     
  
      /// <summary> 
      /// This function is called by dwgIn(). Its purpose is to allow the object to read in its data.
      /// </summary>
      /// <returns> Acad::ErrorStatus </returns>
      virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler *pFiler);    
  
      /// <summary> 
      /// This function is called by dxfOut(). Its purpose is to allow the object to write out its data.
      /// </summary>
      /// <returns> Acad::ErrorStatus </returns>
      virtual Acad::ErrorStatus dxfOutFields(AcDbDxfFiler *pFiler) const;   
  
      /// <summary> 
      /// This function is called by dxfIn(). Its purpose is to allow the object to read in its data.
      /// </summary>
      /// <returns> Acad::ErrorStatus </returns>
      virtual Acad::ErrorStatus dxfInFields (AcDbDxfFiler *pFiler);  
   
      /// <summary> 
      /// Returns id of the graph, by default it is 0 if setGraphId was not called to assign an id previously
      /// </summary>
      /// <returns> Acad::UInt32 </returns>
      virtual Adesk::UInt32     graphId() const;
  
      /// <summary> 
      /// Sets id of the graph. When the owningObject has more than one graphs, it is important to assign a 
      /// unique id to each of the graphs
      /// </summary>
      /// <returns> none </returns>
      virtual void              setGraphId(Adesk::UInt32 id);
  
  protected:
  
      AcImpGraph* mpImpGraph;
  
  private:
      /// <summary> 
      /// Disabled copy constructor
      /// </summary>
      AcGraph(const AcGraph &graph);
  
      /// <summary> 
      /// Disabled assignment operator
      /// </summary>
      AcGraph &operator = (const AcGraph &graph);
  
  friend class AcGraphNode;
  friend class AcImpGraphNode;
  friend class AcImpGraph;
  };
  
  #pragma pack (pop)
  