#include "ListIterator.h"
#include "SortedIndexedList.h"
#include <iostream>
using namespace std;
#include <exception>

SortedIndexedList::SortedIndexedList(Relation r) {
	// O(1)
	this->_relation = r;
	this->_capacity = 10;
	this->_length = 0;
	this->_elements = new TComp[this->_capacity];
	this->_next = new int[this->_capacity];
	this->_prev = new int[this->_capacity];
	for(int i = 0; i < this->_capacity; i++){
		this->_elements[i] = NULL_TCOMP;
		this->_next[i] = -1;
		this->_prev[i] = -1;
	}
	this->_head = -1;
	this->_tail = -1;
	this->_firstEmpty = 0;
}

int SortedIndexedList::size() const {
	//O(1)
	return this->_length;
}

bool SortedIndexedList::isEmpty() const {
	//O(1)
	return this->_length == 0;
}

TComp SortedIndexedList::getElement(int i) const{
	//O(i) - average case | O(i) - worst case | O(i) - best case
	if(i < 0 || i >= this->_length)
		throw exception();
	int current = this->_head;
	while(i != 0){
		i--;
		current = this->_next[current];
	}
	return this->_elements[current];
}

TComp SortedIndexedList::remove(int i) {
	// O(i) - average case | O(i) - worst case | O(i) - best case
	if(i < 0 || i >= this->_length)
		throw exception();
	int current = this->_head;
	while(i != 0){
		i--;
		current = this->_next[current];
	}
	TComp removed = this->_elements[current];
	if(this->_head == current)
		this->_head = this->_next[current];
	else
		this->_next[this->_prev[current]] = this->_next[current];
	if(this->_tail == current)
		this->_tail = this->_prev[current];
	else
		this->_prev[this->_next[current]] = this->_prev[current];
	this->_elements[current] = NULL_TCOMP;
	this->_next[current] = -1;
	this->_prev[current] = -1;
	this->_length--;
	if(this->_firstEmpty > current)
		this->_firstEmpty = current;
	return removed;
}

int SortedIndexedList::search(TComp e) const {
	//O(n) - average case | O(n) - worst case | O(1) - best case
	int current = this->_head;
	int i = 0;
	while(current != -1){
		if(this->_elements[current] == e)
			return i;
		current = this->_next[current];
		i++;
	}
	return -1;
}

void SortedIndexedList::add(TComp e) {
	// O(n) - average case | O(n) - worst case | O(1) - best case
	if(this->_length == this->_capacity)
		this->resize();
	int current = this->_head;
	int prev = -1;
	while(current != -1 && this->_relation(this->_elements[current], e)){
		prev = current;
		current = this->_next[current];
	}
	this->_elements[this->_firstEmpty] = e;
	this->_next[this->_firstEmpty] = current;
	this->_prev[this->_firstEmpty] = prev;
	if(prev == -1)
		this->_head = this->_firstEmpty;
	else
		this->_next[prev] = this->_firstEmpty;
	if(current == -1)
		this->_tail = this->_firstEmpty;
	else
		this->_prev[current] = this->_firstEmpty;
	this->_length++;
	while(this->_firstEmpty < this->_capacity && this->_elements[this->_firstEmpty] != NULL_TCOMP)
		this->_firstEmpty++;
		
}

ListIterator SortedIndexedList::iterator(){
	//O(1)
	return ListIterator(*this);
}

//destructor
SortedIndexedList::~SortedIndexedList() {
	//O(1)
	delete[] this->_elements;
	delete[] this->_next;
	delete[] this->_prev;
}

void SortedIndexedList::resize(){
	//O(n)
	this->_capacity *= 2;
	TComp* newElements = new TComp[this->_capacity];
	int* newNext = new int[this->_capacity];
	int* newPrev = new int[this->_capacity];
	for(int i = 0; i < this->_capacity; i++){
		newElements[i] = NULL_TCOMP;
		newNext[i] = -1;
		newPrev[i] = -1;
	}
	for(int i = 0; i < this->_length; i++){
		newElements[i] = this->_elements[i];
		newNext[i] = this->_next[i];
		newPrev[i] = this->_prev[i];
	}
	delete[] this->_elements;
	delete[] this->_next;
	delete[] this->_prev;
	this->_elements = newElements;
	this->_next = newNext;
	this->_prev = newPrev;
}