#include <assert.h>
#include <iostream.h>

#include "Heap.hpp"

void Heap::swap(int i,int j)
{
    heap_node tmp = ref(i);
	
    ref(i) = ref(j);
    ref(j) = tmp;
	
    ref(i).obj->token = i;
    ref(j).obj->token = j;
}

void Heap::upheap(int i)
{
    if( i==0 ) return;
	
    if( ref(i).import*ref(i).factor > ref(parent(i)).import*ref(parent(i)).factor )
	{
        swap(i,parent(i));
        upheap(parent(i));
    }
}

void Heap::downheap(int i)
{
    if (i>=size) return;        // perhaps just extracted the last
	
    int largest = i,
        l = left(i),
        r = right(i);
	
    if( l<size && ref(l).import*ref(l).factor > ref(largest).import*ref(largest).factor ) largest = l;
    if( r<size && ref(r).import*ref(r).factor > ref(largest).import*ref(largest).factor ) largest = r;
	
    if( largest != i )
	{
        swap(i,largest);
        downheap(largest);
    }
}



void Heap::insert(Labelled *t, real v, real f)
{
    if( size == maxLength() )
    {
		cerr << "NOTE: Growing heap from " << size << " to " << 2*size << endl;
		resize(2*size);
    }
	
    int i = size++;
	
    ref(i).obj = t;
    ref(i).import = v;
    ref(i).factor = f;
	
    ref(i).obj->token = i;
	
    upheap(i);
}

void Heap::update(Labelled *t, real v, real f)
{
    int i = t->token;
	
    if( i >= size )
    {
		cerr << "WARNING: Attempting to update past end of heap!" << endl;
		return;
    }
    else if( i == NOT_IN_HEAP )
    {
		cerr << "WARNING: Attempting to update object not in heap!" << endl;
		return;
    }
	
    real old = ref(i).import;
    real oldf = ref(i).factor;

    ref(i).import = v;
    ref(i).factor = f;
	
    if( v*f<old*oldf )
        downheap(i);
    else
        upheap(i);
}



heap_node *Heap::extract()
{
    if( size<1 ) return 0;
	
    swap(0,size-1);
    size--;
	
    downheap(0);
	
    ref(size).obj->token = NOT_IN_HEAP;
	
    return &ref(size);
}

heap_node *Heap::kill(int i)
{
    if( i>=size )
		cerr << "WARNING: Attempt to delete invalid heap node." << endl;
	
    swap(i, size-1);
    size--;
    ref(size).obj->token = NOT_IN_HEAP;
	
    if( ref(i).import*ref(i).factor < ref(size).import*ref(size).factor )
		downheap(i);
    else
		upheap(i);
	
	
    return &ref(size);
}
