// Generated by CoffeeScript 1.6.3
(function() {
  var TaskGroup, balUtilFlow, balUtilPaths, eachr, extendr, extractOptsAndCallback, ignorefs, pathUtil, safefs, typeChecker,
    __slice = [].slice,
    __hasProp = {}.hasOwnProperty;

  pathUtil = require('path');

  eachr = require('eachr');

  typeChecker = require('typechecker');

  extendr = require('extendr');

  safefs = require('safefs');

  extractOptsAndCallback = require('extract-opts').extractOptsAndCallback;

  TaskGroup = require('taskgroup').TaskGroup;

  balUtilFlow = require('./flow');

  ignorefs = require('ignorefs');

  balUtilPaths = {
    resolveCaseSensitivePath: function(path, next) {
      var parentPath;
      parentPath = safefs.getParentPathSync(path) || '/';
      if (parentPath === '/') {
        return next(null, parentPath);
      }
      safefs.resolveCaseSensitivePath(parentPath, function(err, parentPath) {
        return safefs.readdir(parentPath, function(err, files) {
          var file, relativePathLowerCase, _i, _len;
          if (err) {
            return next(err);
          }
          relativePathLowerCase = relativePath.toLowerCase();
          for (_i = 0, _len = files.length; _i < _len; _i++) {
            file = files[_i];
            if (file.toLowerCase() === relativePathLowerCase) {
              return next(null, pathUtil.join(parentPath, relativePath));
            }
          }
          err = new Error("Could not find the path " + relativePath + " inside " + parentPath);
          return next(err);
        });
      });
      return safefs;
    },
    cp: function(src, dst, next) {
      safefs.readFile(src, 'binary', function(err, data) {
        if (err) {
          return next(err);
        }
        return safefs.writeFile(dst, data, 'binary', function(err) {
          return next(err);
        });
      });
      return this;
    },
    prefixPathSync: function(path, parentPath) {
      path = path.replace(/[\/\\]$/, '');
      if (/^([a-zA-Z]\:|\/)/.test(path) === false) {
        path = pathUtil.join(parentPath, path);
      }
      return path;
    },
    isDirectory: function(path, next) {
      if ((path != null ? path.isDirectory : void 0) != null) {
        return next(null, path.isDirectory(), path);
      } else {
        safefs.stat(path, function(err, stat) {
          if (err) {
            return next(err);
          }
          return next(null, stat.isDirectory(), stat);
        });
      }
      return this;
    },
    generateSlugSync: function(path) {
      var result;
      result = path.replace(/[^a-zA-Z0-9]/g, '-').replace(/^-/, '').replace(/-+/, '-');
      return result;
    },
    scanlist: function(path, next) {
      balUtilPaths.scandir({
        path: path,
        readFiles: true,
        ignoreHiddenFiles: true,
        next: function(err, list) {
          return next(err, list);
        }
      });
      return this;
    },
    scantree: function(path, next) {
      balUtilPaths.scandir({
        path: path,
        readFiles: true,
        ignoreHiddenFiles: true,
        next: function(err, list, tree) {
          return next(err, tree);
        }
      });
      return this;
    },
    scandir: function() {
      var args, err, list, next, opts, tree;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      list = {};
      tree = {};
      if (args.length === 1) {
        opts = args[0];
      } else if (args.length >= 4) {
        opts = {
          path: args[0],
          fileAction: args[1] || null,
          dirAction: args[2] || null,
          next: args[3] || null
        };
      } else {
        err = new Error('balUtilPaths.scandir: unsupported arguments');
        throw err;
      }
      if (opts.recurse == null) {
        opts.recurse = true;
      }
      if (opts.readFiles == null) {
        opts.readFiles = false;
      }
      if (opts.ignorePaths == null) {
        opts.ignorePaths = false;
      }
      if (opts.ignoreHiddenFiles == null) {
        opts.ignoreHiddenFiles = false;
      }
      if (opts.ignoreCommonPatterns == null) {
        opts.ignoreCommonPatterns = false;
      }
      if (opts.next == null) {
        opts.next = function(err) {
          if (err) {
            throw err;
          }
        };
      }
      next = opts.next;
      if (opts.action != null) {
        if (opts.fileAction == null) {
          opts.fileAction = opts.action;
        }
        if (opts.dirAction == null) {
          opts.dirAction = opts.action;
        }
      }
      if (opts.parentPath && !opts.path) {
        opts.path = opts.parentPath;
      }
      if (!opts.path) {
        err = new Error('balUtilPaths.scandir: path is needed');
        return next(err);
      }
      safefs.readdir(opts.path, function(err, files) {
        var tasks;
        if (err) {
          return next(err);
        }
        if (files.length === 0) {
          return next(null, list, tree);
        }
        tasks = new TaskGroup().setConfig({
          concurrency: 0
        }).once('complete', function(err) {
          return opts.next(err, list, tree);
        });
        files.forEach(function(file) {
          return tasks.addTask(function(complete) {
            var fileFullPath, fileRelativePath, isIgnoredFile;
            fileFullPath = pathUtil.join(opts.path, file);
            fileRelativePath = opts.relativePath ? pathUtil.join(opts.relativePath, file) : file;
            isIgnoredFile = ignorefs.isIgnoredPath(fileFullPath, {
              ignorePaths: opts.ignorePaths,
              ignoreHiddenFiles: opts.ignoreHiddenFiles,
              ignoreCommonPatterns: opts.ignoreCommonPatterns,
              ignoreCustomPatterns: opts.ignoreCustomPatterns
            });
            if (isIgnoredFile) {
              return complete();
            }
            return balUtilPaths.isDirectory(fileFullPath, function(err, isDirectory, fileStat) {
              var handle;
              if (err) {
                return complete(err);
              }
              if (tasks.paused) {
                return complete();
              }
              if (isDirectory) {
                handle = function(err, skip, subtreeCallback) {
                  if (err) {
                    return complete(err);
                  }
                  if (tasks.paused) {
                    return complete();
                  }
                  if (skip) {
                    return complete();
                  }
                  list[fileRelativePath] = 'dir';
                  tree[file] = {};
                  if (!opts.recurse) {
                    return complete();
                  }
                  return balUtilPaths.scandir({
                    path: fileFullPath,
                    relativePath: fileRelativePath,
                    fileAction: opts.fileAction,
                    dirAction: opts.dirAction,
                    readFiles: opts.readFiles,
                    ignorePaths: opts.ignorePaths,
                    ignoreHiddenFiles: opts.ignoreHiddenFiles,
                    ignoreCommonPatterns: opts.ignoreCommonPatterns,
                    ignoreCustomPatterns: opts.ignoreCustomPatterns,
                    recurse: opts.recurse,
                    stat: opts.fileStat,
                    next: function(err, _list, _tree) {
                      var filePath, fileType;
                      tree[file] = _tree;
                      for (filePath in _list) {
                        if (!__hasProp.call(_list, filePath)) continue;
                        fileType = _list[filePath];
                        list[filePath] = fileType;
                      }
                      if (err) {
                        return complete(err);
                      }
                      if (tasks.paused) {
                        return complete();
                      }
                      if (subtreeCallback) {
                        return subtreeCallback(complete);
                      }
                      return complete();
                    }
                  });
                };
                if (opts.dirAction) {
                  return opts.dirAction(fileFullPath, fileRelativePath, handle, fileStat);
                } else if (opts.dirAction === false) {
                  return handle(err, true);
                } else {
                  return handle(err, false);
                }
              } else {
                handle = function(err, skip) {
                  if (err) {
                    return complete(err);
                  }
                  if (tasks.paused) {
                    return complete();
                  }
                  if (skip) {
                    return complete();
                  }
                  if (opts.readFiles) {
                    return safefs.readFile(fileFullPath, function(err, data) {
                      if (err) {
                        return complete(err);
                      }
                      if (opts.readFiles !== 'binary') {
                        data = data.toString();
                      }
                      list[fileRelativePath] = data;
                      tree[file] = data;
                      return complete();
                    });
                  } else {
                    list[fileRelativePath] = 'file';
                    tree[file] = true;
                    return complete();
                  }
                };
                if (opts.fileAction) {
                  return opts.fileAction(fileFullPath, fileRelativePath, handle, fileStat);
                } else if (opts.fileAction === false) {
                  return handle(err, true);
                } else {
                  return handle(err, false);
                }
              }
            });
          });
        });
        return tasks.run();
      });
      return this;
    },
    cpdir: function() {
      var args, err, next, opt, opts, outPath, scandirOpts, srcPath, _i, _len, _ref;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      opts = {};
      if (args.length === 1) {
        opts = args[0];
      } else if (args.length >= 3) {
        srcPath = args[0], outPath = args[1], next = args[2];
        opts = {
          srcPath: srcPath,
          outPath: outPath,
          next: next
        };
      } else {
        err = new Error('balUtilPaths.cpdir: unknown arguments');
        if (next) {
          return next(err);
        } else {
          throw err;
        }
      }
      scandirOpts = {
        path: opts.srcPath,
        fileAction: function(fileSrcPath, fileRelativePath, next) {
          var fileOutPath;
          fileOutPath = pathUtil.join(opts.outPath, fileRelativePath);
          return safefs.ensurePath(pathUtil.dirname(fileOutPath), function(err) {
            if (err) {
              return next(err);
            }
            return balUtilPaths.cp(fileSrcPath, fileOutPath, function(err) {
              return next(err);
            });
          });
        },
        next: opts.next
      };
      _ref = ['ignorePaths', 'ignoreHiddenFiles', 'ignoreCommonPatterns', 'ignoreCustomPatterns'];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        opt = _ref[_i];
        scandirOpts[opt] = opts[opt];
      }
      balUtilPaths.scandir(scandirOpts);
      return this;
    },
    rpdir: function() {
      var args, err, next, opt, opts, outPath, scandirOpts, srcPath, _i, _len, _ref;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      opts = {};
      if (args.length === 1) {
        opts = args[0];
      } else if (args.length >= 3) {
        srcPath = args[0], outPath = args[1], next = args[2];
        opts = {
          srcPath: srcPath,
          outPath: outPath,
          next: next
        };
      } else {
        err = new Error('balUtilPaths.cpdir: unknown arguments');
        if (next) {
          return next(err);
        } else {
          throw err;
        }
      }
      scandirOpts = {
        path: opts.srcPath,
        fileAction: function(fileSrcPath, fileRelativePath, next) {
          var fileOutPath;
          fileOutPath = pathUtil.join(opts.outPath, fileRelativePath);
          return safefs.ensurePath(pathUtil.dirname(fileOutPath), function(err) {
            if (err) {
              return next(err);
            }
            return balUtilPaths.isPathOlderThan(fileOutPath, fileSrcPath, function(err, older) {
              if (older === true || older === null) {
                return balUtilPaths.cp(fileSrcPath, fileOutPath, function(err) {
                  return next(err);
                });
              } else {
                return next();
              }
            });
          });
        },
        next: opts.next
      };
      _ref = ['ignorePaths', 'ignoreHiddenFiles', 'ignoreCommonPatterns', 'ignoreCustomPatterns'];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        opt = _ref[_i];
        scandirOpts[opt] = opts[opt];
      }
      balUtilPaths.scandir(scandirOpts);
      return this;
    },
    rmdirDeep: function(parentPath, next) {
      safefs.exists(parentPath, function(exists) {
        if (!exists) {
          return next();
        }
        return balUtilPaths.scandir(parentPath, function(fileFullPath, fileRelativePath, next) {
          return safefs.unlink(fileFullPath, function(err) {
            return next(err);
          });
        }, function(fileFullPath, fileRelativePath, next) {
          return next(null, false, function(next) {
            return balUtilPaths.rmdirDeep(fileFullPath, function(err) {
              return next(err);
            });
          });
        }, function(err, list, tree) {
          if (err) {
            return next(err, list, tree);
          }
          return safefs.rmdir(parentPath, function(err) {
            return next(err, list, tree);
          });
        });
      });
      return this;
    },
    writetree: function(dstPath, tree, next) {
      safefs.ensurePath(dstPath, function(err) {
        var tasks;
        if (err) {
          return next(err);
        }
        tasks = new TaskGroup().setConfig({
          concurrency: 0
        }).once('complete', next);
        eachr(tree, function(value, fileRelativePath) {
          return tasks.addTask(function(complete) {
            var fileFullPath;
            fileFullPath = pathUtil.join(dstPath, fileRelativePath.replace(/^\/+/, ''));
            if (typeChecker.isObject(value)) {
              return balUtilPaths.writetree(fileFullPath, value, complete);
            } else {
              return safefs.writeFile(fileFullPath, value, complete);
            }
          });
        });
        return tasks.run();
      });
      return this;
    },
    readPath: function(filePath, opts, next) {
      var data, err, http, req, requestOpts, tasks, zlib, _base, _ref, _ref1;
      _ref = extractOptsAndCallback(opts, next), opts = _ref[0], next = _ref[1];
      if (/^http/.test(filePath)) {
        data = '';
        tasks = new TaskGroup().once('complete', function(err) {
          if (err) {
            return next(err);
          }
          return next(null, data);
        });
        requestOpts = require('url').parse(filePath);
        if (requestOpts.path == null) {
          requestOpts.path = requestOpts.pathname;
        }
        if (requestOpts.method == null) {
          requestOpts.method = 'GET';
        }
        if (requestOpts.headers == null) {
          requestOpts.headers = {};
        }
        if ((_base = requestOpts.headers)['user-agent'] == null) {
          _base['user-agent'] = 'Wget/1.14 (linux-gnu)';
        }
        http = requestOpts.protocol === 'https:' ? require('https') : require('http');
        zlib = null;
        try {
          zlib = require('zlib');
        } catch (_error) {
          err = _error;
        }
        req = http.request(requestOpts, function(res) {
          res.on('data', function(chunk) {
            return tasks.addTask(function(complete) {
              if (res.headers['content-encoding'] === 'gzip' && Buffer.isBuffer(chunk)) {
                if (zlib === null) {
                  err = new Error('Gzip encoding not supported on this environment');
                  return complete(err);
                }
                return zlib.unzip(chunk, function(err, chunk) {
                  if (err) {
                    return complete(err);
                  }
                  data += chunk;
                  return complete();
                });
              } else {
                data += chunk;
                return complete();
              }
            });
          });
          return res.on('end', function() {
            var locationHeader, _ref1;
            locationHeader = ((_ref1 = res.headers) != null ? _ref1.location : void 0) || null;
            if (locationHeader && locationHeader !== requestOpts.href) {
              return balUtilPaths.readPath(locationHeader, function(err, _data) {
                if (err) {
                  return tasks.exit(err);
                }
                data = _data;
                return tasks.exit();
              });
            } else {
              return tasks.run();
            }
          });
        });
        if (req.setTimeout == null) {
          req.setTimeout = function(delay) {
            return setTimeout(function() {
              req.abort();
              err = new Error('Request timed out');
              return tasks.exit(err);
            }, delay);
          };
        }
        req.setTimeout((_ref1 = opts.timeout) != null ? _ref1 : 10 * 1000);
        req.on('error', function(err) {
          return tasks.exit(err);
        }).on('timeout', function() {
          return req.abort();
        });
        req.end();
      } else {
        safefs.readFile(filePath, function(err, data) {
          if (err) {
            return next(err);
          }
          return next(null, data);
        });
      }
      return this;
    },
    empty: function(filePath, next) {
      safefs.exists(filePath, function(exists) {
        if (!exists) {
          return next(null, true);
        }
        return safefs.stat(filePath, function(err, stat) {
          if (err) {
            return next(err);
          }
          return next(null, stat.size === 0);
        });
      });
      return this;
    },
    isPathOlderThan: function(aPath, bInput, next) {
      var bMtime, bPath, mode;
      bMtime = null;
      if (typeChecker.isNumber(bInput)) {
        mode = 'time';
        bMtime = new Date(new Date() - bInput);
      } else {
        mode = 'path';
        bPath = bInput;
      }
      balUtilPaths.empty(aPath, function(err, empty) {
        if (empty || err) {
          return next(err, null);
        }
        return safefs.stat(aPath, function(err, aStat) {
          var compare;
          if (err) {
            return next(err);
          }
          compare = function() {
            var older;
            if (aStat.mtime < bMtime) {
              older = true;
            } else {
              older = false;
            }
            return next(null, older);
          };
          if (mode === 'path') {
            return balUtilPaths.empty(bPath, function(err, empty) {
              if (empty || err) {
                return next(err, null);
              }
              return safefs.stat(bPath, function(err, bStat) {
                if (err) {
                  return next(err);
                }
                bMtime = bStat.mtime;
                return compare();
              });
            });
          } else {
            return compare();
          }
        });
      });
      return this;
    }
  };

  module.exports = balUtilPaths;

}).call(this);
