//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// C o n n e c t i v i t y
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides facilities to solve connectivity problems in graphs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/connectivity.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemConnectivity
#define guGraphProblemConnectivity

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef GRAPH_PROBLEM_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemConnectivity
#define private_area graphProblemConnectivity_private

namespace public_area  { /*NAMESPACE*/ using namespace graph; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemConnectivity
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
/*ALIAS*/
#define tdGraph class prArcData,class prNodeData //

/*ALIAS*/
#define tuGraph prArcData,prNodeData //

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {
 template <tdGraph>
 void findConnectedComponent(clGraph<tuGraph> &,tyNodeKey,std_vector(clNode<tuGraph> *) &);

 template <tdGraph>
 void findConnectedComponents(clGraph<tuGraph> &,std_vector(std_vector(clNode<tuGraph> *)) &);

 template <tdGraph>
 void findStronglyConnectedComponent(clGraph<tuGraph> &,tyNodeKey,std_vector(clNode<tuGraph> *) &);

 template <tdGraph>
 void findStronglyConnectedComponents(clGraph<tuGraph> &,
                                      std_vector(std_vector(clNode<tuGraph> *)) &);
}

namespace private_area {
 template <tdGraph>
 void findStronglyConnectedComponent(clGraph<tuGraph> &,clNode<tuGraph> &,
                                     std_vector(clNode<tuGraph> *) &,tyMark agMark);

