/*
 * stringbuffer.js
 *
 * Created by Martin Carlberg.
 * Copyright 2013, Martin Carlberg.
 *
 * Additional work by Aparajita Fishman.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the MIT license (http://opensource.org/licenses/MIT).
 */

"use strict";

var indentation = require("./indentation"),
    sourceMap = require("source-map");


var StringBuffer = function(generateSourceMap, file)
{
    this.atoms = [];
    this.nodes = [];
    this.generateSourceMap = generateSourceMap;
    this.file = file;
    this.sourceMap = null;
    this.rootNode = generateSourceMap ? new sourceMap.SourceNode() : null;
};

Object.defineProperty(
    StringBuffer.prototype, "length", {
        get: function()
        {
            return this.atoms.length;
        }
    }
);

StringBuffer.prototype.toString = function()
{
    return this.atoms.join("");
};

StringBuffer.prototype.concat = function(string, node)
{
    this.atoms.push(string);

    if (this.generateSourceMap)
        this.nodes.push(node || null);
};

StringBuffer.prototype.remove = function(index)
{
    this.atoms[index] = "";

    // Mark the node undefined so it won't be used
    if (this.generateSourceMap)
        this.nodes[index] = undefined;
};

StringBuffer.prototype.getSourceMap = function()
{
    if (this.generateSourceMap && !this.sourceMap)
    {
        if (!this.rootNode)
            this.rootNode = new sourceMap.SourceNode();

        for (var i = 0; i < this.nodes.length; i++)
        {
            var string = this.atoms[i],
                node = this.nodes[i];

            if (node)
            {
                //console.log("Snippet: " + string + ", line: " + node.loc.start.line + ", column: " + node.loc.start.column + ", source: " + node.loc.source);
                this.rootNode.add(new sourceMap.SourceNode(node.loc.start.line, node.loc.start.column, node.loc.source, string));
            }
            else if (node === null)
                this.rootNode.add(string);
        }

        this.sourceMap = this.rootNode.toStringWithSourceMap({ file: this.file }).map;
    }

    return this.sourceMap;
};

StringBuffer.prototype.concatFormat = function(node, scope, key)
{
    if (!key)
        return;

    var format = scope.compiler.format,
        value = format.valueForProperty(scope, node.type, key);

    if (!value)
        return;

    var lines = value.split("\n"),
        lineIndent = indentation.indentation;

    for (var i = 0; i < lines.length; i++)
    {
        var line = lines[i];

        if (line.charAt(0) === "|")
        {
            var numberEnd = line.indexOf("|", 1);

            if (numberEnd === -1)
                numberEnd = line.length;

            var indentAmount = parseInt(line.substring(1, numberEnd), 10);

            if (indentAmount < 0)
                lineIndent = indentation.indentation.substring(indentation.indentSize * -indentAmount);
            else
                lineIndent = indentation.indentation + indentation.indentStep.repeat(indentAmount);

            lines[i] = lineIndent + line.substring(numberEnd);
        }
        else if (i > 0 && (line || i === lines.length - 1))
        {
            // Keep the current indentation
            lines[i] = indentation.indentation + line;
        }
    }

    indentation.indentation = lineIndent;
    this.concat(lines.join("\n"));
};

StringBuffer.prototype.concatWithFormat = function(node, scope, string, format, isAnchorNode)
{
    format = format || string;

    this.concatFormat(node, scope, "before-" + format);
    this.concat(string, isAnchorNode ? node : null);
    this.concatFormat(node, scope, "after-" + format);
};

StringBuffer.prototype.concatWithFormats = function(node, scope, before, string, after, isAnchorNode)
{
    if (before)
        this.concatFormat(node, scope, before);

    this.concat(string, isAnchorNode ? node : null);

    if (after)
        this.concatFormat(node, scope, after);
};

StringBuffer.prototype.concatLeftParens = function(node, scope)
{
    this.concatWithFormat(node, scope, "(", "left-parens");
};

StringBuffer.prototype.concatRightParens = function(node, scope)
{
    this.concatWithFormat(node, scope, ")", "right-parens");
};

StringBuffer.prototype.concatComma = function(node, scope)
{
    this.concatWithFormat(node, scope, ",", "comma");
};

StringBuffer.prototype.concatOperator = function(node, scope, operator)
{
    this.concatWithFormat(node, scope, operator || node.operator, "operator");
};

StringBuffer.prototype.concatParenthesizedBlock = function(node, scope, func)
{
    this.concatWithFormats(node, scope, "before-left-parens", "(", func ? "after-left-parens" : null);

    if (func)
        func();

    this.concatWithFormats(node, scope, func ? "before-left-parens" : null, ")", "after-left-parens");
};

StringBuffer.prototype.concatBuffer = function(buffer)
{
    this.atoms.push.apply(this.atoms, buffer.atoms);
    this.nodes.push.apply(this.nodes, buffer.nodes);
};

StringBuffer.prototype.isEmpty = function()
{
    return this.atoms.length === 0;
};

module.exports = StringBuffer;

@@ -855,32 +855,236 @@
  = function()%0A%7B%0A
+    // Trim whitespace at the beginning%0A    for (var i = 0; i %3C this.atoms.length; i++)%0A    %7B%0A        if (/%5Cs+/.test(this.atoms%5Bi%5D))%0A            this.atoms%5Bi%5D = %22%22;%0A        else%0A            break;%0A    %7D%0A%0A
     return this.

Trim whitespace at the beginning of the output.