#include <iostream>

template <class T>
class LinkList
{
private:

    struct ListNode
    {
        T value1;
        struct ListNode *next;
    };

    ListNode *head;   // List head pointer

    void destroy(); // utility function

public:
    //***Constructor***
    LinkList();
    LinkList(const LinkList&);

    //***Destructor***
    ~LinkList();

    LinkList& operator=(LinkList);

    //***LinkList Operations***
    void append(T);
    // removed insert since it's invariants are violated by append.
    void display(std::ostream& stream) const;
};

template <class T>
void LinkList<T>::display(std::ostream& os) const
{
    unsigned index = 0;

    ListNode* current = head;

    while (current)
    {
        os << index++ << ": " << current->value1 << '\n';
        current = current->next;
    }
}

//Implimentation for LinkList
template <class T>
void LinkList<T>::destroy()
{
    ListNode* current = head;

    while (current)
    {
        ListNode* next = current->next;
        delete current;
        current = next;
    }

    head = nullptr;
}

//***Constructor***
template <class T>
LinkList<T>::LinkList() : head(nullptr)
{
}

template <class T>
LinkList<T>::LinkList(const LinkList<T>& list) : head(nullptr)
{
    ListNode* current = list.head;

    while (current)
    {
        append(current->value1);
        current = current->next;
    }
}

template <class T>
LinkList<T>& LinkList<T>::operator=(LinkList list)
{
    destroy();
    head = list.head;
    list.head = nullptr;

    return *this;
}


//***Destructor***
template <class T>
LinkList<T>::~LinkList()
{
    destroy();
}


//***LinkList Operations***
template <class T>
void LinkList<T>::append(T val1)
{
    ListNode* n = new ListNode;
    n->value1 = val1;
    n->next = nullptr;

    if (head == nullptr)
        head = n;
    else
    {
        ListNode* current = head;

        while (current->next)
            current = current->next;

        current->next = n;
    }
}

int main()
{
    LinkList<int> a;
    a.append(3);
    a.append(2);
    a.append(1);
    a.display(std::cout);
    std::cout << '\n';

    LinkList<int> b(a);		// copy constructor
    b.display(std::cout);
    std::cout << '\n';

    LinkList<int> c;
    c = a;					// copy assignment
    c.display(std::cout);
    std::cout << '\n';
}