// [The "BSD license"]
//  Copyright (c) 2013 Terence Parr
//  Copyright (c) 2013 Sam Harwell
//  Copyright (c) 2014 Eric Vergnaud
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//  1. Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//  3. The name of the author may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///

//  A rule context is a record of a single rule invocation. It knows
//  which context invoked it, if any. If there is no parent context, then
//  naturally the invoking state is not valid.  The parent link
//  provides a chain upwards from the current rule invocation to the root
//  of the invocation tree, forming a stack. We actually carry no
//  information about the rule associated with this context (except
//  when parsing). We keep only the state number of the invoking state from
//  the ATN submachine that invoked this. Contrast this with the s
//  pointer inside ParserRuleContext that tracks the current state
//  being "executed" for the current rule.
//
//  The parent contexts are useful for computing lookahead sets and
//  getting error information.
//
//  These objects are used during parsing and prediction.
//  For the special case of parsers, we use the subclass
//  ParserRuleContext.
//
//  @see ParserRuleContext
///

var RuleNode = require('./tree/Tree').RuleNode;
var INVALID_INTERVAL = require('./tree/Tree').INVALID_INTERVAL;

function RuleContext(parent, invokingState) {
    RuleNode.call(this);
    // What context invoked this rule?
    this.parentCtx = parent || null;
    // What state invoked the rule associated with this context?
    // The "return address" is the followState of invokingState
    // If parent is null, this should be -1.
    this.invokingState = invokingState || -1;
    return this;
}

RuleContext.prototype = Object.create(RuleNode.prototype);
RuleContext.prototype.constructor = RuleContext;

RuleContext.prototype.depth = function () {
    var n = 0;
    var p = this;
    while (p !== null) {
        p = p.parentCtx;
        n += 1;
    }
    return n;
};

// A context is empty if there is no invoking state; meaning nobody call
// current context.
RuleContext.prototype.isEmpty = function () {
    return this.invokingState === -1;
};

// satisfy the ParseTree / SyntaxTree interface

RuleContext.prototype.getSourceInterval = function () {
    return INVALID_INTERVAL;
};

RuleContext.prototype.getRuleContext = function () {
    return this;
};

RuleContext.prototype.getPayload = function () {
    return this;
};

// Return the combined text of all child nodes. This method only considers
// tokens which have been added to the parse tree.
// <p>
// Since tokens on hidden channels (e.g. whitespace or comments) are not
// added to the parse trees, they will not appear in the output of this
// method.
// /
RuleContext.prototype.getText = function () {
    if (this.getChildCount() === 0) {
        return "";
    } else {
        return this.children.map(function (child) {
            return child.getText();
        }).join("");
    }
};

RuleContext.prototype.getChild = function (i) {
    return null;
};

RuleContext.prototype.getChildCount = function () {
    return 0;
};

RuleContext.prototype.accept = function (visitor) {
    return visitor.visitChildren(this);
};

//need to manage circular dependencies, so export now
exports.RuleContext = RuleContext;
var Trees = require('./tree/Trees').Trees;


// Print out a whole tree, not just a node, in LISP format
// (root child1 .. childN). Print just a node if this is a leaf.
//

RuleContext.prototype.toStringTree = function (ruleNames, recog) {
    return Trees.toStringTree(this, ruleNames, recog);
};

RuleContext.prototype.toString = function (ruleNames, stop) {
    ruleNames = ruleNames || null;
    stop = stop || null;
    var p = this;
    var s = "[";
    while (p !== null && p !== stop) {
        if (ruleNames === null) {
            if (!p.isEmpty()) {
                s += p.invokingState;
            }
        } else {
            var ri = p.ruleIndex;
            var ruleName = (ri >= 0 && ri < ruleNames.length) ? ruleNames[ri]
                : "" + ri;
            s += ruleName;
        }
        if (p.parentCtx !== null && (ruleNames !== null || !p.parentCtx.isEmpty())) {
            s += " ";
        }
        p = p.parentCtx;
    }
    s += "]";
    return s;
};

