//==================================================================================================
// P r o g r a m                                                                          Interface
// S o l v e _ g r a p h
// C o n s o l e
//                                                                                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 execute the program in console mode. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "program/solve_graph/console.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guProgramSolveGraphConsole
#define guProgramSolveGraphConsole

// Headers //---------------------------------------------------------------------------------------
#include <map> /*INCLUDE*/
#include <bpp/calendar.hpp> /*INCLUDE*/
#include <bpp/graph_problem.hpp> /*INCLUDE*/

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programSolveGraphConsole
#define private_area programSolveGraphConsole_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniProgramSolveGraphConsole
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------

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

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  { function tyReturn run(tyCardinal,tcString []); }
namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area { /*ERROR*/ extern_error erSyntax; /* Syntax error in the command line. */ }

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

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

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

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// P r o g r a m                                                                     Implementation
// S o l v e _ g r a p h
// C o n s o l e
//                                                                                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__ "program/solve_graph/console.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define PROGRAM_SOLVE_GRAPH_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/program/solve_graph/console.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programSolveGraphConsole
#define private_area programSolveGraphConsole_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Program/Solve_graph/Console");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area { static_error erSyntax; }

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*FUNCTION*/
 /* Start function of the program. It deals with the commands the user gives through a command
    line and executes the appropriate functions. */
 function tyReturn run(tyCardinal agCounter,tcString agParameterS[]) {
  method_name("run");

  clString  lcCommand;
  tyBoolean lcError;

  tyCardinal lcCounter = 1;

  environment_private::goProgramName = "S o l v e   G r a p h";

  try {
   if (agCounter==1) send_error(erSyntax);

   while (lcCounter<agCounter) {
    lcCommand=agParameterS[lcCounter];
    lcError=true;

    //---------------------------------------------------------------------------------------Context
    if (lcCommand=="+context") {
     lcError=false;
     environment::nextLine();
     environment::outContext();
    }

    //------------------------------------------------------------------------------------------Help
    else if (lcCommand=="+help") {
     lcError=false;
     environment::nextLine();
     environment::inform("-=-=- H E L P -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
     environment::out(" This program solves various problems in graphs.",true,true);
     environment::nextLine();
     environment::out(" * Syntax: [commands] [input file] [output file]",true,true);
     environment::nextLine();
     environment::out(" * Commands:",true,true);
     environment::out("   +context       = shows the context of the program's running.",true,true);
     environment::out("   +help          = shows this help.",true,true);
     environment::out("   +info          = shows information about the program.",true,true);
     environment::out("   +license       = shows the license of the program.",true,true);
     environment::out("   +checkflow     = verifies that the flow in a graph is valid and",true,true);
     environment::out("                    compatible.",true,true);
     environment::out("   +connect <x>   = finds the connected component that contains the",true,true);
     environment::out("                    node <x>.",true,true);
     environment::out("   +connects      = finds the connected components of the graph.",true,true);
     environment::out("   +cycles        = finds as independent cycles as possible in the graph.",true,true);
     environment::out("   +distances     = finds the shortest distance between all pairs of",true,true);
     environment::out("                    nodes in the graph.",true,true);
     environment::out("   +maxflow       = solves the maximum flow problem in the graph,",true,true);
     environment::out("                    using Ford and Fulkerson's method.",true,true);
     environment::out("   +minflowlp     = translates the minimum linear cost flow problem",true,true);
     environment::out("                    in the graph into a linear program.",true,true);
     environment::out("   +minflow1      = solves the minimum linear cost flow problem in the",true,true);
     environment::out("                    graph as a linear program.",true,true);
     environment::out("   +minflow2      = solves the minimum linear cost flow problem in the",true,true);
     environment::out("                    graph, using the cycle-canceling method.",true,true);
     environment::out("   +minflow3      = solves the minimum linear cost flow problem in the",true,true);
     environment::out("                    graph, using the cost-scaling method.",true,true);
     environment::out("   +mintree1      = solves the minimum spanning tree problem in the",true,true);
     environment::out("                    graph, using Kruskal's method.",true,true);
     environment::out("   +mintree2      = solves the minimum spanning tree problem in the",true,true);
     environment::out("                    graph, using Prim's method.",true,true);
     environment::out("   +negativecycle = finds a negative cycle for the minimum linear cost",true,true);
     environment::out("                    flow problem in the graph.",true,true);
     environment::out("   +path1 <x> <y> = finds the shortest path between the node <x> and the",true,true);
     environment::out("                    node <y>, using Bellman's method.",true,true);
     environment::out("   +path2 <x> <y> = finds the shortest path between the node <x> and the",true,true);
     environment::out("                    node <y>, using Dijkstra's method.",true,true);
     environment::out("   +path3 <x> <y> = finds the shortest path between the node <x> and the",true,true);
     environment::out("                    node <y>, using Bellman & Ford's method.",true,true);
     environment::out("   +serial1       = decomposes the graph into serial-parallel components",true,true);
     environment::out("                    with the method I.",true,true);
     environment::out("   +serial2       = decomposes the graph into serial-parallel components",true,true);
     environment::out("                    with the method II.",true,true);
     environment::out("   +serial3       = decomposes the graph into serial-parallel components",true,true);
     environment::out("                    with the method III.",true,true);
     environment::out("   +sconnect <x>  = finds the strongly connected component that contains",true,true);
     environment::out("                    the node <x>.",true,true);
     environment::out("   +sconnects     = finds the strongly connected components of the graph.",true,true);
     environment::out("   +topological   = finds a topological ordering of the nodes",true,true);
     environment::out("                    of the graph.",true,true);
     environment::out("   +tree          = finds a covering tree in the graph.",true,true);
     environment::out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);
    }

    //------------------------------------------------------------------------------------------Info
    else if (lcCommand=="+info") {
     lcError=false;
     environment::nextLine();
     environment::outInformation();
    }

    //---------------------------------------------------------------------------------------License
    else if (lcCommand=="+license") {
     lcError=false;
     environment::nextLine();
     environment::outLicense();
    }

    //---------------------------------------------------------------------------------------Connect
    else if (lcCommand=="+connect") {
     if (agCounter-lcCounter>3) {
      std_vector(clGenericNode *) lcComponent;
      clInFile                    lcFin;
      clOutFile                   lcFout;
      clGenericGraph              lcGraph;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+2],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Connected Component...");

      graphProblemConnectivity::
      findConnectedComponent(lcGraph,nodeKey(clString(agParameterS[lcCounter+1])),lcComponent);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+3],ios::out|ios::trunc);
      lcFout << "Component = " << lcComponent;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=3;
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Sconnect
    else if (lcCommand=="+sconnect") {
     if (agCounter-lcCounter>3) {
      std_vector(clGenericNode *) lcComponent;
      clInFile                    lcFin;
      clOutFile                   lcFout;
      clGenericGraph              lcGraph;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+2],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Strongly Connected Component...");

      graphProblemConnectivity::findStronglyConnectedComponent(
      lcGraph,nodeKey(clString(agParameterS[lcCounter+1])),lcComponent);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+3],ios::out|ios::trunc);
      lcFout << "Component = " << lcComponent;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=3;
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Connects
    else if (lcCommand=="+connects") {
     if (agCounter-lcCounter>2) {
      typedef std_vector(std_vector(clGenericNode *)) clComponentS;

      clComponentS                 lcComponentS;
      clComponentS::const_iterator lcCurrentComponent;
      clInFile                     lcFin;
      clOutFile                    lcFout;
      clGenericGraph               lcGraph;
      clComponentS::const_iterator lcLastComponent;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Connected Components...");
      graphProblemConnectivity::findConnectedComponents(lcGraph,lcComponentS);
      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcCurrentComponent=lcComponentS.begin();
      lcLastComponent=lcComponentS.end();

      if (lcCurrentComponent==lcLastComponent) lcFout << "None" << end_line;

      while (lcCurrentComponent!=lcLastComponent) {
       lcFout << "Component = " << *(lcCurrentComponent);
       lcCurrentComponent++;
      }

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //-------------------------------------------------------------------------------------Sconnects
    else if (lcCommand=="+sconnects") {
     if (agCounter-lcCounter>2) {
      typedef std_vector(std_vector(clGenericNode *)) clComponentS;

      clComponentS                 lcComponentS;
      clComponentS::const_iterator lcCurrentComponent;
      clInFile                     lcFin;
      clOutFile                    lcFout;
      clGenericGraph               lcGraph;
      clComponentS::const_iterator lcLastComponent;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Strongly Connected Components...");
      graphProblemConnectivity::findStronglyConnectedComponents(lcGraph,lcComponentS);
      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcCurrentComponent=lcComponentS.begin();
      lcLastComponent=lcComponentS.end();

      if (lcCurrentComponent==lcLastComponent) lcFout << "None" << end_line;

      while (lcCurrentComponent!=lcLastComponent) {
       lcFout << "Component = " << *(lcCurrentComponent);
       lcCurrentComponent++;
      }

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Mintree1
    else if (lcCommand=="+mintree1") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinSpanningTree::clCostData                         clCostData;
      typedef graphProblemMinSpanningTree::clKruskalAlgo<clCostData,clNoData> clKruskalAlgo;
      typedef graphProblemMinSpanningTree::clSpanningGraph                    clSpanningGraph;

      clInFile        lcFin;
      clOutFile       lcFout;
      clSpanningGraph lcGraph;
      clGraphLayout   lcGraphLayout;
      clSpanningGraph lcTree;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Minimum Spanning Tree (Kruskal's Method)...");
      clKruskalAlgo().run(lcGraph,lcTree);
      environment::out("Total Cost = ",false,true);
      environment::out(graphProblemMinSpanningTree::totalCost(lcTree),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcFout << lcTree;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Mintree2
    else if (lcCommand=="+mintree2") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinSpanningTree::clCostData                      clCostData;
      typedef graphProblemMinSpanningTree::clPrimAlgo<clCostData,clNoData> clPrimAlgo;
      typedef graphProblemMinSpanningTree::clSpanningGraph                 clSpanningGraph;

      clInFile        lcFin;
      clOutFile       lcFout;
      clSpanningGraph lcGraph;
      clGraphLayout   lcGraphLayout;
      clSpanningGraph lcTree;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Minimum Spanning Tree (Prim's Method)...");
      clPrimAlgo().run(lcGraph,lcTree);
      environment::out("Total Cost = ",false,true);
      environment::out(graphProblemMinSpanningTree::totalCost(lcTree),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcFout << lcTree;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //-----------------------------------------------------------------------------------------Path1
    else if (lcCommand=="+path1") {
     if (agCounter-lcCounter>4) {
      typedef graphProblemShortestPath::clLengthData                         clLengthData;
      typedef graphProblemShortestPath::clBellmanAlgo<clLengthData,clNoData> clBellmanAlgo;
      typedef graphProblemShortestPath::clLengthArc                          clLengthArc;
      typedef graphProblemShortestPath::clLengthGraph                        clLengthGraph;

      clInFile                  lcFin;
      clOutFile                 lcFout;
      clLengthGraph             lcGraph;
      std_vector(clLengthArc *) lcPath;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+3],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Shortest Path (Bellman's Method)...");

      clBellmanAlgo().run(lcGraph,arcKey(clString(agParameterS[lcCounter+1])),
                          arcKey(clString(agParameterS[lcCounter+2])),lcPath);

      environment::out("Length = ",false,true);

      if (lcPath.size()==0) environment::out("+oo",true);
      else environment::out(graphProblemShortestPath::length(lcPath),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+4],ios::out|ios::trunc);
      lcFout << "Path = " << lcPath;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=4;
      lcError=false;
     }
    }

    //-----------------------------------------------------------------------------------------Path2
    else if (lcCommand=="+path2") {
     if (agCounter-lcCounter>4) {
      typedef graphProblemShortestPath::clLengthArc                           clLengthArc;
      typedef graphProblemShortestPath::clDijkstraAlgo<clLengthData,clNoData> clDijkstraAlgo;
      typedef graphProblemShortestPath::clLengthArc                           clLengthArc;
      typedef graphProblemShortestPath::clLengthGraph                         clLengthGraph;

      clInFile                  lcFin;
      clOutFile                 lcFout;
      clLengthGraph             lcGraph;
      std_vector(clLengthArc *) lcPath;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+3],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Shortest Path (Dijkstra's Method)...");

      clDijkstraAlgo().run(lcGraph,arcKey(clString(agParameterS[lcCounter+1])),
                           arcKey(clString(agParameterS[lcCounter+2])),lcPath);

      environment::out("Length = ",false,true);
      environment::out(graphProblemShortestPath::length(lcPath),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+4],ios::out|ios::trunc);
      lcFout << "Path = " << lcPath;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=4;
      lcError=false;
     }
    }

    //-----------------------------------------------------------------------------------------Path3
    else if (lcCommand=="+path3") {
     if (agCounter-lcCounter>4) {
      typedef graphProblemShortestPath::clLengthData                      clLengthData;
      typedef graphProblemShortestPath::clFordAlgo<clLengthData,clNoData> clFordAlgo;
      typedef graphProblemShortestPath::clLengthArc                       clLengthArc;
      typedef graphProblemShortestPath::clLengthGraph                     clLengthGraph;

      clInFile                  lcFin;
      clOutFile                 lcFout;
      clLengthGraph             lcGraph;
      std_vector(clLengthArc *) lcPath;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+3],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Shortest Path (Bellman & Ford's Method)...");

      clFordAlgo().run(lcGraph,arcKey(clString(agParameterS[lcCounter+1])),
                       arcKey(clString(agParameterS[lcCounter+2])),lcPath);

      environment::out("Length = ",false,true);
      environment::out(graphProblemShortestPath::length(lcPath),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+4],ios::out|ios::trunc);
      lcFout << "Path = " << lcPath;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=4;
      lcError=false;
     }
    }

    //-------------------------------------------------------------------------------------Distances
    else if (lcCommand=="+distances") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemShortestPath::clLengthGraph clLengthGraph;
      typedef graphProblemShortestPath::clLengthNode  clLengthNode;
      typedef std_pair(clLengthNode *,clLengthNode *) clPair;
      typedef std_map(clPair,tyReal)                  clDistanceX;

      clDistanceX::const_iterator lcCurrentPair;
      clDistanceX                 lcDistanceX;
      clInFile                    lcFin;
      clOutFile                   lcFout;
      clLengthGraph               lcGraph;
      clDistanceX::const_iterator lcLastPair;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Computing Shortest Distances (Dantzig's Method)...");
      graphProblemShortestPath::computeAllShortestDistance(lcGraph,lcDistanceX);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcCurrentPair=lcDistanceX.begin();
      lcLastPair=lcDistanceX.end();

      while (lcCurrentPair!=lcLastPair) {
       lcFout << (*lcCurrentPair).first.first->key() << " To ";
       lcFout << (*lcCurrentPair).first.second->key() << " = ";
       lcFout << (*lcCurrentPair).second << end_line;
       lcCurrentPair++;
      }

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //---------------------------------------------------------------------------------------Maxflow
    else if (lcCommand=="+maxflow") {
     if (agCounter-lcCounter>2) {
      tyBoolean lcOk = true;

      clInFile                          lcFin;
      clOutFile                         lcFout;
      graphProblemMaxFlow::clFlowGraph  lcGraph;
      clGraphLayout                     lcGraphLayout;
      graphProblemMaxFlow::clFlowNode * lcSourceNode;
      graphProblemMaxFlow::clFlowNode * lcTargetNode;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Maximum Flow (Ford and Fulkerson's Method)...");
      lcSourceNode=firstNode(lcGraph);
      lcTargetNode=lastNode(lcGraph);
      environment::out("Source Node = ",false,true);

      if (lcSourceNode==nil) {
       environment::out("Not Found",true);
       lcOk=false;
      }
      else environment::out(lcSourceNode->key(),true);

      environment::out("Target Node = ",false,true);

      if (lcTargetNode==nil) {
       environment::out("Not Found",true);
       lcOk=false;
      }
      else environment::out(lcTargetNode->key(),true);

      if (lcOk) {
       graphProblemMaxFlow::findMaximumFlow(lcGraph,*lcSourceNode,*lcTargetNode);
       environment::out("Total Flow = ",false,true);
       environment::out(graphProblemMaxFlow::totalOutgoingFlow(*lcSourceNode),true);

       environment::inform("Writing Output File...");
       open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
       lcFout << lcGraph;
       if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
       lcFout << lcGraphLayout;
       close(lcFout);
       if (lcFout.fail()) send_error(erFileWriting);
      }

      lcCounter+=2;
      lcError=false;
     }
    }

    //----------------------------------------------------------------------------------------Cycles
    else if (lcCommand=="+cycles") {
     if (agCounter-lcCounter>2) {
      clCycleS::const_iterator lcCurrentCycle;
      clCycleS                 lcCycleS;
      clInFile                 lcFin;
      clOutFile                lcFout;
      clGenericGraph           lcGraph;
      clCycleS::const_iterator lcLastCycle;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Find Cycles...");
      findCycles(lcGraph,lcCycleS);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcCurrentCycle=lcCycleS.begin();
      lcLastCycle=lcCycleS.end();
      if (lcCurrentCycle==lcLastCycle) lcFout << "None" << end_line;

      while (lcCurrentCycle!=lcLastCycle) {
       lcFout << "Cycle = " << *lcCurrentCycle << end_line;
       lcCurrentCycle++;
      }

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //-------------------------------------------------------------------Serial1 & Serial2 & Serial3
    else if (lcCommand=="+serial1" or lcCommand=="+serial2" or lcCommand=="+serial3") {
     if (agCounter-lcCounter>2) {
      typedef
      clBinaryTree<graphProblemSerialParallel::clSerialParallelData<clGenericData,clGenericData> >
      clTree;

      typedef graphProblemSerialParallel::clDecomposeAlgoI<clGenericData,clGenericData>   clAlgoI;
      typedef graphProblemSerialParallel::clDecomposeAlgoII<clGenericData,clGenericData>  clAlgoII;
      typedef graphProblemSerialParallel::clDecomposeAlgoIII<clGenericData,clGenericData> clAlgoIII;
      typedef std_vector(clTree *)                                                        clTreeS;

      clTreeS::const_iterator lcCurrentTree;
      clTreeS                 lcTreeS;
      clInFile                lcFin;
      clOutFile               lcFout;
      clGenericGraph          lcGraph;
      clTreeS::const_iterator lcLastTree;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      if (lcCommand=="+serial1") {
       environment::inform("Searching Serial-Parallel Components (Method I)...");
       clAlgoI().run(lcGraph,lcTreeS);
      }
      else if (lcCommand=="+serial2") {
       environment::inform("Searching Serial-Parallel Components (Method II)...");
       clAlgoII().run(lcGraph,lcTreeS);
      }
      else {
       environment::inform("Searching Serial-Parallel Components (Method III)...");
       clAlgoIII().run(lcGraph,lcTreeS);
      }

      environment::out("Number Components = ",false,true);
      environment::out(tyCardinal(lcTreeS.size()),true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcCurrentTree=lcTreeS.begin();
      lcLastTree=lcTreeS.end();
      if (lcCurrentTree==lcLastTree) lcFout << "None" << end_line;

      while (lcCurrentTree!=lcLastTree) {
       lcFout << *(*lcCurrentTree);
       delete_object(*lcCurrentTree);
       lcCurrentTree++;
       if (lcCurrentTree!=lcLastTree) lcFout << end_line;
      }

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //------------------------------------------------------------------------------------------Tree
    else if (lcCommand=="+tree") {
     if (agCounter-lcCounter>2) {
      clInFile       lcFin;
      clOutFile      lcFout;
      clGenericGraph lcGraph;
      clGraphLayout  lcGraphLayout;
      clGenericGraph lcTree;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Find Covering Tree...");
      findCoveringTree(lcGraph,lcTree);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcFout << lcTree;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    //-------------------------------------------------------------------------------------Checkflow
    else if (lcCommand=="+checkflow") {
     if (agCounter-lcCounter>1) {
      clInFile                               lcFin;
      clOutFile                              lcFout;
      graphProblemMinCostFlow::clLinearGraph lcGraph;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Checking Compatibility...");
      lcGraph.solved()=graphProblemMinCostFlow::checkCompatibility(lcGraph);

      if (lcGraph.solved())
       environment::out("Compatible Flow",true,true);
      else
       environment::out("Incompatible Flow",true,true);

      environment::inform("Checking Flow...");
      lcGraph.solved()=graphProblemMinCostFlow::checkFlow(lcGraph);

      if (lcGraph.solved())
       environment::out("Valid Flow",true,true);
      else
       environment::out("Invalid Flow",true,true);

      lcError=false;
     }
    }

    //-------------------------------------------------------------------------------------Minflowlp
    else if (lcCommand=="+minflowlp") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinCostFlow::clLinearArcData clLinearArcData;
      typedef graphProblemMinCostFlow::clNodeData      clNodeData;

      clInFile                               lcFin;
      clOutFile                              lcFout;
      graphProblemMinCostFlow::clLinearGraph lcGraph;
      graphProblemMinCostFlow::clFlowSystem  lcSystem;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Translating Into Linear Program...");
      graphProblemMinCostFlowLinearSystem::clSolveAlgo<clLinearArcData,clNodeData>().
      buildLinearSystem(lcSystem,lcGraph);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[++lcCounter],ios::out|ios::trunc);
      lcFout << lcSystem;
      close(lcFout);
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Minflow1
    else if (lcCommand=="+minflow1") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinCostFlowStructure::clLinearArcData   clArcData;
      typedef graphProblemMinCostFlowStructure::clNodeData        clNodeData;
      typedef graphProblemMinCostFlowStructure::clVariableContent clVariableContent;
      typedef linearSystemSolver::clSolver<clVariableContent>     clLinearSolver;

      typedef graphProblemMinCostFlowLinearSystem::clSolveAlgo<clArcData,clNodeData> clSolveAlgo;

      clInFile                      lcFin;
      clOutFile                     lcFout;
      clGraph<clArcData,clNodeData> lcGraph;
      clGraphLayout                 lcGraphLayout;
      tyInteger                     lcNbIteration;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Minimum Cost Flow (Linear Program Resolution)...");
      lcNbIteration=clSolveAlgo().run(lcGraph,clLinearSolver::defaultSolver());
      environment::out("Result = ",false,true);

      if (lcNbIteration<0) environment::out("Inconsistent Constraints",true);
      else {
       environment::out("Consistent Constraints",true);
       environment::out("Iterations = ",false,true);
       environment::out(lcNbIteration,true);
       environment::out("Total Cost = ",false,true);
       environment::out(graphProblemMinCostFlow::totalCost(lcGraph),true);
      }

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[++lcCounter],ios::out|ios::trunc);
      lcFout << lcGraph;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
     }

     lcError=false;
    }

    //--------------------------------------------------------------------------------------Minflow2
    else if (lcCommand=="+minflow2") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinCostFlow::clLinearArcData clArcData;
      typedef graphProblemMinCostFlow::clNodeData      clNodeData;

      typedef graphProblemMinCostFlowCycleCanceling::clSolveAlgo<clArcData,clNodeData> clSolveAlgo;

      clInFile                      lcFin;
      clOutFile                     lcFout;
      clGraph<clArcData,clNodeData> lcGraph;
      clGraphLayout                 lcGraphLayout;
      tyInteger                     lcNbIteration;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Minimum Cost Flow (Cycle-Canceling Method)...");
      lcNbIteration=clSolveAlgo().run(lcGraph);
      environment::out("Result = ",false,true);

      if (lcNbIteration<0) environment::out("Inconsistent Constraints",true);
      else {
       environment::out("Consistent Constraints",true);
       environment::out("Iterations = ",false,true);
       environment::out(lcNbIteration,true);
       environment::out("Total Cost = ",false,true);
       environment::out(graphProblemMinCostFlow::totalCost(lcGraph),true);
      }

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[++lcCounter],ios::out|ios::trunc);
      lcFout << lcGraph;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
      lcError=false;
     }
    }

    //--------------------------------------------------------------------------------------Minflow3
    else if (lcCommand=="+minflow3") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinCostFlow::clLinearArcData clArcData;
      typedef graphProblemMinCostFlow::clNodeData      clNodeData;

      typedef graphProblemMinCostFlowCostScaling::clSolveAlgo<clArcData,clNodeData> clSolveAlgo;

      clInFile                      lcFin;
      clOutFile                     lcFout;
      clGraph<clArcData,clNodeData> lcGraph;
      clGraphLayout                 lcGraphLayout;
      tyInteger                     lcNbIteration;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      lcFin >> lcGraphLayout;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Minimum Cost Flow (Cost-Scaling Method)...");
      lcNbIteration=clSolveAlgo().run(lcGraph);
      environment::out("Result = ",false,true);

      if (lcNbIteration<0) environment::out("Inconsistent Constraints",true);
      else {
       environment::out("Consistent Constraints",true);
       environment::out("Iterations = ",false,true);
       environment::out(lcNbIteration,true);
       environment::out("Total Cost = ",false,true);
       environment::out(graphProblemMinCostFlow::totalCost(lcGraph),true);
      }

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[++lcCounter],ios::out|ios::trunc);
      lcFout << lcGraph;
      if (lcGraphLayout.size()>0) lcFout << end_line << end_line;
      lcFout << lcGraphLayout;
      close(lcFout);
      lcError=false;
     }
    }

    //---------------------------------------------------------------------------------NegativeCycle
    else if (lcCommand=="+negativecycle") {
     if (agCounter-lcCounter>2) {
      typedef graphProblemMinCostFlow::clLinearArcData clArcData;
      typedef graphProblemMinCostFlow::clNodeData      clNodeData;
      typedef clArc<clArcData,clNodeData>              tyArc;
      typedef clNode<clArcData,clNodeData>             tyNode;
      typedef tyNode::cpArcX::const_iterator           clArcIterator;

      clArcIterator                 lcCurrentArc;
      std_map(tyArc *,tyInteger)    lcCycle;
      clInFile                      lcFin;
      clOutFile                     lcFout;
      clGraph<clArcData,clNodeData> lcGraph;
      clArcIterator                 lcLastArc;
      tyArc *                       lcReturnLoop;
      tyNode *                      lcSourceNode;
      tyNode *                      lcTargetNode;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[++lcCounter],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Searching Negative Cycle For Minimum Cost Flow...");
      lcSourceNode=firstNode(lcGraph);
      lcTargetNode=lastNode(lcGraph);

      if (lcSourceNode==nil or lcTargetNode==nil)
       send_error(graphProblemMinCostFlow::erInvalidFlowGraph);

      lcReturnLoop=new_object(tyArc(lcGraph,lcGraph.getNewArcKey(),clArcData(),
                                    lcTargetNode->key(),lcSourceNode->key()));

      lcReturnLoop->data().minimum()=clArcData::negativeInfinity();
      lcReturnLoop->data().maximum()=clArcData::positiveInfinity();
      lcReturnLoop->data().unitCost()=0.0;
      lcReturnLoop->data().flow()=0.0;

      lcCurrentArc=lcReturnLoop->sourceNode()->incomingArcs().begin();
      lcLastArc=lcReturnLoop->sourceNode()->incomingArcs().end();

      while (lcCurrentArc!=lcLastArc) {
       lcReturnLoop->data().flow()+=(*lcCurrentArc).second->data().flow();
       ++lcCurrentArc;
      }

      if (graphProblemMinCostFlowCycleCanceling::findNegativeCycle(lcGraph,lcCycle))
       environment::out("Cycle Found",true,true);
      else environment::out("No Cycle Found",true,true);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[++lcCounter],ios::out|ios::trunc);
      lcFout << "Cycle = " << lcCycle << end_line;
      close(lcFout);

      lcError=false;
     }
    }

    //-----------------------------------------------------------------------------------Topological
    else if (lcCommand=="+topological") {
     if (agCounter-lcCounter>2) {
      clInFile                    lcFin;
      clOutFile                   lcFout;
      clGenericGraph              lcGraph;
      std_vector(clGenericNode *) lcOrdering;
      tyBoolean                   lcResult;

      environment::nextLine();
      environment::inform("Reading Input File...");
      open(lcFin,agParameterS[lcCounter+1],ios::in);
      lcFin >> lcGraph;
      close(lcFin);
      if (lcFin.fail()) send_error(erFileReading);

      environment::inform("Find Topological Ordering...");
      lcResult=findTopologicalOrdering(lcGraph,lcOrdering);

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);

      if (lcResult) lcFout << "Ordering = " << lcOrdering;
      else lcFout << "Circuit Detected" << end_line;

      close(lcFout);
      if (lcFout.fail()) send_error(erFileWriting);

      lcCounter+=2;
      lcError=false;
     }
    }

    if (lcError) send_error(erSyntax);
    lcCounter++;
   }
  }

  program_catch;
 }
}

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);

    erSyntax.create("Solve Graph - Use the '+help' parameter to get some help.");
   }

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

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