/*
 * Copyright (c) 2004, Stony Brook University
 * Contributors: Ashish Raniwala
 * All rights reserved.
 *
 * See copyright notice included in the distribution for details
 *
 */

// raniwala: added for manual routing in wireless scenario
//
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "tagtable.h"
#include <math.h>
#include <random.h>

int global_flowid = -1;
int flow_to_tag[10000];

static int tagent_compare(const void *a, const void *b) {

  nsaddr_t ia = ((const tag_table_ent *) a)->dst;
  nsaddr_t ib = ((const tag_table_ent *) b)->dst;

  int ta = ((const tag_table_ent *) a)->tag;
  int tb = ((const tag_table_ent *) b)->tag;

  if (ia > ib) return 1;
  if (ib > ia) return -1;

  if (ta > tb) return 1;
  if (tb > ta) return -1;
  return 0;
}

TagTable::TagTable() {
  // Let's start with a ten element maxelts.
  _elts = 0;
  _maxelts = 10;
  _rtab = new tag_table_ent[_maxelts];
}

void
TagTable::AddTag(const tag_table_ent &ent)
{
  tag_table_ent *it;

  if ((it = (tag_table_ent*) bsearch(&ent, _rtab, _elts, sizeof(tag_table_ent), 
				 tagent_compare))) {
    bcopy(&ent,it,sizeof(tag_table_ent));
    return;
    /*
    if (it->seqnum < ent.seqnum || it->metric > (ent.metric+em)) {
      bcopy(&ent,it,sizeof(rtable_ent));
      it->metric += em;
      return NEW_ROUTE_SUCCESS_OLDENT;
    } else {
      return NEW_ROUTE_METRIC_TOO_HIGH;
    }
    */
  }

  if (_elts == _maxelts) {
    tag_table_ent *tmp = _rtab;
    _maxelts *= 2;
    _rtab = new tag_table_ent[_maxelts];
    bcopy(tmp, _rtab, _elts*sizeof(tag_table_ent));
    delete tmp;
  }
  
  int max;
  
  for (max=0;max<_elts;max++) {
	  if ((ent.dst < _rtab[max].dst)  ||
	      ((ent.dst == _rtab[max].dst) && (ent.tag < _rtab[max].tag)) )
	  {
		  break;
	  }
  }
  // Copy all the further out guys out yet another.
  // bcopy does not seem to quite work on sunos???
  
  //bcopy(&rtab[max], &rtab[max+1], sizeof(fixed_rtable_ent)*(elts-max));
  
  //if (elts) {
  int i = _elts-1;
  while (i >= max) 
	  _rtab[i+1] = _rtab[i--];
  //}
  bcopy(&ent, &_rtab[max], sizeof(tag_table_ent));
  _elts++;

  return;
}

void 
TagTable::InitLoop() {
  _ctr = 0;
}

tag_table_ent *
TagTable::NextLoop() {
  if (_ctr >= _elts)
    return 0;

  return &_rtab[_ctr++];
}

// Only valid (duh) as long as no new routes are added
int 
TagTable::RemainingLoop() {
  return _elts-_ctr;
}

tag_table_ent *
TagTable::GetTag(nsaddr_t dest) {
//should use a random approach
	int i;
	int first;
	int last;
	double r;
	int chosen;

	for (i=0; i<_elts; i++)
	{
		if (_rtab[i].dst == dest)
			break;
	}
	first = i;

	for (i=_elts-1; i>=0; i--)
	{
		if (_rtab[i].dst == dest)
			break;
	}
	last = i;

	do
	{
		r = Random::uniform((double) first, (double) (last+1));
		chosen = (int) floor(r);
	} while (chosen == (last + 1));

	printf("Randomization::First %d Last %d Chosen %d Tag %d\n", first, last, chosen, _rtab[chosen].tag);

	return &_rtab[chosen];


//return (tag_table_ent *) bsearch(&ent, _rtab, _elts, sizeof(tag_table_ent), 
//				tagent_compare);
}

void TagTable::IncreaseTagCount(int tag)
{
	printf("Not implemented\n");
}

void TagTable::DecreaseTagCount(int tag)
{
	printf("Not implemented\n");
}

void TagTable::ResetTagCount(int tag)
{
	printf("Not implemented\n");
}

