/**
 * @fileoverview Disallows multiple blank lines.
 * implementation adapted from the no-trailing-spaces rule.
 * @author Greg Cochard
 */
"use strict";

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

module.exports = {
    meta: {
        docs: {
            description: "disallow multiple empty lines",
            category: "Stylistic Issues",
            recommended: false
        },

        schema: [
            {
                type: "object",
                properties: {
                    max: {
                        type: "integer",
                        minimum: 0
                    },
                    maxEOF: {
                        type: "integer",
                        minimum: 0
                    },
                    maxBOF: {
                        type: "integer",
                        minimum: 0
                    }
                },
                required: ["max"],
                additionalProperties: false
            }
        ]
    },

    create: function(context) {

        // Use options.max or 2 as default
        var max = 2,
            maxEOF,
            maxBOF;

        // store lines that appear empty but really aren't
        var notEmpty = [];

        if (context.options.length) {
            max = context.options[0].max;
            maxEOF = context.options[0].maxEOF;
            maxBOF = context.options[0].maxBOF;
        }

        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------

        return {

            TemplateLiteral: function(node) {
                var start = node.loc.start.line;
                var end = node.loc.end.line;

                while (start <= end) {
                    notEmpty.push(start);
                    start++;
                }
            },

            "Program:exit": function checkBlankLines(node) {
                var lines = context.getSourceLines(),
                    currentLocation = -1,
                    lastLocation,
                    blankCounter = 0,
                    location,
                    firstOfEndingBlankLines,
                    firstNonBlankLine = -1,
                    trimmedLines = [];

                lines.forEach(function(str, i) {
                    var trimmed = str.trim();

                    if ((firstNonBlankLine === -1) && (trimmed !== "")) {
                        firstNonBlankLine = i;
                    }

                    trimmedLines.push(trimmed);
                });

                // add the notEmpty lines in there with a placeholder
                notEmpty.forEach(function(x, i) {
                    trimmedLines[i] = x;
                });

                if (typeof maxEOF === "undefined") {

                    /*
                     * Swallow the final newline, as some editors add it
                     * automatically and we don't want it to cause an issue
                     */
                    if (trimmedLines[trimmedLines.length - 1] === "") {
                        trimmedLines = trimmedLines.slice(0, -1);
                    }

                    firstOfEndingBlankLines = trimmedLines.length;
                } else {

                    // save the number of the first of the last blank lines
                    firstOfEndingBlankLines = trimmedLines.length;
                    while (trimmedLines[firstOfEndingBlankLines - 1] === ""
                            && firstOfEndingBlankLines > 0) {
                        firstOfEndingBlankLines--;
                    }
                }

                // Aggregate and count blank lines
                if (firstNonBlankLine > maxBOF) {
                    context.report(node, 0,
                            "Too many blank lines at the beginning of file. Max of " + maxBOF + " allowed.");
                }

                lastLocation = currentLocation;
                currentLocation = trimmedLines.indexOf("", currentLocation + 1);
                while (currentLocation !== -1) {
                    lastLocation = currentLocation;
                    currentLocation = trimmedLines.indexOf("", currentLocation + 1);
                    if (lastLocation === currentLocation - 1) {
                        blankCounter++;
                    } else {
                        location = {
                            line: lastLocation + 1,
                            column: 1
                        };

                        if (lastLocation < firstOfEndingBlankLines) {

                            // within the file, not at the end
                            if (blankCounter >= max) {
                                context.report({
                                    node: node,
                                    loc: location,
                                    message: "More than " + max + " blank " + (max === 1 ? "line" : "lines") + " not allowed."
                                });
                            }
                        } else {

                            // inside the last blank lines
                            if (blankCounter > maxEOF) {
                                context.report({
                                    node: node,
                                    loc: location,
                                    message: "Too many blank lines at the end of file. Max of " + maxEOF + " allowed."
                                });
                            }
                        }

                        // Finally, reset the blank counter
                        blankCounter = 0;
                    }
                }
            }
        };

    }
};
