define(['exports', 'module', '../utils'], function (exports, module, _utils) {
  /* global define, require */
  'use strict';

  var SourceNode = undefined;

  try {
    /* istanbul ignore next */
    if (typeof define !== 'function' || !define.amd) {
      // We don't support this in AMD environments. For these environments, we assume that
      // they are running on the browser and thus have no need for the source-map library.
      var SourceMap = require('source-map');
      SourceNode = SourceMap.SourceNode;
    }
  } catch (err) {}
  /* NOP */

  /* istanbul ignore if: tested but not covered in istanbul due to dist build  */
  if (!SourceNode) {
    SourceNode = function (line, column, srcFile, chunks) {
      this.src = '';
      if (chunks) {
        this.add(chunks);
      }
    };
    /* istanbul ignore next */
    SourceNode.prototype = {
      add: function add(chunks) {
        if (_utils.isArray(chunks)) {
          chunks = chunks.join('');
        }
        this.src += chunks;
      },
      prepend: function prepend(chunks) {
        if (_utils.isArray(chunks)) {
          chunks = chunks.join('');
        }
        this.src = chunks + this.src;
      },
      toStringWithSourceMap: function toStringWithSourceMap() {
        return { code: this.toString() };
      },
      toString: function toString() {
        return this.src;
      }
    };
  }

  function castChunk(chunk, codeGen, loc) {
    if (_utils.isArray(chunk)) {
      var ret = [];

      for (var i = 0, len = chunk.length; i < len; i++) {
        ret.push(codeGen.wrap(chunk[i], loc));
      }
      return ret;
    } else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
      // Handle primitives that the SourceNode will throw up on
      return chunk + '';
    }
    return chunk;
  }

  function CodeGen(srcFile) {
    this.srcFile = srcFile;
    this.source = [];
  }

  CodeGen.prototype = {
    isEmpty: function isEmpty() {
      return !this.source.length;
    },
    prepend: function prepend(source, loc) {
      this.source.unshift(this.wrap(source, loc));
    },
    push: function push(source, loc) {
      this.source.push(this.wrap(source, loc));
    },

    merge: function merge() {
      var source = this.empty();
      this.each(function (line) {
        source.add(['  ', line, '\n']);
      });
      return source;
    },

    each: function each(iter) {
      for (var i = 0, len = this.source.length; i < len; i++) {
        iter(this.source[i]);
      }
    },

    empty: function empty() {
      var loc = this.currentLocation || { start: {} };
      return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
    },
    wrap: function wrap(chunk) {
      var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1];

      if (chunk instanceof SourceNode) {
        return chunk;
      }

      chunk = castChunk(chunk, this, loc);

      return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
    },

    functionCall: function functionCall(fn, type, params) {
      params = this.generateList(params);
      return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']);
    },

    quotedString: function quotedString(str) {
      return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
      .replace(/\u2029/g, '\\u2029') + '"';
    },

    objectLiteral: function objectLiteral(obj) {
      // istanbul ignore next

      var _this = this;

      var pairs = [];

      Object.keys(obj).forEach(function (key) {
        var value = castChunk(obj[key], _this);
        if (value !== 'undefined') {
          pairs.push([_this.quotedString(key), ':', value]);
        }
      });

      var ret = this.generateList(pairs);
      ret.prepend('{');
      ret.add('}');
      return ret;
    },

    generateList: function generateList(entries) {
      var ret = this.empty();

      for (var i = 0, len = entries.length; i < len; i++) {
        if (i) {
          ret.add(',');
        }

        ret.add(castChunk(entries[i], this));
      }

      return ret;
    },

    generateArray: function generateArray(entries) {
      var ret = this.generateList(entries);
      ret.prepend('[');
      ret.add(']');

      return ret;
    }
  };

  module.exports = CodeGen;
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 11664 characters]
