namespace dhrg {

void generate(const string& fname, const string& ground_truth_fname, bool subdiv, bool doRebase, bool doStore, int n, ld R, ld T) {
  any = rogueviz::add_edgetype("embedded edges");
  ld full = wvolarea_auto(R);

  fhstream g(ground_truth_fname, "wt");

  println(hlog, "generating...");
  for(int i=0; i<n; i++) {
    ld p = hrandf() * full;
    ld r = binsearch(0, R, [&] (ld r1) { return wvolarea_auto(r1) > p; });
    transmatrix h = random_spin() * xpush(r);
    println(hlog, "h = ", h * C0);
    for(int i=0; i<MDIM; i++) print(g, (h*C0)[i], " "); println(g);
    int id = rogueviz::getid(its(i+1));
    println(hlog, "id = ", id);
    rogueviz::vertexdata& vd(rogueviz::vdata[id]);
    vd.name = its(i+1);
    vd.cp = rogueviz::colorpair(rogueviz::dftcolor);
    rogueviz::createViz(id, currentmap->gamestart(), h);
    }

  logistic tester; tester.R = R; tester.T = T;

  println(hlog, "picking edges...");
  vector<pair<int, int>> edges;
  for(int i=0; i<n; i++) for(int j=0; j<i; j++) {
    ld dist = hdist(rogueviz::vdata[i].m->at*C0, rogueviz::vdata[j].m->at*C0);
    if(hrandf() < tester.yes(dist)) edges.emplace_back(i, j);
    }

  println(hlog, "number of edges: ", isize(edges));
  vector<int> degrees(n, 0);
  for(auto [i,j]: edges) degrees[i]++, degrees[j]++;
  sort(degrees.begin(), degrees.end());
  println(hlog, "degrees = ", degrees);

  fhstream f(fname, "wt");
  for(auto [i,j]: edges) println(f, i, " ", j);
  
  if(doRebase) {
    printf("Rebasing...\n");
    for(int i=0; i<isize(rogueviz::vdata); i++) {
      if(i % 10000 == 0) printf("%d/%d\n", i, isize(rogueviz::vdata));
      if(rogueviz::vdata[i].m) {
        virtualRebase(rogueviz::vdata[i].m);
        auto& at = rogueviz::vdata[i].m->at;
        ld v = intval(at*C0, Hypc);
        fixmatrix(at);
        if(abs(v+1) > .1 || isnan(v)) at = Id;
        }
      }
    printf("Done.\n");
    }

  for(auto [i, j]: edges) addedge(i, j, 1, subdiv, any);
    
  if(doStore) rogueviz::storeall();
  }

void generate_convert(const string& iname, const string& fname, const string& ground_truth_fname, bool subdiv, bool doRebase, bool doStore) {
  any = rogueviz::add_edgetype("embedded edges");

  fhstream g(ground_truth_fname, "wt");
  fhstream fi(iname, "rt");
  string ignore;
  if(!scan(fi, ignore, ignore, ignore, ignore, N, graph_R, graph_alpha, graph_T)) {
    printf("Error: incorrect format of the first line\n"); exit(1);
    }
  rogueviz::vdata.reserve(N);
  while(true) {
    string s = scan<string>(fi);
    if(s == "" || s == "#ROGUEVIZ_ENDOFDATA") break;
    int id = rogueviz::getid(s);
    double r, alpha;
    if(!scan(fi, r, alpha)) { printf("Error: incorrect format of r/alpha\n"); exit(1); }
    r /= (GDIM-1);
    rogueviz::vertexdata& vd(rogueviz::vdata[id]);
    vd.name = s;
    vd.cp = rogueviz::colorpair(rogueviz::dftcolor);
    transmatrix h = random_spin() * xpush(r);
    for(int i=0; i<MDIM; i++) print(g, (h*C0)[i], " "); println(g);
    rogueviz::createViz(id, currentmap->gamestart(), h);    
    }
  
  logistic tester; tester.R = graph_R/(GDIM-1); tester.T = graph_T/(GDIM-1);

  println(hlog, "picking edges...");
  vector<pair<int, int>> edges;
  for(int i=0; i<N; i++) for(int j=0; j<i; j++) {
    ld dist = hdist(rogueviz::vdata[i].m->at*C0, rogueviz::vdata[j].m->at*C0);
    if(hrandf() < tester.yes(dist)) edges.emplace_back(i, j);
    }

  println(hlog, "number of edges: ", isize(edges));
  vector<int> degrees(N, 0);
  for(auto [i,j]: edges) degrees[i]++, degrees[j]++;
  sort(degrees.begin(), degrees.end());
  println(hlog, "degrees = ", degrees);

  fhstream f(fname, "wt");
  for(auto [i,j]: edges) println(f, i, " ", j);
  
  if(doRebase) {
    printf("Rebasing...\n");
    for(int i=0; i<isize(rogueviz::vdata); i++) {
      if(i % 10000 == 0) printf("%d/%d\n", i, isize(rogueviz::vdata));
      if(rogueviz::vdata[i].m) {
        virtualRebase(rogueviz::vdata[i].m);
        auto& at = rogueviz::vdata[i].m->at;
        ld v = intval(at*C0, Hypc);
        fixmatrix(at);
        if(abs(v+1) > .1 || isnan(v)) at = Id;
        }
      }
    printf("Done.\n");
    }

  for(auto [i, j]: edges) addedge(i, j, 1, subdiv, any);
    
  if(doStore) rogueviz::storeall();
  }

}
