// Generated by CoffeeScript 1.6.3
(function() {
  var async, coffee, conditionals, copyFile, escodegen, esprima, estools, expander, fs, isHidden, jscoverageFormatting, path, tools, wrench, writeFile, _;

  fs = require('fs');

  path = require('path');

  _ = require('underscore');

  esprima = require('esprima');

  escodegen = require('escodegen');

  wrench = require('wrench');

  coffee = require('coffee-script');

  async = require('async');

  tools = require('./tools');

  estools = require('./estools');

  conditionals = require('./conditionals');

  expander = require('./expander');

  jscoverageFormatting = require('./jscoverage-formatting');

  isHidden = function(filename) {
    return filename[0] === '.';
  };

  copyFile = function(source, target, cb) {
    var cbCalled, done, rd, wr;
    cbCalled = false;
    done = function(err) {
      if (!cbCalled) {
        cb(err);
        return cbCalled = true;
      }
    };
    rd = fs.createReadStream(source);
    rd.on("error", done);
    wr = fs.createWriteStream(target);
    wr.on("error", done);
    wr.on("close", function(ex) {
      return done();
    });
    return rd.pipe(wr);
  };

  writeFile = (function() {
    var sourceMappings;
    sourceMappings = [
      function(x) {
        return x.replace(/&/g, '&amp;');
      }, function(x) {
        return x.replace(/</g, '&lt;');
      }, function(x) {
        return x.replace(/>/g, '&gt;');
      }, function(x) {
        return x.replace(/\\/g, '\\\\');
      }, function(x) {
        return x.replace(/"/g, '\\"');
      }, function(x) {
        return tools.strToNumericEntity(x);
      }, function(x) {
        return '"' + x + '"';
      }
    ];
    return function(originalCode, coveredCode, filename, trackedLines, coverageVar) {
      var originalSource, output;
      originalSource = originalCode.split(/\r?\n/g).map(function(line) {
        return sourceMappings.reduce((function(src, f) {
          return f(src);
        }), line);
      });
      if (_.last(originalSource) === '""') {
        originalSource = originalSource.slice(0, -1);
      }
      output = [];
      output.push("/* automatically generated by jscov - do not edit */");
      output.push("if (typeof " + coverageVar + " === 'undefined') " + coverageVar + " = {};");
      output.push("if (! " + coverageVar + "['" + filename + "']) {");
      output.push("  " + coverageVar + "['" + filename + "'] = [];");
      trackedLines.forEach(function(line) {
        return output.push("  " + coverageVar + "['" + filename + "'][" + line + "] = 0;");
      });
      output.push("}");
      output.push(coveredCode);
      output.push(("" + coverageVar + "['" + filename + "'].source = [") + originalSource.join(",") + "];");
      return output.join('\n');
    };
  })();

  exports.rewriteSource = function(code, filename) {
    var ast, coverageVar, injectList, outcode, trackedLines;
    injectList = {};
    coverageVar = '_$jscoverage';
    ast = esprima.parse(code, {
      loc: true
    });
    jscoverageFormatting.formatTree(ast);
    estools.addBeforeEveryStatement(ast, function(node) {
      injectList[node.loc.start.line] = 1;
      return estools.coverageNode(node, filename, coverageVar);
    });
    jscoverageFormatting.postFormatTree(ast);
    trackedLines = _.sortBy(Object.keys(injectList).map(function(x) {
      return parseInt(x, 10);
    }), _.identity);
    outcode = escodegen.generate(ast, {
      indent: "  "
    });
    return writeFile(code, outcode, filename, trackedLines, coverageVar);
  };

  exports.rewriteFile = function(sourceFileBase, sourceFile, targetDir, options) {
    var data, outfile, output;
    data = fs.readFileSync(path.join(sourceFileBase, sourceFile), 'utf8');
    if (options.conditionals) {
      data = conditionals.expand(data, {
        lang: (sourceFile.match(/\.coffee$/) ? 'coffee' : 'js')
      });
    }
    if (sourceFile.match(/\.coffee$/)) {
      data = coffee.compile(data);
    }
    if (options.expand) {
      data = expander.expand(data);
    }
    output = exports.rewriteSource(data, sourceFile);
    outfile = path.join(targetDir, sourceFile).replace(/\.coffee$/, '.js');
    wrench.mkdirSyncRecursive(path.dirname(outfile));
    return fs.writeFileSync(outfile, output, 'utf8');
  };

  exports.rewriteFolder = function(source, target, options, callback) {
    var errors, ex, files;
    errors = [];
    if (callback == null) {
      callback = options;
      options = {};
    }
    try {
      wrench.rmdirSyncRecursive(target, true);
      files = wrench.readdirSyncRecursive(source);
    } catch (_error) {
      ex = _error;
      callback(ex);
      return;
    }
    return async.forEach(files, function(file, callback) {
      var dirs;
      if (fs.lstatSync(path.join(source, file)).isDirectory()) {
        return callback();
      }
      dirs = path.dirname(file).split(path.sep);
      if (dirs[0] === '.') {
        dirs = dirs.slice(1);
      }
      if ((dirs.some(isHidden) || isHidden(path.basename(file))) && !options.hidden) {
        return callback();
      }
      if (file.match(/\.(coffee|js)$/)) {
        try {
          if (options.verbose) {
            console.log("Rewriting " + source + "/" + file + " to " + target + "...");
          }
          exports.rewriteFile(source, file, target, options);
        } catch (_error) {
          ex = _error;
          errors.push({
            file: file,
            ex: ex
          });
          callback();
          return;
        }
        return callback();
      } else {
        if (options.verbose) {
          console.log("Copying " + source + " to " + target + "...");
        }
        return copyFile(path.join(source, file), path.join(target, file), callback);
      }
    }, function(err) {
      var failures;
      if (err != null) {
        return callback(err);
      }
      if (errors.length > 0) {
        failures = _.sortBy(errors, function(x) {
          return x.file;
        }).map(function(x) {
          return x.file + ": " + (x.ex.message || 'UNKNOWN');
        }).join('\n');
        return callback(new Error(failures));
      } else {
        return callback();
      }
    });
  };

  exports.cover = function(start, dir, file) {
    return path.join(start, process.env.JSCOV || dir, file);
  };

}).call(this);
