(function() {
  var CoffeeScript, cacheDirectory, compileCoffeeScript, convertFilePath, crypto, fs, getCachePath, getCachedJavaScript, loadCoffeeScript, path, requireCoffeeScript, stats;

  crypto = require('crypto');

  path = require('path');

  CoffeeScript = null;

  fs = require('fs-plus');

  stats = {
    hits: 0,
    misses: 0
  };

  cacheDirectory = null;

  getCachePath = function(coffee) {
    var digest;
    digest = crypto.createHash('sha1').update(coffee, 'utf8').digest('hex');
    return path.join(cacheDirectory, "" + digest + ".js");
  };

  getCachedJavaScript = function(cachePath) {
    var cachedJavaScript;
    if (fs.isFileSync(cachePath)) {
      try {
        cachedJavaScript = fs.readFileSync(cachePath, 'utf8');
        stats.hits++;
        return cachedJavaScript;
      } catch (_error) {}
    }
  };

  convertFilePath = function(filePath) {
    if (process.platform === 'win32') {
      filePath = "/" + (path.resolve(filePath).replace(/\\/g, '/'));
    }
    return encodeURI(filePath);
  };

  loadCoffeeScript = function() {
    var coffee, coffeePrepareStackTrace;
    coffee = require('coffee-script');
    coffeePrepareStackTrace = Error.prepareStackTrace;
    if (coffeePrepareStackTrace != null) {
      Error.prepareStackTrace = function(error, stack) {
        var coffeeError;
        try {
          return coffeePrepareStackTrace(error, stack);
        } catch (_error) {
          coffeeError = _error;
          return stack;
        }
      };
    }
    return coffee;
  };

  compileCoffeeScript = function(coffee, filePath, cachePath) {
    var js, v3SourceMap, _ref;
    if (CoffeeScript == null) {
      CoffeeScript = loadCoffeeScript();
    }
    _ref = CoffeeScript.compile(coffee, {
      filename: filePath,
      sourceMap: true
    }), js = _ref.js, v3SourceMap = _ref.v3SourceMap;
    stats.misses++;
    if ((typeof btoa !== "undefined" && btoa !== null) && (typeof unescape !== "undefined" && unescape !== null) && (typeof encodeURIComponent !== "undefined" && encodeURIComponent !== null)) {
      js = "" + js + "\n//# sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//# sourceURL=" + (convertFilePath(filePath));
    }
    try {
      fs.writeFileSync(cachePath, js);
    } catch (_error) {}
    return js;
  };

  requireCoffeeScript = function(module, filePath) {
    var cachePath, coffee, js, _ref;
    coffee = fs.readFileSync(filePath, 'utf8');
    cachePath = getCachePath(coffee);
    js = (_ref = getCachedJavaScript(cachePath)) != null ? _ref : compileCoffeeScript(coffee, filePath, cachePath);
    return module._compile(js, filePath);
  };

  exports.register = function() {
    var propertyConfig;
    propertyConfig = {
      enumerable: true,
      value: requireCoffeeScript,
      writable: false
    };
    Object.defineProperty(require.extensions, '.coffee', propertyConfig);
    Object.defineProperty(require.extensions, '.litcoffee', propertyConfig);
    Object.defineProperty(require.extensions, '.coffee.md', propertyConfig);
  };

  exports.getCacheMisses = function() {
    return stats.misses;
  };

  exports.getCacheHits = function() {
    return stats.hits;
  };

  exports.resetCacheStats = function() {
    return stats = {
      hits: 0,
      misses: 0
    };
  };

  exports.setCacheDirectory = function(newCacheDirectory) {
    return cacheDirectory = newCacheDirectory;
  };

  exports.getCacheDirectory = function() {
    return cacheDirectory;
  };

  exports.addPathToCache = function(filePath) {
    var cachePath, coffee;
    coffee = fs.readFileSync(filePath, 'utf8');
    cachePath = getCachePath(coffee);
    compileCoffeeScript(coffee, filePath, cachePath);
  };

}).call(this);
