var assert = require("assert");
var n = require("./types").namedTypes;
var builtIn = require("ast-types").builtInTypes;

function Path(node, parent) {
    assert.ok(this instanceof Path);
    n.Node.assert(node);
    if (parent) {
        assert.ok(parent instanceof Path);
    } else {
        parent = null;
    }

    Object.defineProperties(this, {
        node: { value: node },
        parent: { value: parent }
    });
}

var Pp = Path.prototype;

Pp.cons = function(child) {
    return new Path(child, this);
};

Pp.needsParens = function() {
    if (!this.parent)
        return false;

    var node = this.node;
    var parent = this.parent.node;

    if (n.UnaryExpression.check(node))
        return n.MemberExpression.check(parent)
            && parent.object === node;

    if (isBinary(node)) {
        if (n.CallExpression.check(parent) &&
            parent.callee === node)
            return true;

        if (n.UnaryExpression.check(parent))
            return true;

        if (n.MemberExpression.check(parent) &&
            parent.object === node)
            return true;
    }

    if (n.Literal.check(node) &&
        builtIn.number.check(node.value) &&
        n.MemberExpression.check(parent) &&
        parent.object === node)
        return true;

    if (n.AssignmentExpression.check(node) ||
        n.ConditionalExpression.check(node))
    {
        if (n.UnaryExpression.check(parent))
            return true;

        if (isBinary(parent))
            return true;

        if (n.CallExpression.check(parent) &&
            parent.callee === node)
            return true;

        if (n.ConditionalExpression.check(parent) &&
            parent.test === node)
            return true;

        if (n.MemberExpression.check(parent) &&
            parent.object === node)
            return true;
    }

    return false; // TODO
};

function isBinary(node) {
    return n.BinaryExpression.check(node)
        || n.LogicalExpression.check(node);
}

exports.Path = Path;

@@ -1083,32 +1083,316 @@
     return true;
+%0A%0A        if (isBinary(parent)) %7B%0A            var po = parent.operator;%0A            var pp = PRECEDENCE%5Bpo%5D;%0A            var no = node.operator;%0A            var np = PRECEDENCE%5Bno%5D;%0A            if (pp %3E np %7C%7C (pp == np && node === parent.right))%0A                return true;%0A        %7D
 %0A    %7D%0A%0A    if (
@@ -2264,16 +2264,308 @@
 de);%0A%7D%0A%0A
+var PRECEDENCE = %7B%7D;%0A%5B%5B%22%7C%7C%22%5D,%0A %5B%22&&%22%5D,%0A %5B%22%7C%22%5D,%0A %5B%22%5E%22%5D,%0A %5B%22&%22%5D,%0A %5B%22==%22, %22===%22, %22!=%22, %22!==%22%5D,%0A %5B%22%3C%22, %22%3E%22, %22%3C=%22, %22%3E=%22, %22in%22, %22instanceof%22%5D,%0A %5B%22%3E%3E%22, %22%3C%3C%22, %22%3E%3E%3E%22%5D,%0A %5B%22+%22, %22-%22%5D,%0A %5B%22*%22, %22/%22, %22%25%22%5D%0A%5D.forEach(function(tier, i) %7B%0A    tier.forEach(function(op) %7B%0A        PRECEDENCE%5Bop%5D = i;%0A    %7D);%0A%7D);%0A%0A
 exports.

Handle BinaryExpression operator precedence in needsParens.