#pragma once
#include <iostream>

// Forward declaration of LinkedList
template <typename T> class LinkedList;

/// <summary>
/// Template class to allow the LinkedListNode to store any data type
/// </summary>
/// <typeparam name="T">Value type</typeparam>
template <typename T>
class LinkedListNode {
private:
    T _value; // Value of the node
    LinkedListNode* _next; // Pointer to the next node in the linked list

public:
    /// <summary>
    /// Linked list item constructor
    /// </summary>
    /// <param name="value">The value of the node</param>
    /// <param name="next">The next node in the linked list</param>
    LinkedListNode(const T& value, LinkedListNode* next);

    /// <summary>
    /// Retrieve the value of the node
    /// </summary>
    /// <returns>The respective value for the node</returns>
    const T& getValue() const;

    /// <summary>
    /// Retrieve next node in the linked list
    /// </summary>
    /// <returns>Next linked node</returns>
    LinkedListNode* getNext();

    /// <summary>
    /// Assigns the item new value
    /// </summary>
    /// <param name="other">The value to be replaced with</param>
    /// <returns>New linked list item</returns>
    LinkedListNode<T>& operator=(const LinkedListNode<T>& other);

    template <typename U> friend class LinkedList;
};

// Implementation of LinkedListNode

template <typename T>
LinkedListNode<T>::LinkedListNode(const T& value, LinkedListNode* next)
    : _value(value), _next(next) {}

template<typename T>
const T& LinkedListNode<T>::getValue() const {
    return _value;
}

template <typename T>
LinkedListNode<T>* LinkedListNode<T>::getNext() {
    return _next;
}

template <typename T>
LinkedListNode<T>& LinkedListNode<T>::operator=(const LinkedListNode<T>& other) {
    if (this != &other) {
        _value = other._value;
        _next = other._next;
    }
    return *this;
}