// -*- c++ -*-
#include <iostream>
#include <fstream>

#include <list_graph.h>
//#include <smart_graph.h>
#include <dimacs.h>
#include <edmonds_karp.h>
#include <time_measure.h>
//#include <graph_wrapper.h>
#include <preflow.h>
#include <preflow_res.h>
#include <for_each_macros.h>

using namespace hugo;

// Use a DIMACS max flow file as stdin.
// read_dimacs_demo < dimacs_max_flow_file


//   struct Ize {
//   };
  
//   struct Mize {
//     Ize bumm;
//   };

//   template <typename B>
//     class Huha {
//     public:
//       int u;
//       B brr;
//     };


int main(int, char **) {

  typedef ListGraph MutableGraph;

//  typedef SmartGraph Graph;
  typedef ListGraph Graph;
  typedef Graph::Node Node;
  typedef Graph::EdgeIt EdgeIt;


//   Mize mize[10];
//   Mize bize[0];
//   Mize zize;
//   typedef Mize Tize[0];

//   std::cout << &zize << " " << sizeof(mize) << sizeof(Tize) << std::endl;
//   std::cout << sizeof(bize) << std::endl;


//   Huha<Tize> k;
//   std::cout << sizeof(k) << std::endl;


//   struct Bumm {
//     //int a;
//     bool b;
//   };

//   std::cout << sizeof(Bumm) << std::endl;


  Graph G;
  Node s, t;
  Graph::EdgeMap<int> cap(G);
  readDimacsMaxFlow(std::cin, G, s, t, cap);
  Timer ts;
  Graph::EdgeMap<int> flow(G); //0 flow
  Preflow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
    pre_flow_test(G, s, t, cap, flow, true);
  PreflowRes<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
    pre_flow_res(G, s, t, cap, flow, true);
  MaxFlow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
    max_flow_test(G, s, t, cap, flow);

  {
    std::cout << "preflow ..." << std::endl;
    ts.reset();
    pre_flow_test.run();
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "flow value: "<< pre_flow_test.flowValue() << std::endl;
  }

  {
    std::cout << "wrapped preflow ..." << std::endl;
    FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
    ts.reset();
    pre_flow_res.run();
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "flow value: "<< pre_flow_test.flowValue() << std::endl;
  }

  {
    std::cout << "physical blocking flow augmentation ..." << std::endl;
    FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
    ts.reset();
    int i=0;
    while (max_flow_test.augmentOnBlockingFlow<MutableGraph>()) { ++i; }
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
  }

  {
    std::cout << "faster physical blocking flow augmentation ..." << std::endl;
    FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
    ts.reset();
    int i=0;
    while (max_flow_test.augmentOnBlockingFlow1<MutableGraph>()) { ++i; }
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
  }

  {
    std::cout << "on-the-fly blocking flow augmentation ..." << std::endl;
    FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
    ts.reset();
    int i=0;
    while (max_flow_test.augmentOnBlockingFlow2()) { ++i; }
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
  }

  {
    std::cout << "on-the-fly shortest path augmentation ..." << std::endl;
    FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
    ts.reset();
    int i=0;
    while (max_flow_test.augmentOnShortestPath()) { ++i; }
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
  }


  return 0;
}
