//==================================================================================================
// P r o g r a m                                                                          Interface
// G r a p h _ l a y o u t
// 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/graph_layout/console.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guProgramGraphLayoutConsole
#define guProgramGraphLayoutConsole

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

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programGraphLayoutConsole
#define private_area programGraphLayoutConsole_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniProgramGraphLayoutConsole
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 {}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// P r o g r a m                                                                     Implementation
// G r a p h _ l a y o u t
// 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/graph_layout/console.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define PROGRAM_GRAPH_LAYOUT_DLL

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programGraphLayoutConsole
#define private_area programGraphLayoutConsole_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Program/Graph_layout/Console");

// Initialization //--------------------------------------------------------------------------------
#undef iniProgramGraphLayoutConsole
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;
  std_vector(clString) lcFormatS;

  tyBoolean lcArcData          = true;
  tyBoolean lcArcKey           = true;
  tyBoolean lcFlipped          = false;
  tyBoolean lcMirrored         = false;
  tyBoolean lcNodeData         = true;
  tyBoolean lcNodeKey          = true;
  tyReal    lcNodeRadius       = 10.0;
  tyBoolean lcReversed         = false;
  tyReal    lcSpaceCoefficient = 1.0;
  tyBoolean lcTextCentered     = false;

  tyCardinal lcCounter = 1;

  environment_private::goProgramName = "G r a p h   L a y o u t";

  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 deals with the layout of a graph.",true,true);
     environment::nextLine();
     environment::out(" * Syntax: [options] [commands] [input file] [output file]",true,true);
     environment::nextLine();
     environment::out(" * Options:",true,true);
     environment::out("   -ctext      = centers vertically the text of the nodes in the EPS file.",true,true);
     environment::out("   -flip       = reverses the vertical coordinates.",true,true);
     environment::out("   -mirror     = reverses the horizontal coordinates.",true,true);
     environment::out("   -nadata     = does not display the arc data in the EPS file.",true,true);
     environment::out("   -nakey      = does not display the arc keys in the EPS file.",true,true);
     environment::out("   -nndata     = does not display the node data in the EPS file.",true,true);
     environment::out("   -nnkey      = does not display the node keys in the EPS file.",true,true);
     environment::out("   -radius <x> = sets the radius of the nodes to <x>, default is 10.",true,true);
     environment::out("   -reverse    = reverses the horizontal and vertical coordinates",true,true);
     environment::out("                 of the nodes in the EPS file.",true,true);
     environment::out("   -space <x>  = sets the space coefficient for multiple arc",true,true);
     environment::out("                 labels to <x>.",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("   +bintree = generates the layout of the binary tree. The",true,true);
     environment::out("              tree is converted into a graph and a layout is",true,true);
     environment::out("              built for this graph.",true,true);
     environment::out("   +eps     = converts the graph into the EPS (Encapsulated",true,true);
     environment::out("              PostScript) format.",true,true);
     environment::out("   +improve = attempts to improve the layout of the graph.",true,true);
     environment::out("   +layout  = generates randomly a layout for the graph.",true,true);
     environment::out("   +number  = numbers from 0 the keys of the arcs and nodes",true,true);
     environment::out("              of the graph.",true,true);
     environment::out("   +remove  = removes the layout of 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();
    }

    //-----------------------------------------------------------------------------------------Ctext
    else if (lcCommand=="-ctext") {
     lcError=false;
     lcTextCentered=true;
    }

    //------------------------------------------------------------------------------------------Flip
    else if (lcCommand=="-flip") {
     lcError=false;
     lcFlipped=true;
    }

    //----------------------------------------------------------------------------------------Mirror
    else if (lcCommand=="-mirror") {
     lcError=false;
     lcMirrored=true;
    }

    //----------------------------------------------------------------------------------------Nadata
    else if (lcCommand=="-nadata") {
     lcError=false;
     lcArcData=false;
    }

    //-----------------------------------------------------------------------------------------Nakey
    else if (lcCommand=="-nakey") {
     lcError=false;
     lcArcKey=false;
    }

    //----------------------------------------------------------------------------------------Nndata
    else if (lcCommand=="-nndata") {
     lcError=false;
     lcNodeData=false;
    }

    //-----------------------------------------------------------------------------------------Nnkey
    else if (lcCommand=="-nnkey") {
     lcError=false;
     lcNodeKey=false;
    }

    //----------------------------------------------------------------------------------------Radius
    else if (lcCommand=="-radius") {
     if (agCounter-lcCounter>1) {
      lcNodeRadius=real(agParameterS[lcCounter+1]);
      lcCounter+=1;
      lcError=false;
     }
    }

    //---------------------------------------------------------------------------------------Reverse
    else if (lcCommand=="-reverse") {
     lcError=false;
     lcReversed=true;
    }

    //-----------------------------------------------------------------------------------------Space
    else if (lcCommand=="-space") {
     if (agCounter-lcCounter>1) {
      lcSpaceCoefficient=real(agParameterS[lcCounter+1]);
      lcCounter+=1;
      lcError=false;
     }
    }

    //---------------------------------------------------------------------------------------Bintree
    else if (lcCommand=="+bintree") {
     if (agCounter-lcCounter>2) {
      clGraph<clNoData,clGenericData> lcGraph;
      clInFile                        lcFin;
      clOutFile                       lcFout;
      clGraphLayout                   lcLayout;
      clBinaryTree<clGenericData>     lcTree;

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

      environment::inform("Generating Layout...");
      generateBinaryTreeLayout(lcGraph,lcTree,lcLayout);

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

      lcCounter+=2;
      lcError=false;
     }
    }

    //-------------------------------------------------------------------------------------------Eps
    else if (lcCommand=="+eps") {
     if (agCounter-lcCounter>2) {
      clGenericGraph lcGraph;
      clInFile       lcFin;
      clOutFile      lcFout;
      clGraphLayout  lcLayout;

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

      if (lcLayout.size()==0 and lcGraph.nodes().size()!=0)
       environment::out("No Layout !",true,true);
      else {
       environment::inform("Generating EPS File...");
       open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);

       convertEps(lcFout,lcGraph,lcLayout,lcNodeData,lcArcData,lcNodeKey,lcArcKey,
                  lcTextCentered,lcReversed,lcMirrored,lcFlipped,lcSpaceCoefficient,lcNodeRadius);

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

      lcCounter+=2;
      lcError=false;
     }
    }

    //---------------------------------------------------------------------------------------Improve
    else if (lcCommand=="+improve") {
     if (agCounter-lcCounter>2) {
      clGenericGraph lcGraph;
      clInFile       lcFin;
      clOutFile      lcFout;
      clGraphLayout  lcLayout;

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

      if (lcLayout.size()==0 and lcGraph.nodes().size()!=0)
       environment::out("No Layout !",true,true);
      else {
       environment::inform("Improving Layout...");
       improveGraphLayout(lcGraph,lcLayout);

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

      lcCounter+=2;
      lcError=false;
     }
    }

    //----------------------------------------------------------------------------------------Layout
    else if (lcCommand=="+layout") {
     if (agCounter-lcCounter>2) {
      clGenericGraph lcGraph;
      clInFile       lcFin;
      clOutFile      lcFout;
      clGraphLayout  lcLayout;

      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("Generating Layout...");
      generateGraphLayout(lcGraph,lcLayout);
      improveGraphLayout(lcGraph,lcLayout);

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

      lcCounter+=2;
      lcError=false;
     }
    }

    //----------------------------------------------------------------------------------------Number
    else if (lcCommand=="+number") {
     if (agCounter-lcCounter>2) {
      clGenericGraph lcGraph;
      clInFile       lcFin;
      clOutFile      lcFout;
      clGraphLayout  lcLayout;

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

      environment::inform("Numbering Keys...");
      lcGraph.numberKeys();
      numberLayoutKeys(lcLayout);

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

      lcCounter+=2;
      lcError=false;
     }
    }

    //----------------------------------------------------------------------------------------Remove
    else if (lcCommand=="+remove") {
     if (agCounter-lcCounter>2) {
      clGenericGraph lcGraph;
      clInFile       lcFin;
      clOutFile      lcFout;

      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("Removing Layout...");

      environment::inform("Writing Output File...");
      open(lcFout,agParameterS[lcCounter+2],ios::out|ios::trunc);
      lcFout << lcGraph;
      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("Graph Layout - Use the '+help' parameter to get some help.");
   }

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

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