/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
using Antlr4.Runtime.Sharpen;
using Antlr4.Runtime.Tree;

namespace Antlr4.Runtime.Tree
{
    public abstract class AbstractParseTreeVisitor<Result> : IParseTreeVisitor<Result>
    {
        /// <summary>
        /// <inheritDoc/>
        /// <p>The default implementation calls
        /// <see cref="IParseTree.Accept{T}(IParseTreeVisitor{T})"/>
        /// on the
        /// specified tree.</p>
        /// </summary>
        public virtual Result Visit(IParseTree tree)
        {
            return tree.Accept(this);
        }

        /// <summary>
        /// <inheritDoc/>
        /// <p>The default implementation initializes the aggregate result to
        /// <see cref="AbstractParseTreeVisitor{Result}.DefaultResult()">defaultResult()</see>
        /// . Before visiting each child, it
        /// calls
        /// <see cref="AbstractParseTreeVisitor{Result}.ShouldVisitNextChild(IRuleNode, Result)">shouldVisitNextChild</see>
        /// ; if the result
        /// is
        /// <see langword="false"/>
        /// no more children are visited and the current aggregate
        /// result is returned. After visiting a child, the aggregate result is
        /// updated by calling
        /// <see cref="AbstractParseTreeVisitor{Result}.AggregateResult(Result, Result)">aggregateResult</see>
        /// with the
        /// previous aggregate result and the result of visiting the child.</p>
        /// <p>The default implementation is not safe for use in visitors that modify
        /// the tree structure. Visitors that modify the tree should override this
        /// method to behave properly in respect to the specific algorithm in use.</p>
        /// </summary>
        public virtual Result VisitChildren(IRuleNode node)
        {
            Result result = DefaultResult;
            int n = node.ChildCount;
            for (int i = 0; i < n; i++)
            {
                if (!ShouldVisitNextChild(node, result))
                {
                    break;
                }
                IParseTree c = node.GetChild(i);
                Result childResult = c.Accept(this);
                result = AggregateResult(result, childResult);
            }
            return result;
        }

        /// <summary>
        /// <inheritDoc/>
        /// <p>The default implementation returns the result of
        /// <see cref="AbstractParseTreeVisitor{Result}.DefaultResult()">defaultResult</see>
        /// .</p>
        /// </summary>
        public virtual Result VisitTerminal(ITerminalNode node)
        {
            return DefaultResult;
        }

        /// <summary>
        /// <inheritDoc/>
        /// <p>The default implementation returns the result of
        /// <see cref="AbstractParseTreeVisitor{Result}.DefaultResult()">defaultResult</see>
        /// .</p>
        /// </summary>
        public virtual Result VisitErrorNode(IErrorNode node)
        {
            return DefaultResult;
        }

        /// <summary>Gets the default value returned by visitor methods.</summary>
        /// <remarks>
        /// Gets the default value returned by visitor methods. This value is
        /// returned by the default implementations of
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitTerminal(ITerminalNode)">visitTerminal</see>
        /// ,
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitErrorNode(IErrorNode)">visitErrorNode</see>
        /// .
        /// The default implementation of
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)">visitChildren</see>
        /// initializes its aggregate result to this value.
        /// <p>The base implementation returns
        /// <see langword="null"/>
        /// .</p>
        /// </remarks>
        /// <returns>The default value returned by visitor methods.</returns>
        protected internal virtual Result DefaultResult
        {
            get
            {
                return default(Result);
            }
        }

        /// <summary>Aggregates the results of visiting multiple children of a node.</summary>
        /// <remarks>
        /// Aggregates the results of visiting multiple children of a node. After
        /// either all children are visited or
        /// <see cref="AbstractParseTreeVisitor{Result}.ShouldVisitNextChild(IRuleNode, Result)"/>
        /// returns
        /// <see langword="false"/>
        /// , the aggregate value is returned as the result of
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
        /// .
        /// <p>The default implementation returns
        /// <paramref name="nextResult"/>
        /// , meaning
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
        /// will return the result of the last child visited
        /// (or return the initial value if the node has no children).</p>
        /// </remarks>
        /// <param name="aggregate">
        /// The previous aggregate value. In the default
        /// implementation, the aggregate value is initialized to
        /// <see cref="AbstractParseTreeVisitor{Result}.DefaultResult()"/>
        /// , which is passed as the
        /// <paramref name="aggregate"/>
        /// argument
        /// to this method after the first child node is visited.
        /// </param>
        /// <param name="nextResult">
        /// The result of the immediately preceeding call to visit
        /// a child node.
        /// </param>
        /// <returns>The updated aggregate result.</returns>
        protected internal virtual Result AggregateResult(Result aggregate, Result nextResult)
        {
            return nextResult;
        }

        /// <summary>
        /// This method is called after visiting each child in
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
        /// . This method is first called before the first
        /// child is visited; at that point
        /// <paramref name="currentResult"/>
        /// will be the initial
        /// value (in the default implementation, the initial value is returned by a
        /// call to
        /// <see cref="AbstractParseTreeVisitor{Result}.DefaultResult()"/>
        /// . This method is not called after the last
        /// child is visited.
        /// <p>The default implementation always returns
        /// <see langword="true"/>
        /// , indicating that
        /// <c>visitChildren</c>
        /// should only return after all children are visited.
        /// One reason to override this method is to provide a "short circuit"
        /// evaluation option for situations where the result of visiting a single
        /// child has the potential to determine the result of the visit operation as
        /// a whole.</p>
        /// </summary>
        /// <param name="node">
        /// The
        /// <see cref="IRuleNode"/>
        /// whose children are currently being
        /// visited.
        /// </param>
        /// <param name="currentResult">
        /// The current aggregate result of the children visited
        /// to the current point.
        /// </param>
        /// <returns>
        ///
        /// <see langword="true"/>
        /// to continue visiting children. Otherwise return
        /// <see langword="false"/>
        /// to stop visiting children and immediately return the
        /// current aggregate result from
        /// <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
        /// .
        /// </returns>
        protected internal virtual bool ShouldVisitNextChild(IRuleNode node, Result currentResult)
        {
            return true;
        }
    }
}
