#include <vector>
#include <iostream>
#include <stdlib.h>

using namespace std;

template <typename T> class SkipList;

template <typename T>
class SkipNode {
  friend class SkipList<T>; // SkipList class can get access to
  // all SkipNode members
  private:
  T* key; // pointer to the key in this node
  std::vector<SkipNode<T>*> forward; // vector of forward pointers
  SkipNode(T* key, int level) :
    key(key), forward(level,(SkipNode<T>*)0) {}
  public:
  void print() {
    cout << "Key = ";
    if (key == nullptr) { cout << "(null)" << endl; }
    else { cout << *key << endl; }
    cout << "level = " << forward.size() << endl;
    for (int i=0; i<forward.size(); i++) {
      cout << this << " --> F[" << i << "] = ";
      if (forward[i] == nullptr) { cout << "(null)" << endl; }
      else { cout << forward[i] << endl; }
    }
  }
};

template <typename T>
class SkipList {
  private:
    SkipNode<T> header;
    const int MAXLEVEL;
    float prob;

  public:
    SkipList(int maxlevel, float p) :
      MAXLEVEL(maxlevel), header((T*)0, maxlevel)
  { prob = p < 1.0 && p > 0.0 ? p : 0.5; }
    void insert(T* key, int level); // will define this later...
    void insert(T* key) {
      int newLevel = randomLevel();       // generate level of the new node
      insert(key, newLevel);
    }

    void print() {
        cout << "MAXLEVEL = " << MAXLEVEL << endl;
        cout << "prob = " << prob << endl;
        SkipNode<T>* x = &header;
        while (x != nullptr) {
          x->print();
          x = x->forward[0];
        }
    }

  private:
    /** Return a random double in range [0,1) */
    double drand() {
      return rand() / (RAND_MAX + 1.0);
    }
    int randomLevel() {
      int level;
      // note the empty loop body!
      for(level = 1; drand() < prob && level < MAXLEVEL; level++) ;
      return level;
    }

};

template <typename T>
void SkipList<T>::insert(T* key, int level) {

  std::vector<SkipNode<T> *> prev(MAXLEVEL, (SkipNode<T> *)0);// "prev" vector
  std::vector<SkipNode<T> *> curr(MAXLEVEL, (SkipNode<T> *)0);// "curr" vector

  SkipNode<T>* x = &header;       // start at dummy header node
  for(int lvl=MAXLEVEL-1; lvl>=0; lvl--) {  // search for insert posn.
    while( x->forward[lvl] &&
        *(x->forward[lvl]->key) < *key ) {
      x = x->forward[lvl];       // follow pointer with index lvl
    }
    // update curr and prev
    curr[lvl] = x->forward[lvl];
    prev[lvl] = x;
  }

  x = new SkipNode<T>(key, level);     // create new node

  // splice into list
  for (int i=0; i<level; i++) {
    x->forward[i] = curr[i];  // who x points to
    prev[i]->forward[i] = x;  // who points to x
  }
}


int main() {
  srand(0);
  SkipList<int> list(5, 0.5);
  int v[] = {3, 5, 6, 21, 25, 26};
  int l[] = {2, 1, 3, 1, 4, 1};
  
  for (int i = 0; i < 6; i++) {
    list.insert(&v[i], l[i]);
  }
  int k = 22;
  list.insert(&k, 2);
  list.print();
}

