// Generated by CoffeeScript 1.7.1
(function() {
  var asar, asarStatsToFsStats, cachedArchives, child_process, createNotFoundError, exists, existsSync, fakeTime, fs, getOrCreateArchive, gid, lstat, lstatSync, nextInode, open, openSync, overrideAPI, overrideAPISync, path, readFile, readFileSync, readdir, readdirSync, realpath, realpathSync, splitPath, stat, statSync, statSyncNoException, uid, util;

  asar = process.atomBinding('asar');

  child_process = require('child_process');

  fs = require('fs');

  path = require('path');

  util = require('util');

  cachedArchives = {};

  getOrCreateArchive = function(p) {
    var archive;
    archive = cachedArchives[p];
    if (archive != null) {
      return archive;
    }
    archive = asar.createArchive(p);
    if (!archive) {
      return false;
    }
    return cachedArchives[p] = archive;
  };

  process.on('exit', function() {
    var archive, p, _results;
    _results = [];
    for (p in cachedArchives) {
      archive = cachedArchives[p];
      _results.push(archive.destroy());
    }
    return _results;
  });

  splitPath = function(p) {
    var index;
    if (typeof p !== 'string') {
      return [false];
    }
    if (p.substr(-5) === '.asar') {
      return [true, p, ''];
    }
    index = p.lastIndexOf(".asar" + path.sep);
    if (index === -1) {
      return [false];
    }
    return [true, p.substr(0, index + 5), p.substr(index + 6)];
  };

  nextInode = 0;

  uid = process.getuid != null ? process.getuid() : 0;

  gid = process.getgid != null ? process.getgid() : 0;

  fakeTime = new Date();

  asarStatsToFsStats = function(stats) {
    return {
      dev: 1,
      ino: ++nextInode,
      mode: 33188,
      nlink: 1,
      uid: uid,
      gid: gid,
      rdev: 0,
      atime: stats.atime || fakeTime,
      birthtime: stats.birthtime || fakeTime,
      mtime: stats.mtime || fakeTime,
      ctime: stats.ctime || fakeTime,
      size: stats.size,
      isFile: function() {
        return stats.isFile;
      },
      isDirectory: function() {
        return stats.isDirectory;
      },
      isSymbolicLink: function() {
        return stats.isLink;
      },
      isBlockDevice: function() {
        return false;
      },
      isCharacterDevice: function() {
        return false;
      },
      isFIFO: function() {
        return false;
      },
      isSocket: function() {
        return false;
      }
    };
  };

  createNotFoundError = function(asarPath, filePath) {
    var error;
    error = new Error("ENOENT, " + filePath + " not found in " + asarPath);
    error.code = "ENOENT";
    error.errno = -2;
    return error;
  };

  lstatSync = fs.lstatSync;

  fs.lstatSync = function(p) {
    var archive, asarPath, filePath, isAsar, stats, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return lstatSync(p);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      throw new Error("Invalid package " + asarPath);
    }
    stats = archive.stat(filePath);
    if (!stats) {
      throw createNotFoundError(asarPath, filePath);
    }
    return asarStatsToFsStats(stats);
  };

  lstat = fs.lstat;

  fs.lstat = function(p, callback) {
    var archive, asarPath, filePath, isAsar, stats, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return lstat(p, callback);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return callback(new Error("Invalid package " + asarPath));
    }
    stats = getOrCreateArchive(asarPath).stat(filePath);
    if (!stats) {
      return callback(createNotFoundError(asarPath, filePath));
    }
    return process.nextTick(function() {
      return callback(null, asarStatsToFsStats(stats));
    });
  };

  statSync = fs.statSync;

  fs.statSync = function(p) {
    var asarPath, filePath, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return statSync(p);
    }
    return fs.lstatSync(p);
  };

  stat = fs.stat;

  fs.stat = function(p, callback) {
    var asarPath, filePath, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return stat(p, callback);
    }
    return process.nextTick(function() {
      return fs.lstat(p, callback);
    });
  };

  statSyncNoException = fs.statSyncNoException;

  fs.statSyncNoException = function(p) {
    var archive, asarPath, filePath, isAsar, stats, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return statSyncNoException(p);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return false;
    }
    stats = archive.stat(filePath);
    if (!stats) {
      return false;
    }
    return asarStatsToFsStats(stats);
  };

  realpathSync = fs.realpathSync;

  fs.realpathSync = function(p) {
    var archive, asarPath, filePath, isAsar, real, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return realpathSync.apply(this, arguments);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      throw new Error("Invalid package " + asarPath);
    }
    real = archive.realpath(filePath);
    if (real === false) {
      throw createNotFoundError(asarPath, filePath);
    }
    return path.join(realpathSync(asarPath), real);
  };

  realpath = fs.realpath;

  fs.realpath = function(p, cache, callback) {
    var archive, asarPath, filePath, isAsar, real, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return realpath.apply(this, arguments);
    }
    if (typeof cache === 'function') {
      callback = cache;
      cache = void 0;
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return callback(new Error("Invalid package " + asarPath));
    }
    real = archive.realpath(filePath);
    if (real === false) {
      return callback(createNotFoundError(asarPath, filePath));
    }
    return realpath(asarPath, function(err, p) {
      if (err) {
        return callback(err);
      }
      return callback(null, path.join(p, real));
    });
  };

  exists = fs.exists;

  fs.exists = function(p, callback) {
    var archive, asarPath, filePath, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return exists(p, callback);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return callback(new Error("Invalid package " + asarPath));
    }
    return process.nextTick(function() {
      return callback(archive.stat(filePath) !== false);
    });
  };

  existsSync = fs.existsSync;

  fs.existsSync = function(p) {
    var archive, asarPath, filePath, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return existsSync(p);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return false;
    }
    return archive.stat(filePath) !== false;
  };

  open = fs.open;

  readFile = fs.readFile;

  fs.readFile = function(p, options, callback) {
    var archive, asarPath, buffer, encoding, filePath, flag, info, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return readFile.apply(this, arguments);
    }
    if (typeof options === 'function') {
      callback = options;
      options = void 0;
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return callback(new Error("Invalid package " + asarPath));
    }
    info = archive.getFileInfo(filePath);
    if (!info) {
      return callback(createNotFoundError(asarPath, filePath));
    }
    if (!options) {
      options = {
        encoding: null,
        flag: 'r'
      };
    } else if (util.isString(options)) {
      options = {
        encoding: options,
        flag: 'r'
      };
    } else if (!util.isObject(options)) {
      throw new TypeError('Bad arguments');
    }
    flag = options.flag || 'r';
    encoding = options.encoding;
    buffer = new Buffer(info.size);
    return open(archive.path, flag, function(error, fd) {
      if (error) {
        return callback(error);
      }
      return fs.read(fd, buffer, 0, info.size, info.offset, function(error) {
        return fs.close(fd, function() {
          return callback(error, encoding ? buffer.toString(encoding) : buffer);
        });
      });
    });
  };

  openSync = fs.openSync;

  readFileSync = fs.readFileSync;

  fs.readFileSync = function(p, options) {
    var archive, asarPath, buffer, e, encoding, fd, filePath, flag, info, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return readFileSync.apply(this, arguments);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      throw new Error("Invalid package " + asarPath);
    }
    info = archive.getFileInfo(filePath);
    if (!info) {
      throw createNotFoundError(asarPath, filePath);
    }
    if (!options) {
      options = {
        encoding: null,
        flag: 'r'
      };
    } else if (util.isString(options)) {
      options = {
        encoding: options,
        flag: 'r'
      };
    } else if (!util.isObject(options)) {
      throw new TypeError('Bad arguments');
    }
    flag = options.flag || 'r';
    encoding = options.encoding;
    buffer = new Buffer(info.size);
    fd = openSync(archive.path, flag);
    try {
      fs.readSync(fd, buffer, 0, info.size, info.offset);
    } catch (_error) {
      e = _error;
      throw e;
    } finally {
      fs.closeSync(fd);
    }
    if (encoding) {
      return buffer.toString(encoding);
    } else {
      return buffer;
    }
  };

  readdir = fs.readdir;

  fs.readdir = function(p, callback) {
    var archive, asarPath, filePath, files, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return readdir.apply(this, arguments);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      return callback(new Error("Invalid package " + asarPath));
    }
    files = archive.readdir(filePath);
    if (!files) {
      return callback(createNotFoundError(asarPath, filePath));
    }
    return process.nextTick(function() {
      return callback(null, files);
    });
  };

  readdirSync = fs.readdirSync;

  fs.readdirSync = function(p) {
    var archive, asarPath, filePath, files, isAsar, _ref;
    _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
    if (!isAsar) {
      return readdirSync.apply(this, arguments);
    }
    archive = getOrCreateArchive(asarPath);
    if (!archive) {
      throw new Error("Invalid package " + asarPath);
    }
    files = archive.readdir(filePath);
    if (!files) {
      throw createNotFoundError(asarPath, filePath);
    }
    return files;
  };

  overrideAPISync = function(module, name, arg) {
    var old;
    if (arg == null) {
      arg = 0;
    }
    old = module[name];
    return module[name] = function() {
      var archive, asarPath, filePath, isAsar, newPath, p, _ref;
      p = arguments[arg];
      _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
      if (!isAsar) {
        return old.apply(this, arguments);
      }
      archive = getOrCreateArchive(asarPath);
      if (!archive) {
        throw new Error("Invalid package " + asarPath);
      }
      newPath = archive.copyFileOut(filePath);
      if (!newPath) {
        throw createNotFoundError(asarPath, filePath);
      }
      arguments[arg] = newPath;
      return old.apply(this, arguments);
    };
  };

  overrideAPI = function(module, name, arg) {
    var old;
    if (arg == null) {
      arg = 0;
    }
    old = module[name];
    return module[name] = function() {
      var archive, asarPath, callback, filePath, isAsar, newPath, p, _ref;
      p = arguments[arg];
      _ref = splitPath(p), isAsar = _ref[0], asarPath = _ref[1], filePath = _ref[2];
      if (!isAsar) {
        return old.apply(this, arguments);
      }
      callback = arguments[arguments.length - 1];
      if (typeof callback !== 'function') {
        return overrideAPISync(module, name, arg);
      }
      archive = getOrCreateArchive(asarPath);
      if (!archive) {
        return callback(new Error("Invalid package " + asarPath));
      }
      newPath = archive.copyFileOut(filePath);
      if (!newPath) {
        return callback(createNotFoundError(asarPath, filePath));
      }
      arguments[arg] = newPath;
      return old.apply(this, arguments);
    };
  };

  overrideAPI(fs, 'open');

  overrideAPI(child_process, 'execFile');

  overrideAPISync(process, 'dlopen', 1);

  overrideAPISync(require('module')._extensions, '.node', 1);

  overrideAPISync(fs, 'openSync');

  overrideAPISync(child_process, 'fork');

}).call(this);