 testing_mode ( function void test(void); )
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clString,goDataLocation,?);

// X X X  Interface //------------------------------------------------------------------------------
namespace {}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// X X X  Inline //---------------------------------------------------------------------------------
namespace {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------FindConnectedComponent
 /*FUNCTION*/ /* Finds the connected graph component that contains a given node. */
 template <tdGraph>
 void findConnectedComponent(clGraph<tuGraph> & agGraph,tyNodeKey agNodeKey,
                             std_vector(clNode<tuGraph> *) & agComponent) {
  typedef typename clNode<tuGraph>::cpArcX::const_iterator cpArcIterator;
  typedef std_vector(clNode<tuGraph> *)                    cpNodeS;

  tyMark            lcMark = ++(agGraph.mark());
  clNode<tuGraph> & lcNode = agGraph.node(agNodeKey);

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpArcIterator     lcLastArc;
  clNode<tuGraph> * lcNode1;
  clNode<tuGraph> * lcNode2;
  cpNodeS           lcNodeS;
  cpNodeS           lcSet;

  agComponent.erase(agComponent.begin(),agComponent.end());
  lcNode.mark()=lcMark;
  lcNodeS.push_back(&lcNode);

  while (lcNodeS.size()>0) {
   lcNode1=lcNodeS.back();
   lcNodeS.pop_back();
   agComponent.push_back(lcNode1);
   lcCurrentArc=lcNode1->incomingArcs().begin();
   lcLastArc=lcNode1->incomingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode2=lcArc->sourceNode();

    if (lcNode2->mark()<lcMark) {
     lcNode2->mark()=lcMark;
     lcNodeS.push_back(lcNode2);
    }

    lcCurrentArc++;
   }

   lcCurrentArc=lcNode1->outgoingArcs().begin();
   lcLastArc=lcNode1->outgoingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode2=lcArc->targetNode();

    if (lcNode2->mark()<lcMark) {
     lcNode2->mark()=lcMark;
     lcNodeS.push_back(lcNode2);
    }

    lcCurrentArc++;
   }
  }
 }
 //--------------------------------------------------------------------------FindConnectedComponents
 /*FUNCTION*/ /* Finds the connected components of a graph. */
 template <tdGraph>
 void findConnectedComponents(clGraph<tuGraph> & agGraph,
                              std_vector(std_vector(clNode<tuGraph> *)) & agComponentS) {
  typedef std_vector(clNode<tuGraph> *)                      cpNodeS;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  cpNodeIterator lcCurrentNode = agGraph.nodes().begin();
  cpNodeIterator lcLastNode    = agGraph.nodes().end();
  tyMark         lcMark        = agGraph.mark();

  while (lcCurrentNode!=lcLastNode) {
   while (lcCurrentNode!=lcLastNode and (*lcCurrentNode).second->mark()>lcMark) lcCurrentNode++;

   if (lcCurrentNode!=lcLastNode) {
    agComponentS.push_back(cpNodeS());
    findConnectedComponent(agGraph,(*lcCurrentNode).second->key(),agComponentS.back());
   }
  }
 }
 //-------------------------------------------------------------------FindStronglyConnectedComponent
 /*FUNCTION*/ /* Finds the strongly connected graph component that contains a given node. */
 template <tdGraph>
 void findStronglyConnectedComponent(clGraph<tuGraph> & agGraph,tyNodeKey agNodeKey,
                                     std_vector(clNode<tuGraph> *) & agComponent) {
  typedef typename clNode<tuGraph>::cpArcX::const_iterator cpArcIterator;
  typedef std_vector(clNode<tuGraph> *)                    cpNodeS;

  tyMark            lcMark1     = ++(agGraph.mark());
  tyMark            lcMark2     = ++(agGraph.mark());
  tyMark            lcMark3     = ++(agGraph.mark());
  clNode<tuGraph> & lcFirstNode = agGraph.node(agNodeKey);

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpArcIterator     lcLastArc;
  cpNodeS           lcMarkedNodeS;
  clNode<tuGraph> * lcNode;
  cpNodeS           lcNodeS;

  agComponent.erase(agComponent.begin(),agComponent.end());

  // Direct Spreading //
  lcFirstNode.mark()=lcMark1;
  lcNodeS.push_back(&lcFirstNode);

  while (lcNodeS.size()>0) {
   lcNode=lcNodeS.back();
   lcNodeS.pop_back();
   lcCurrentArc=lcNode->incomingArcs().begin();
   lcLastArc=lcNode->incomingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode=lcArc->sourceNode();

    if (lcNode->mark()<lcMark1) {
     lcNode->mark()=lcMark1;
     lcNodeS.push_back(lcNode);
    }

    lcCurrentArc++;
   }
  }

  // Indirect Spreading //
  lcFirstNode.mark()=lcMark3;
  lcNodeS.push_back(&lcFirstNode);

  while (lcNodeS.size()>0) {
   lcNode=lcNodeS.back();
   lcNodeS.pop_back();
   if (lcNode->mark()==lcMark3) agComponent.push_back(lcNode);
   lcCurrentArc=lcNode->outgoingArcs().begin();
   lcLastArc=lcNode->outgoingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode=lcArc->targetNode();

    if (lcNode->mark()<lcMark2) {
     if (lcNode->mark()==lcMark1) lcNode->mark()=lcMark3;
     else lcNode->mark()=lcMark2;

     lcNodeS.push_back(lcNode);
    }

    lcCurrentArc++;
   }
  }
 }
 //------------------------------------------------------------------FindStronglyConnectedComponents
 /*FUNCTION*/ /* Finds the strongly connected components of a graph. */
 template <tdGraph>
 void findStronglyConnectedComponents(clGraph<tuGraph> & agGraph,
                                      std_vector(std_vector(clNode<tuGraph> *)) & agComponentS) {
  typedef std_vector(clNode<tuGraph> *)                      cpNodeS;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  cpNodeIterator lcCurrentNode = agGraph.nodes().begin();
  cpNodeIterator lcLastNode    = agGraph.nodes().end();
  tyMark         lcMark        = agGraph.mark();

  while (lcCurrentNode!=lcLastNode) {
   while (lcCurrentNode!=lcLastNode and (*lcCurrentNode).second->mark()>lcMark) lcCurrentNode++;

   if (lcCurrentNode!=lcLastNode) {
    agComponentS.push_back(cpNodeS());

    private_area::findStronglyConnectedComponent(agGraph,*((*lcCurrentNode).second),
                                                 agComponentS.back(),lcMark);
   }
  }
 }
}

