/* -*- C++ -*-
 *
 * This file is a part of LEMON, a generic C++ optimization library
 *
 * Copyright (C) 2003-2007
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
 *
 * Permission to use, modify and distribute this software is granted
 * provided that this copyright notice appears in all copies. For
 * precise terms see the accompanying LICENSE file.
 *
 * This software is provided "AS IS" with no warranty of any kind,
 * express or implied, and with no claim as to its suitability for any
 * purpose.
 *
 */

///\ingroup demos
///\file
///\brief DIMACS to LGF converter.
///
/// This program converts various DIMACS formats to the LEMON Graph Format
/// (LGF).
///
/// \include dim_to_lgf.cc

#include <iostream>
#include <fstream>
#include <cstring>

#include <lemon/smart_graph.h>
#include <lemon/dimacs.h>
#include <lemon/graph_writer.h>

#include <lemon/arg_parser.h>

using namespace std;
using namespace lemon;


int main(int argc, const char *argv[]) {
  typedef SmartGraph Graph;

  typedef Graph::Edge Edge;
  typedef Graph::Node Node;
  typedef Graph::EdgeIt EdgeIt;
  typedef Graph::NodeIt NodeIt;
  typedef Graph::EdgeMap<double> DoubleEdgeMap;
  typedef Graph::NodeMap<double> DoubleNodeMap;

  std::string inputName;
  std::string outputName;
  std::string typeName;

  bool mincostflow;
  bool maxflow;
  bool shortestpath;
  bool capacitated;
  bool plain;

  bool version;

  ArgParser ap(argc, argv);
  ap.refOption("-input", 
               "use FILE as input instead of standard input", 
               inputName).synonym("i", "-input")
    .refOption("-output", 
               "use FILE as output instead of standard output", 
               outputName).synonym("o", "-output")
    .refOption("-mincostflow", 
               "set the type of the graph to \"mincostflow\" graph", 
               mincostflow)
    .optionGroup("type", "-mincostflow").synonym("mcf", "-mincostflow")
    .refOption("-maxflow", 
               "set the type of the graph to \"maxflow\" graph", 
               maxflow)
    .optionGroup("type", "-maxflow").synonym("mf", "-maxflow")
    .refOption("-shortestpath", 
               "set the type of the graph to \"shortestpath\" graph", 
               shortestpath)
    .optionGroup("type", "-shortestpath").synonym("sp", "-shortestpath")
    .refOption("-capacitated", 
               "set the type of the graph to \"capacitated\" graph", 
               capacitated)
    .optionGroup("type", "-capacitated").synonym("cap", "-capacitated")
    .refOption("-plain", 
               "set the type of the graph to \"plain\" graph", 
               plain)
    .optionGroup("type", "-plain").synonym("pl", "-plain")
    .onlyOneGroup("type")
    .mandatoryGroup("type")
    .refOption("-version", "show version information", version)
    .synonym("v", "-version")
    .run();

  ifstream input;
  if (!inputName.empty()) {
    input.open(inputName.c_str());
    if (!input) {
      cerr << "File open error" << endl;
      return -1;
    }
  }
  istream& is = (inputName.empty() ? cin : input);

  ofstream output;
  if (!outputName.empty()) {
    output.open(outputName.c_str());
    if (!output) {
      cerr << "File open error" << endl;
      return -1;
    }
  }
  ostream& os = (outputName.empty() ? cout : output);

  if (mincostflow) {
    Graph graph;
    DoubleEdgeMap lower(graph), capacity(graph), cost(graph);
    DoubleNodeMap supply(graph);
    readDimacs(is, graph, lower, capacity, cost, supply);
    GraphWriter<Graph>(os, graph).
      writeNodeMap("supply", supply).
      writeEdgeMap("lower", lower).
      writeEdgeMap("capacity", capacity).
      writeEdgeMap("cost", cost).
      run();
  } else if (maxflow) {
    Graph graph;
    Node s, t;
    DoubleEdgeMap capacity(graph);
    readDimacs(is, graph, capacity, s, t);
    GraphWriter<Graph>(os, graph).
      writeEdgeMap("capacity", capacity).
      writeNode("source", s).
      writeNode("target", t).
      run();
  } else if (shortestpath) {
    Graph graph;
    Node s;
    DoubleEdgeMap capacity(graph);
    readDimacs(is, graph, capacity, s);
    GraphWriter<Graph>(os, graph).
      writeEdgeMap("capacity", capacity).
      writeNode("source", s).
      run();
  } else if (capacitated) {
    Graph graph;
    DoubleEdgeMap capacity(graph);
    readDimacs(is, graph, capacity);
    GraphWriter<Graph>(os, graph).
      writeEdgeMap("capacity", capacity).
      run();
  } else if (plain) {
    Graph graph;
    readDimacs(is, graph);
    GraphWriter<Graph>(os, graph).run();
  } else {
    cerr << "Invalid type error" << endl;
    return -1;
  }
  return 0;
}
