#pragma once
#include <iostream>
#include <string>
#include "chainNode.h"
#include "linearList.h"

template <typename T>
class chain : public linearList<T> {
public:
	chain(int initialCapacity = 10);
	chain(const chain<T>& x);
	~chain();
	virtual bool empty() const; //If empty, return 0;
	virtual int size() const; //Return Array Size
	virtual T& get(int theIndex) const; // Return Arr[theIndex]
	virtual int indexOf(const T& theElement) const; //Return the index of "theElement" first appeared
	virtual void erase(int theIndex); //Erase Arr[theIndex] 
	virtual void insert(int theIndex, const T& theElement); //Insert theElement to place Arr[theIndex]
	virtual void output() const; //cout		
protected:
	chainNode<T>* first;
	int listSize;
	int capacity;
};

template <typename T>
chain<T>::chain(int initialCapacity) {
	capacity = initialCapacity;
}

template <typename T>
chain<T>::chain(const chain<T>& x) {
	//**********Copy The WHOLE Chain*********
	capacity = x.capacity;
	listSize = x.listSize;
	//**********Deep Copy: Copy Every Node with figures********

	if (x.first == nullptr) {
		first = nullptr;
		return;
	}

	chainNode<T>* source = x.first;
	first = new chainNode<T>(source->element);//equals to chainNode<T>(source->element, nullptr)
	chainNode<T>* target = first;

	source = source->next;

	while (source != nullptr) {
		target->next = new chainNode<T>(source->element);
		target = target->next;
		source = source->next;
	}
}

template <class T>
chain<T>::~chain() {
	chainNode<T>* tmp = first;
	while (tmp != nullptr) {
		tmp = tmp->next;
		delete first;
		first = tmp;
	}
}

template <class T>
bool chain<T>::empty() const {
	//If empty, return 0;
	return listSize == 0;
}

template <class T>
int chain<T>::size() const
{
	//Return Array Size
	return listSize;
}

template <class T>
T& chain<T>::get(int theIndex) const
{
	// Return Arr[theIndex]
	if (theIndex < 0 || theIndex >= listSize) {
		throw std::out_of_range("Index out of bounds: " + std::to_string(theIndex));
	}

	chainNode<T>* tmp = first;
	for (int i = 1; i <= theIndex; i++) {
		tmp = tmp->next;
	}
	return tmp->element;
}

template <class T>
int chain<T>::indexOf(const T& theElement) const
{
	//Return the index of "theElement" first appeared
	chainNode<T>* tmp = first;
	for (int i = 0; i < listSize; i++) {
		if (tmp->element == theElement) {
			return i;//i = arr - 1
		}
		tmp = tmp->next;
	}
	return -1;
}

template <class T>
void chain<T>::erase(int theIndex)
{
	//Erase Arr[theIndex]
	if (theIndex < 0 || theIndex >= listSize) {
		throw std::out_of_range("Index out of bounds: " + std::to_string(theIndex));
	}

	chainNode<T>* deleteNode;

	if (theIndex == 0) {
		deleteNode = first;
		first = first->next;
	}
	else {
		chainNode<T>* prev = first;
		for (int i = 0; i < theIndex - 1; i++) {
			prev = prev->next;
		}
		deleteNode = prev->next;
		prev->next = deleteNode->next;
	}
	delete deleteNode;
	listSize--;
}


template <class T>
void chain<T>::insert(int theIndex, const T& theElement)
{
	//Insert theElement to place Arr[theIndex]
	chainNode<T>* arr = first;
	if (theIndex < 0) throw std::out_of_range("index out of range");

	if (theIndex == 0) {
		// ²åÈëµ½Í·²¿
		first = new chainNode<T>(theElement, first);
	}
	else {
		for (int i = 0; i < theIndex - 1; i++) {
			arr = arr->next;
		}
		chainNode<T>* insert = new chainNode<T>(theElement);
		insert->next = arr->next;
		arr->next = insert;
		listSize++;
	}
}

template <class T>
void chain<T>::output() const
{
	//cout
	chainNode<T>* tmp = first;
	for (int i = 0; i < listSize; i++) {
		std::cout << tmp->element << " ";
		tmp = tmp->next;
	}
	std::cout << std::endl;
}
