#include<iostream>

template<typename T>
class MyList {
	struct Node {
		T val;
		Node* next;
	};
	Node* head;

	void copyFrom(const MyList& other) {
		if (!other.head) {
			head = nullptr;
			return;
		}

		Node* newLast = new Node();
		newLast->val = other.head->val;
		head = newLast;

		Node* otherNode = other.head->next;
		while (otherNode) {
			Node * newNode = new Node();
			newNode->val = otherNode->val;
			newLast->next = newNode;
			newLast = newNode;

			otherNode = otherNode->next;
		}
		
		newLast->next = nullptr;
	}

public:
	MyList() :
		head(nullptr)
	{}
	~MyList()
	{
		while (!empty())
			pop();
	}

	MyList(const MyList & other) {
		copyFrom(other);
	}

	MyList & operator= (const MyList & other) {
		/* POZOR, oprava z hodiny -- bez explicitniho vyprazdneni tohle
		 * leakne pamet. Bonus: metoda jak rucne zavolat destruktor. */
		this->~MyList();

		copyFrom(other);
		return *this;
	}

	void push(const T& value) {
		Node* newNode = new Node();
		newNode->val = value;
		newNode->next = head;
		head = newNode;
	}

	T& front() const {
		return head->val;
	}

	bool empty() const {
		return !head;
	}

	void pop() {
		Node* tmp = head->next;
		delete head;
		head = tmp;
	}

};

void test2() {
	MyList<MyList<int>> list;
	list.push(MyList<int>());
}

void test1() {
	MyList<int> a;

	a.push(1);
	a.push(2);
	a.push(3);

	MyList<int> b;
	b = a;
	MyList<int> c(a);

	a.pop();

	std::cout << b.front() << std::endl;
	std::cout << c.front() << std::endl;
}

void test()
{
	MyList<int> list;

	std::cout << list.empty() << std::endl;

	list.push(1);
	list.push(2);
	list.push(3);

	std::cout << list.front() << std::endl;
	std::cout << list.empty() << std::endl;

	list.pop();
	std::cout << list.front() << std::endl;
}

int main() 
{
	//test();
	test1();
	//test2();

	return 0;
}