namespace private_area {
 //-------------------------------------------------------------------FindStronglyConnectedComponent
 template <tdGraph>
 void findStronglyConnectedComponent(clGraph<tuGraph> & agGraph,clNode<tuGraph> & agNode,
                                     std_vector(clNode<tuGraph> *) & agComponent,tyMark agMark) {
  typedef typename clNode<tuGraph>::cpArcX::const_iterator cpArcIterator;
  typedef std_vector(clNode<tuGraph> *)                    cpNodeS;
  typedef typename cpNodeS::const_iterator                 cpNodeIterator;

  tyMark lcMark1 = ++(agGraph.mark());
  tyMark lcMark2 = ++(agGraph.mark());
  tyMark lcMark3 = ++(agGraph.mark());

  clArc<tuGraph> *  lcArc;
  cpArcIterator     lcCurrentArc;
  cpNodeIterator    lcCurrentNode;
  cpArcIterator     lcLastArc;
  cpNodeIterator    lcLastNode;
  cpNodeS           lcMarkedNodeS;
  clNode<tuGraph> * lcNode;
  cpNodeS           lcNodeS;

  agComponent.erase(agComponent.begin(),agComponent.end());

  // Direct Spreading //
  agNode.mark()=lcMark1;
  lcNodeS.push_back(&agNode);

  while (lcNodeS.size()>0) {
   lcNode=lcNodeS.back();
   lcNodeS.pop_back();
   lcCurrentArc=lcNode->incomingArcs().begin();
   lcLastArc=lcNode->incomingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode=lcArc->sourceNode();

    if (lcNode->mark()<lcMark1) {
     lcNode->mark()=lcMark1;
     lcNodeS.push_back(lcNode);
     lcMarkedNodeS.push_back(lcNode);
    }

    lcCurrentArc++;
   }
  }

  // Indirect Spreading //
  agNode.mark()=lcMark3;
  lcNodeS.push_back(&agNode);

  while (lcNodeS.size()>0) {
   lcNode=lcNodeS.back();
   lcNodeS.pop_back();
   if (lcNode->mark()==lcMark3) agComponent.push_back(lcNode);
   lcCurrentArc=lcNode->outgoingArcs().begin();
   lcLastArc=lcNode->outgoingArcs().end();

   while (lcCurrentArc!=lcLastArc) {
    lcArc=(*lcCurrentArc).second;
    lcNode=lcArc->targetNode();

    if (lcNode->mark()<lcMark2) {
     if (lcNode->mark()==lcMark1) lcNode->mark()=lcMark3;
     else {
      lcNode->mark()=lcMark2;
      lcMarkedNodeS.push_back(lcNode);
     }

     lcNodeS.push_back(lcNode);
    }

    lcCurrentArc++;
   }
  }

  // Unmarking //
  lcCurrentNode=lcMarkedNodeS.begin();
  lcLastNode=lcMarkedNodeS.end();

  while (lcCurrentNode!=lcLastNode) {
   if ((*lcCurrentNode)->mark()!=lcMark3) (*lcCurrentNode)->mark()=agMark;
   lcCurrentNode++;
  }
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#undef tdGraph
#undef tuGraph
#endif
 
//==================================================================================================
// G r a p h _ p r o b l e m                                                         Implementation
// C o n n e c t i v i t y
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/connectivity.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/connectivity.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemConnectivity
#define private_area graphProblemConnectivity_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Connectivity");

// Initialization //--------------------------------------------------------------------------------
#undef iniGraphProblemConnectivity
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clString,goDataLocation);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()
                     +"graph_problem"+fileNameSeparator()+"connectivity"));
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  try {
   environment::informTermination(goModuleName);

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

// End //-------------------------------------------------------------------------------------------
}