/* The list of blocked sources in an Active<> queue */

class ActiveBlocklist {
    static const int blsize = 100;
protected:
    int size;
    class blocknode;
    class blocknode *list;
public:
    inline ActiveBlocklist(int s=blsize);
    inline int blocked(nsaddr_t src, nsaddr_t dst);
    inline int blocked(nsaddr_t src, nsaddr_t dst, int w, int);
    inline int block(nsaddr_t src, nsaddr_t dst, int w, int, int);
};

class ActiveBlocklist::blocknode {
public:
    nsaddr_t src;
    nsaddr_t dst;
    int winsize;
    int num;
    int dropped;
    int id;
    blocknode() : src(0), dst(0), winsize(0), num(0), dropped(0), id(-1) { }
};

inline ActiveBlocklist::ActiveBlocklist(int s=blsize)
{
    list = new blocknode[size = s];
}
inline int ActiveBlocklist::blocked(nsaddr_t src, nsaddr_t dst)
{
/* Do a linear search to see if the source is blocked, but do not ever
   unblock it */
    
    int b = 0;	/* true if the source is blocked */
    
    for (int i = 0; i < size; i++ ) {
	if (list[i].src == src && list[i].dst == dst) {
	    b = 1;
	    break;
	}
    }
    return b;
}

inline int ActiveBlocklist::blocked(nsaddr_t src, nsaddr_t dst, int w, int id)
{
/* Do a linear search to see if the source is blocked, and unblock it
   if either one window's worth of data has been blocked or the source
   has reduced its window. */
    
    int b = 0;	/* true if the source is blocked */
    
    for (int i = 0; i < size; i++ ) {
	if (list[i].src == src && list[i].dst == dst) {
	    b = (list[i].winsize <= w && list[i].id > id &&
		 ++list[i].dropped < list[i].num);
	    if ( !b ) {
		list[i].src = list[i].dst = (nsaddr_t) 0;
		return -list[i].winsize;
	    }
/*  	    else fprintf(stderr,"blocked bw %d w %d dr %d n%d\n", */
/*  			 list[i].winsize, w, list[i].dropped, list[i].num); */
	    break;
	}
    }
    return b;
}
inline int ActiveBlocklist::block(nsaddr_t src, nsaddr_t dst, int w, int num, int id)
{
/* Block the given source. return true if blocked */
    int i;

    //fprintf(stderr,"src %d dst %d win %d num %d\n",src,dst,w,num);
    /* Don't block empty windows (2 or less) */
    
    if ( w < 3 ) return 0;

    for ( i = 0; i < size; i++ ) 
	if ( list[i].src == 0 && list[i].dst == 0 ) {
	    list[i].src = src;
	    list[i].dst = dst;
	    list[i].winsize = w;
	    list[i].num = (num >= 0) ? num : w;
	    list[i].dropped =0;
	    list[i].id = id;
	    break;
	}
    if ( i == size) {
	fprintf(stderr,"block of %d %d failed\n",src,dst);
	for ( i =0; i < size; i++ ) {
	    fprintf(stderr,"\t%d %d %d %d\n",
		   list[i].src, list[i].dst, list[i].winsize, list[i].dropped);
	}
	return 0;
    }
    else return 1;
}
