// Copyright (c) 2003 Nick Mathewson.  See LICENSE for licensing information.
// $Id: netparams.cpp 1339 2004-09-12 02:39:32Z nickm $
// netparams.cpp -- Generate network parameters
#include <iostream.h>
#include <vector>

#include "assert.h"
#include "rng.h"
#include "netparams.h"
#include "vec.h"

InvDist<int> *
getSingleMixDelays(double pDelay) {
  assert(0.0 < pDelay && pDelay < 1.0);
  InvDist<int> *r = new GeometricDist(1.0-pDelay);
#ifndef QUIET
  cout << "Single MIX ";
  for (int i = 0; i < 1000; ++i) {
    cout << r->get() << " ";
  }
  cout << endl;
  for (int i = 0; i < 25; ++i) {
    cout << "P(" << i << ")=" << r->getP(i) << endl;
  }
#endif
  return r;
}

InvDist<int> *
getMixNetDelays(const InvDist<int> &pathLenDist,
                int maxPathLen,
                double pSingleDelay,
                int maxDelay)
{
  std::vector<double> p(maxPathLen+maxDelay, 0.0);
  for (int pathLen = 1; pathLen < maxPathLen; ++pathLen) {
    double pathProb = pathLenDist.getP(pathLen);
    if (!pathProb)
      continue;
    for (int d = 0; d < maxDelay; ++d) {
      p[pathLen+d] += pathProb * bins(d, pathLen) *
        std::pow(pSingleDelay, d) * std::pow(1.0-pSingleDelay, pathLen);
    }
  }
  InvDist<int> *r = new CumulativeDist(p);
#ifndef QUIET
  cout << "MIXNET ";
  for (int i = 0; i < 1000; ++i) {
    cout << r->get() << " ";
  }
  cout << endl;
  for (int i = 0; i < 25; ++i) {
    cout << "P(" << i << ")=" << r->getP(i) << endl;
  }
#endif
  return r;
}

void
getCommunicationLinks(InvDist<int> *&aliceRecipDist,
                      InvDist<int> *&backgroundTraffic,
                      std::vector<int> *&aliceRecipients,
                      int nAliceRecipients,
                      int nRecipients,
                      bool weightAlice,
		      bool smallworldAlice)
{
  assert(nAliceRecipients < nRecipients);
  assert(nRecipients >= 3);

  backgroundTraffic = aliceRecipDist = NULL;

  // Generate the network connectivity.
  std::vector<int> conns(nRecipients, 0);
  int total = 0;
  conns[0] = 2;
  conns[1] = 2;
  conns[2] = 2;
  total = 6;
  for (int i = 3; i < nRecipients; ++i) {
    while (conns[i] == 0) { // we want nRecipients connected recpients.
      for (int j = 0; j < i; ++j) {
	double pAdd = conns[j] / ((double)total);
	if (rng() < pAdd) {
	  conns[i]++;
	  conns[j]++;
	}
      }
    }
    total += conns[i];
  }

#ifndef QUIET
  cout << " CONNECTIONS " << endl;
  pvec(cout, conns);
#endif

  // XXX Make a constructor decide to use CumulativeDist if granularity
  // XXX is too small.
  backgroundTraffic = new OCumulativeDist(conns);

  std::vector<int> pAlice(nRecipients, 0);
  for (int i = 0; i < nAliceRecipients; ++i) {
    int r;
    do {
      if (smallworldAlice)
	r = backgroundTraffic->get();
      else
	r = (int) (rng()*nRecipients);
    } while (pAlice[r]);
    if (weightAlice) {
      pAlice[r] = conns[r];
    } else {
      pAlice[r] = 1;
    }
  }

  aliceRecipients = new std::vector<int>(nAliceRecipients);
  int j = 0;
  for (int i = 0; i < nRecipients; ++i) {
    if (pAlice[i]) {
      (*aliceRecipients)[j++] = i;
    }
  }

  // XXX Make a constructor decide to use CumulativeDist if granularity
  // XXX is too small.
  aliceRecipDist = new OCumulativeDist(pAlice);
}



void
getNymStats(InvDist<int> *&aliceNymDist,
	    InvDist<int> *&backgroundNymDist,
	    int nNyms)
{
  std::vector<int> a(nNyms,0);
  std::vector<int> b(nNyms,1);
  a[0] = 1;
  b[0] = 0;
  aliceNymDist = new OCumulativeDist(a);
  backgroundNymDist = new OCumulativeDist(b);
}

