/*
    SPDX-FileCopyrightText: 2003-2006 Cies Breijs <cies AT kde DOT nl>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#ifndef _TREENODE_H_
#define _TREENODE_H_

#include <QList>

#include "token.h"
#include "value.h"

/**
 * @short A node in the pointer based node tree structure.
 *
 * The TreeNode object is a node in the node tree as created by the Parser.
 * It can be executed by the Executer.
 *
 * The list of pointers to the children of the TreeNode is only created
 * when it is needed.
 * Each TreeNode has a list of pointers to its children, a pointer to its
 * parent, a pointer to one Token, and can also have a pointer to a Value.
 *
 * @author Cies Breijs
 */
class TreeNode
{
public:
    /**
     * @short Constructor.
     * Initialses the TreeNode.
     * @param token pointer to Token that the TreeNode is associated with.
     */
    explicit TreeNode(Token *token)
    {
        init(nullptr, token);
    }

    /**
     * @short Destructor.
     * This deletes the Value and the Token associated with this TreeNode.
     * The childList auto-deletes all the children, which means that deleting
     * the root node deletes the whole tree.
     */
    virtual ~TreeNode();

    /** @returns the pointer to the parent TreeNode. @see setParent() */
    TreeNode *parent()
    {
        return _parent;
    }

    /** @returns the pointer to associated Token. @see setToken() */
    Token *token()
    {
        return _token;
    }

    /** @returns the pointer to associated Value. @see setValue() @see setNullValue() */
    Value *value()
    {
        if (_value == nullptr)
            _value = new Value();
        return _value;
    }

    /** Sets the pointer to the parent to @p parent. @see parent() */
    void setParent(TreeNode *parent)
    {
        _parent = parent;
    }

    /** Sets the pointer to the associated token to @p token. @see token() and @see TreeNode() */
    void setToken(Token *token)
    {
        _token = token;
    }

    /** Sets the pointer to the associated value to @p value. @see setNullValue() @see value() */
    void setValue(Value value)
    {
        delete _value;
        _value = new Value(value);
    }

    /** Sets the pointer to the associated value to zero. @see setValue() @see value() */
    void setNullValue()
    {
        delete _value;
        _value = nullptr;
    } // appears Empty (see value())

    /** @returns TRUE is the TreeNode has an associated Value. @see value @see setValue */
    bool hasValue() const
    {
        return _value != nullptr;
    }

    /** @returns TRUE is the TreeNode has children. @see childCount @see appendChild */
    bool hasChildren() const
    {
        if (childList == nullptr)
            return false;
        else
            return !childList->isEmpty();
    }

    /** @returns the amount of children. @see appendChild @see hasChildren */
    uint childCount() const
    {
        if (childList == nullptr)
            return 0;
        else
            return childList->size();
    }

    /**
     * Appends the pointer to the TreeNode @p newChild to the childList and
     * sets the child's parent to this. @see childCount @see hasChildren
     */
    void appendChild(TreeNode *newChild);

    /** @returns the pointer to child number @p i (zero if the child does not exists). This does not change the current child. */
    TreeNode *child(int i);

    /** @returns the pointer to the first child (zero if the child does not exists), and set the current child to the first */
    TreeNode *firstChild();

    /** @returns the pointer to the next child (zero if the child does not exists), and set the current child to the next */
    TreeNode *nextChild();

    /** @returns the pointer to the next sibling; the next child of the parent (zero if the next sibling does not exists) */
    TreeNode *nextSibling();

    /** @returns the node tree, starting from 'this' node, as a multi line string */
    QString toString();

private:
    /// Initializes a the TreeNode. Called by the constructor.
    void init(TreeNode *parent, Token *token);

    /** Calls itself, @ref show(), and @ref showTree() for each of the children */
    virtual void show(QString &str, int indent = 0) const;

    /** Prints an indented string describing itself to de debug info */
    void showTree(QString &str, int indent = 0);

    int findChildIndex(TreeNode *child);

    /// typedef for the ChildList.
    typedef QList<TreeNode *> ChildList;

    /// The childList, contains pointers to the children of this node.
    ChildList *childList;

    /// Keeps track of the index of the current child. Zero when no child list is available.
    int currentChildIndex;

    /// The pointer to the parent of this TreeNode.
    TreeNode *_parent;

    /// The pointer to the token associated with this TreeNode (cannot be zero).
    Token *_token;

    /// The pointer to the value associated with this TreeNode (can be zero).
    Value *_value;
};

#endif // _TREENODE_H_
