static bool testListInsertAfterCurrent() {
	ASSERT_TRUE(SP_LIST_NULL_ARGUMENT == spListInsertAfterCurrent(NULL, NULL));

	SPListElement e1 = spListElementCreate(1, 1.0);
	SPListElement e2 = spListElementCreate(2, 2.0);
	SPListElement e3 = spListElementCreate(3, 3.0);
	SPListElement e4 = spListElementCreate(4, 4.0);
	SPList list2 = quickList(3, e2, e3, e4);
	ASSERT_TRUE(SP_LIST_NULL_ARGUMENT == spListInsertAfterCurrent(list2,NULL));
	ASSERT_TRUE(SP_LIST_INVALID_CURRENT == spListInsertAfterCurrent(list2, e1));
	spListGetFirst(list2);
	spListGetNext(list2);
	ASSERT_TRUE(SP_LIST_SUCCESS == spListInsertAfterCurrent(list2, e1));
	ASSERT_TRUE(4 == spListGetSize(list2));
	ASSERT_TRUE(spListElementCompare(e2, spListGetFirst(list2))==0);
	ASSERT_TRUE(spListElementCompare(e3, spListGetNext(list2))==0);
	ASSERT_TRUE(spListElementCompare(e1, spListGetNext(list2))==0);
	ASSERT_TRUE(spListElementCompare(e4, spListGetNext(list2))==0);
	ASSERT_TRUE(spListGetNext(list2) == NULL);
	ASSERT_TRUE(spListGetNext(list2) == NULL);
	spListDestroy(list2);
	spListElementDestroy(e1);
	spListElementDestroy(e2);
	spListElementDestroy(e3);
	spListElementDestroy(e4);
	return true;
}
static bool bpqPeekLastTest() {
	SPBPQueue source, source2;
	SPListElement e1, e2, e3, e4, last, last2;

	source = spBPQueueCreate(maxSize);
	ASSERT_TRUE(spBPQueuePeekLast(source) == NULL); // check edge case

	// e1, e2, e3, e4
	CREATE_4_ELEMENTS()

	// insert element in unsorted order
	source2 = quickQ(4, e3, e1, e4, e2);

	last = spBPQueuePeekLast(source2);
	last2 = spBPQueuePeekLast(source2);

	ASSERT_TRUE(spListElementCompare(e4, last) == 0); // check that peekLast is the maximum
	ASSERT_TRUE(spListElementCompare(last, last2) == 0 && last2 != last); // new copy so not ==

	// free memory
	spBPQueueDestroy(source);
	spBPQueueDestroy(source2);
	spListElementDestroy(last);
	spListElementDestroy(last2);

	// e1, e2, e3, e4
	DESTROY_4_ELEMENTS()
	return true;
}
static bool testListCopy() {
	ASSERT_TRUE(spListCopy(NULL) == NULL);
	SPList list = spListCreate();
	SPList copy = spListCopy(list);
	ASSERT_TRUE(copy != NULL);
	ASSERT_TRUE(0 == spListGetSize(copy));
	SPListElement e1 = spListElementCreate(1, 1.0);
	SPListElement e2 = spListElementCreate(2, 2.0);
	SPListElement e3 = spListElementCreate(3, 3.0);
	SPListElement e4 = spListElementCreate(4, 4.0);
	spListInsertFirst(list, e1);
	ASSERT_TRUE(0 == spListGetSize(copy));
	SPList list2 = quickList(4, e1, e2, e3, e4);
	SPList copy2 = spListCopy(list2);
	ASSERT_TRUE(4 == spListGetSize(copy2));
	ASSERT_TRUE(spListElementCompare(e1, spListGetFirst(copy2)) == 0);
	ASSERT_TRUE(spListElementCompare(e2, spListGetNext(copy2)) == 0);
	ASSERT_TRUE(spListElementCompare(e3, spListGetNext(copy2)) == 0);
	ASSERT_TRUE(spListElementCompare(e4, spListGetNext(copy2)) == 0);
	ASSERT_TRUE(spListGetNext(copy2) == NULL);
	spListDestroy(list);
	spListDestroy(list2);
	spListDestroy(copy);
	spListDestroy(copy2);
	spListElementDestroy(e1);
	spListElementDestroy(e2);
	spListElementDestroy(e3);
	spListElementDestroy(e4);
	return true;
}
// tester for spBPQueueCopy
static bool bpqCopyTest() {
	SPBPQueue source, source2, copy, copy2;
	SPListElement e1, e2, e3, e4, epeek;

	ASSERT_TRUE(spBPQueueCopy(NULL) == NULL); // check edge case

	source = spBPQueueCreate(10);
	copy = spBPQueueCopy(source);
	ASSERT_TRUE(copy != NULL);
	ASSERT_TRUE(0 == spBPQueueSize(copy));

	// e1, e2, e3, e4
	CREATE_4_ELEMENTS()

	spBPQueueEnqueue(source, e1);
	ASSERT_TRUE(0 == spBPQueueSize(copy)); // ensure the copy is a NEW COPY

	source2 = quickQ(4, e1, e2, e3, e4);
	copy2 = spBPQueueCopy(source2);
	ASSERT_TRUE(4 == spBPQueueSize(copy2)); // check that size of copy is correct

	// check that all elements copied correctly
	epeek = spBPQueuePeek(copy2);
	ASSERT_TRUE(spListElementCompare(e1, epeek) == 0);
	spBPQueueDequeue(copy2);
	spListElementDestroy(epeek); // free the element

	// repeat
	epeek = spBPQueuePeek(copy2);
	ASSERT_TRUE(spListElementCompare(e2, epeek) == 0);
	spBPQueueDequeue(copy2);
	spListElementDestroy(epeek);

	epeek = spBPQueuePeek(copy2);
	ASSERT_TRUE(spListElementCompare(e3, epeek) == 0);
	spBPQueueDequeue(copy2);
	spListElementDestroy(epeek);

	epeek = spBPQueuePeek(copy2);
	ASSERT_TRUE(spListElementCompare(e4, epeek) == 0);
	spBPQueueDequeue(copy2);
	spListElementDestroy(epeek);

	epeek = spBPQueuePeek(copy2);
	ASSERT_TRUE(epeek == NULL);

	// free all remaining memory
	spListElementDestroy(epeek);
	spBPQueueDestroy(source);
	spBPQueueDestroy(source2);
	spBPQueueDestroy(copy);
	spBPQueueDestroy(copy2);

	// e1, e2, e3, e4
	DESTROY_4_ELEMENTS()
	return true;
}
static bool testElementCopy() {
	ASSERT_TRUE(spListElementCopy(NULL) == NULL);
	SPListElement element = spListElementCreate(1, 0.0);
	SPListElement elementCopy = spListElementCopy(element);
	ASSERT_TRUE(elementCopy!=NULL);
	ASSERT_TRUE(spListElementCompare(element, elementCopy) == 0);
	ASSERT_TRUE(spListElementSetIndex(elementCopy, 2) == SP_ELEMENT_SUCCESS);
	ASSERT_TRUE(spListElementCompare(element, elementCopy) < 0);
	ASSERT_TRUE(spListElementGetIndex(elementCopy) == 2);
	ASSERT_TRUE(spListElementGetIndex(element) == 1);
	ASSERT_TRUE(spListElementSetValue(element, 1.0) == SP_ELEMENT_SUCCESS);
	ASSERT_TRUE(spListElementCompare(element, elementCopy) > 0);
	spListElementDestroy(element);
	spListElementDestroy(elementCopy);
	return true;
}
static bool testListGetLast() {
	SPList list = spListCreate();
	ASSERT_TRUE(spListGetLast(list) == NULL);
	SPListElement e1 = spListElementCreate(1, 1.0);
	SPListElement e2 = spListElementCreate(2, 2.0);
	SPListElement e3 = spListElementCreate(3, 3.0);
	SPListElement e4 = spListElementCreate(4, 4.0);
	SPList list2 = quickList(4, e1, e2, e3, e4);
	SPListElement last = spListGetLast(list2);
	ASSERT_TRUE(spListElementCompare(e4, last) == 0);
	ASSERT_TRUE(
			spListElementCompare(last, spListGetLast(list2)) == 0
					&& spListGetLast(list2) == last);
	spListDestroy(list);
	spListDestroy(list2);
	spListElementDestroy(e1);
	spListElementDestroy(e2);
	spListElementDestroy(e3);
	spListElementDestroy(e4);
	return true;
}
static bool testListForEach() {
	SPListElement e1 = spListElementCreate(1, 1.0);
	SPListElement e2 = spListElementCreate(2, 2.0);
	SPListElement e3 = spListElementCreate(3, 3.0);
	SPListElement e4 = spListElementCreate(4, 4.0);
    SPListElement e5 = spListElementCreate(5, 5.0);
	SPListElement arr[5] = {e1,e2,e3,e4,e5};
	int i = 1;
	SPList list = quickList(3, e2, e3, e4);
	SP_LIST_FOREACH(SPListElement,e,list){
		ASSERT_TRUE(spListElementCompare(e,arr[i]) == 0);
		i++;
	}
SP_BPQUEUE_MSG spBPQueueEnqueue(SPBPQueue source, SPListElement element) {
	if (source == NULL || element == NULL) {
		return SP_BPQUEUE_INVALID_ARGUMENT;
	}

	bool wasFull = spBPQueueIsFull(source);

	SPList list = source->innerList;

	bool wasInserted = false;
	// Advance iterator to the proper element's place
	SP_LIST_FOREACH(SPListElement, currentElement, list) {

		if (spListElementCompare(element, currentElement) < 0) {

			// Modifying while iterating - bad practice but is more efficient here.
			SP_LIST_MSG returnMSG = spListInsertBeforeCurrent(list, element);

			switch (returnMSG) {
			case SP_LIST_OUT_OF_MEMORY:
				return SP_BPQUEUE_OUT_OF_MEMORY;
			default:
				break;
			}
			wasInserted = true;
			break;
		}
	}

	if (wasInserted) {
		// Remove the last element if needed
		if (wasFull) {
			spListGetLast(list);
			spListRemoveCurrent(list);
		}
		return SP_BPQUEUE_SUCCESS;
	} else {
		if (spBPQueueIsFull(source)) {
			return SP_BPQUEUE_FULL;
		} else {
			// The item is largest than everything, insert last
			SP_LIST_MSG returnMSG = spListInsertLast(list, element);
			switch (returnMSG) {
			case SP_LIST_OUT_OF_MEMORY:
				return SP_BPQUEUE_OUT_OF_MEMORY;
			default:
				return SP_BPQUEUE_SUCCESS;
			}
		}
	}
}
SP_BPQUEUE_MSG spBPQueueInsertNotEmpty(SPBPQueue source, SPListElement newElement) {
	SPListElement currElemInQueue = spListGetFirst(source->queue);

	while (currElemInQueue != NULL && spListElementCompare(currElemInQueue, newElement) <= 0) {
		currElemInQueue = spListGetNext(source->queue);
	}

	// currElemInQueue > newElement
	if (currElemInQueue != NULL) {
		currElemInQueue = NULL;
		return spBPQueueInsertNotEmptyNotLast(source, newElement);
	}

	// we are not at full capacity because we took care of it before
	return spBPQueueInsertNotEmptyButLast(source, newElement);
}
SP_BPQUEUE_MSG spBPQueueEnqueue(SPBPQueue source, SPListElement element) {
	spMinimalVerifyArguments(source != NULL && source->queue != NULL && element != NULL,
			SP_BPQUEUE_INVALID_ARGUMENT);

	if (spBPQueueGetMaxSize(source) == 0)
		return SP_BPQUEUE_FULL;


	// the list is full and the element is greater than all the current items
	if (spBPQueueIsFull(source) && spListElementCompare(element, source->maxElement) >= 0) {
		return SP_BPQUEUE_FULL;
	}

	if (spBPQueueIsEmpty(source))
		return spBPQueueInsertIfEmpty(source,element);

	//insert to a non empty queue
	return spBPQueueInsertNotEmpty(source, element);
}
static bool testElementCompare() {
	SPListElement element1 = spListElementCreate(1, 0.0);
	SPListElement element2 = spListElementCreate(2, 0.0);
	SPListElement element3 = spListElementCreate(1, 1.0);
	SPListElement element4 = spListElementCreate(1, 0.0);
	ASSERT_TRUE(spListElementCompare(element1, element1) == 0);
	ASSERT_TRUE(spListElementCompare(element1, element2) < 0);
	ASSERT_TRUE(spListElementCompare(element2, element1) > 0);
	ASSERT_TRUE(spListElementCompare(element1, element3) < 0);
	ASSERT_TRUE(spListElementCompare(element3, element1) > 0);
	ASSERT_TRUE(spListElementCompare(element1, element4) == 0);
	ASSERT_TRUE(spListElementCompare(element4, element1) == 0);
	spListElementDestroy(element1);
	spListElementDestroy(element2);
	spListElementDestroy(element3);
	spListElementDestroy(element4);
	return true;
}
	SP_LIST_FOREACH(SPListElement,e,list){
		ASSERT_TRUE(spListElementCompare(e,arr[i]) ==  0);
		i++;
	}
static bool bpqEnqueueTest() {
	SPBPQueue source, source2;
	SPListElement e, e1, e2, e3, e4, e5, peek, peekLast;

	ASSERT_TRUE(SP_BPQUEUE_INVALID_ARGUMENT == spBPQueueEnqueue(NULL, NULL)); // check edge case

	CREATE_4_ELEMENTS() // e1, e2, e3, e4
	e5 = spListElementCreate(5, 4.0);
	source = quickQ(3, e2, e1, e4);
	ASSERT_TRUE(SP_BPQUEUE_SUCCESS == spBPQueueEnqueue(source, e3)); // check that enqueue succeeded
	ASSERT_TRUE(SP_BPQUEUE_SUCCESS == spBPQueueEnqueue(source, e5));
	ASSERT_TRUE(5 == spBPQueueSize(source));

	// check that enqueue inserts in order
	peek = spBPQueuePeek(source);
	peekLast = spBPQueuePeekLast(source);
	ASSERT_TRUE(spListElementCompare(e1, peek) == 0);
	// make sure queue sorts by value and then by index
	ASSERT_TRUE(spListElementCompare(e5, peekLast) == 0);

	// e1, e2, e3, e4
	DESTROY_4_ELEMENTS()
	spListElementDestroy(e5);

	// create new queue with maxSize
	source2 = spBPQueueCreate(maxSize);

	// insert 2*maxSize elements from lowest to highest value and check that min and max are correct
	for (int i = 0; i < maxSize; i++) {
		e = spListElementCreate(i, (double) i);
		ASSERT_TRUE(SP_BPQUEUE_SUCCESS == spBPQueueEnqueue(source2, e));
		spListElementDestroy(e);
	}
	for (int i = maxSize; i < 2 * maxSize; i++) {
		e = spListElementCreate(i, (double) i);
		ASSERT_TRUE(SP_BPQUEUE_FULL == spBPQueueEnqueue(source2, e)); // check full when inserting more then maxSize elements
		spListElementDestroy(e);
	}
	ASSERT_TRUE(spBPQueueMinValue(source2) == 0.0);

	// check that all elements with value too high are not in the queue
	ASSERT_TRUE((int )spBPQueueMaxValue(source2) == maxSize - 1);
	spBPQueueClear(source2);

	// insert 2*maxSize elements from highest to lowest value and check that min and max are correct and same as before
	for (int i = 2 * maxSize - 1; i >= 0; i--) {
		e = spListElementCreate(i, (double) i);
		spBPQueueEnqueue(source2, e);
		spListElementDestroy(e);
	}

	// check min value is correct
	ASSERT_TRUE(spBPQueueMinValue(source2) == 0.0);
	ASSERT_TRUE((int )spBPQueueMaxValue(source2) == maxSize - 1);

	// free memory
	spBPQueueDestroy(source);
	spBPQueueDestroy(source2);
	spListElementDestroy(peek);
	spListElementDestroy(peekLast);


	return true;
}
SP_BPQUEUE_MSG spBPQueueEnqueue(SPBPQueue source, SPListElement element){
    int i;
    struct Qnode* new_node;
    struct Qnode* n;
    struct Qnode* oldNext;

    if (!source || !element){
        return SP_BPQUEUE_INVALID_ARGUMENT;
    }


    // create new node using the element's data
    new_node = newNode(spListElementGetIndex(element), spListElementGetValue(element));


    if (!new_node){
        return SP_BPQUEUE_OUT_OF_MEMORY;
    }

    n = source->first;

    // if queue is full
    if (source->size >= source->maxSize){
        // compare the new element to the last element
        if (spListElementCompare(new_node->element, source->last->element) == 1){
            spListElementDestroy(new_node->element);
            free(new_node);
            return SP_BPQUEUE_FULL;
        }
        // new element is smaller, therefore destroy current last node
        spListElementDestroy(source->last->element);
        free(source->last);

        // set the new last node pointer to NULL
        for(i=0;i<source->size-2;i++){
            n=n->next;
        }
        n->next=NULL;
    }

    n = source->first;

    // if queue is empty
    if (!source->first){
        source->first = new_node;
        source->last = new_node;
    } else {
        if (spListElementCompare(n->element, new_node->element) == 1){
            // in case new node is smallest
            source->first = new_node;
            new_node->next = n;
        } else {
            while (n->next && spListElementCompare(n->next->element, new_node->element) == -1){
                n = n->next;
            }
            oldNext = n->next;
            n->next = new_node;
            new_node->next = oldNext;
        }
    }

    n = source->first;
    while (n->next){
       n = n->next;
    }
    source->last = n;

    // if queue is not full, increment size
    if (source->size != source->maxSize){
        source->size += 1;
    }

	return SP_BPQUEUE_SUCCESS;
}