/**
 * @fileoverview Rule to enforce a particular function style
 * @author Nicholas C. Zakas
 * @copyright 2013 Nicholas C. Zakas. All rights reserved.
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

    var style = context.options[0],
        allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true,
        enforceDeclarations = (style === "declaration"),
        stack = [];

    var nodesToCheck = {
        "Program": function() {
            stack = [];
        },

        "FunctionDeclaration": function(node) {
            stack.push(false);

            if (!enforceDeclarations && node.parent.type !== "ExportDefaultDeclaration") {
                context.report(node, "Expected a function expression.");
            }
        },
        "FunctionDeclaration:exit": function() {
            stack.pop();
        },

        "FunctionExpression": function(node) {
            stack.push(false);

            if (enforceDeclarations && node.parent.type === "VariableDeclarator") {
                context.report(node.parent, "Expected a function declaration.");
            }
        },
        "FunctionExpression:exit": function() {
            stack.pop();
        },

        "ThisExpression": function() {
            if (stack.length > 0) {
                stack[stack.length - 1] = true;
            }
        }
    };

    if (!allowArrowFunctions) {
        nodesToCheck.ArrowFunctionExpression = function() {
            stack.push(false);
        };

        nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
            var hasThisExpr = stack.pop();

            if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
                context.report(node.parent, "Expected a function declaration.");
            }
        };
    }

    return nodesToCheck;

};

module.exports.schema = [
    {
        "enum": ["declaration", "expression"]
    },
    {
        "type": "object",
        "properties": {
            "allowArrowFunctions": {
                "type": "boolean"
            }
        },
        "additionalProperties": false
    }
];
