(function() {
  var GitUtils, Minimatch, PathFilter, path;

  Minimatch = require('minimatch').Minimatch;

  GitUtils = require('git-utils');

  path = require('path');

  module.exports = PathFilter = (function() {
    PathFilter.MINIMATCH_OPTIONS = {
      matchBase: true,
      dot: true
    };

    PathFilter.escapeRegExp = function(str) {
      return str.replace(/([\/'*+?|()\[\]{}.\^$])/g, '\\$1');
    };

    function PathFilter(rootPath, _arg) {
      var excludeVcsIgnores, exclusions, includeHidden, inclusions, _ref;
      _ref = _arg != null ? _arg : {}, inclusions = _ref.inclusions, exclusions = _ref.exclusions, includeHidden = _ref.includeHidden, excludeVcsIgnores = _ref.excludeVcsIgnores;
      this.inclusions = this.createMatchers(inclusions, true);
      this.exclusions = this.createMatchers(exclusions, false);
      if (excludeVcsIgnores) {
        this.repo = GitUtils.open(rootPath);
      }
      if (includeHidden !== true) {
        this.excludeHidden();
      }
    }

    /*
    Section: Testing For Acceptance
    */


    PathFilter.prototype.isFileAccepted = function(filepath) {
      return this.isPathAccepted('directory', filepath) && this.isPathAccepted('file', filepath);
    };

    PathFilter.prototype.isDirectoryAccepted = function(filepath) {
      return this.isPathAccepted('directory', filepath);
    };

    PathFilter.prototype.isPathAccepted = function(fileOrDirectory, filepath) {
      if (this.inclusions[fileOrDirectory].length && this.isPathIncluded(fileOrDirectory, filepath)) {
        return true;
      }
      return !this.isPathIgnored(fileOrDirectory, filepath) && this.isPathIncluded(fileOrDirectory, filepath);
    };

    /*
    Section: Private Methods
    */


    PathFilter.prototype.isPathIgnored = function(fileOrDirectory, filepath) {
      var exclusions, r, _ref;
      if ((_ref = this.repo) != null ? _ref.isIgnored(this.repo.relativize(filepath)) : void 0) {
        return true;
      }
      exclusions = this.exclusions[fileOrDirectory];
      r = exclusions.length;
      while (r--) {
        if (exclusions[r].match(filepath)) {
          return true;
        }
      }
      return false;
    };

    PathFilter.prototype.isPathIncluded = function(fileOrDirectory, filepath) {
      var inclusions, r;
      inclusions = this.inclusions[fileOrDirectory];
      r = inclusions.length;
      if (!r) {
        return true;
      }
      while (r--) {
        if (inclusions[r].match(filepath)) {
          return true;
        }
      }
      return false;
    };

    PathFilter.prototype.excludeHidden = function() {
      var matcher;
      matcher = new Minimatch(".*", PathFilter.MINIMATCH_OPTIONS);
      this.exclusions.file.push(matcher);
      return this.exclusions.directory.push(matcher);
    };

    PathFilter.prototype.createMatchers = function(patterns, deepMatch) {
      var addDirectoryMatcher, addFileMatcher, endsWithSeparatorOrStar, matchers, pattern, r;
      if (patterns == null) {
        patterns = [];
      }
      addFileMatcher = function(matchers, pattern) {
        return matchers.file.push(new Minimatch(pattern, PathFilter.MINIMATCH_OPTIONS));
      };
      addDirectoryMatcher = function(matchers, pattern, deepMatch) {
        var deepPath, directoryPattern, i, lastIndex, matchIndex, paths, _i, _ref;
        if (pattern[pattern.length - 1] === path.sep) {
          pattern += '**';
        }
        if (deepMatch) {
          paths = pattern.split(path.sep);
          lastIndex = paths.length - 2;
          if ((_ref = paths[paths.length - 1]) === '*' || _ref === '**') {
            lastIndex--;
          }
          if (lastIndex >= 0) {
            deepPath = '';
            for (i = _i = 0; 0 <= lastIndex ? _i <= lastIndex : _i >= lastIndex; i = 0 <= lastIndex ? ++_i : --_i) {
              deepPath = path.join(deepPath, paths[i]);
              addDirectoryMatcher(matchers, deepPath);
            }
          }
        }
        directoryPattern = RegExp("" + ('\\' + path.sep) + "\\*$|" + ('\\' + path.sep) + "\\*\\*$");
        matchIndex = pattern.search(directoryPattern);
        if (matchIndex > -1) {
          addDirectoryMatcher(matchers, pattern.slice(0, matchIndex));
        }
        return matchers.directory.push(new Minimatch(pattern, PathFilter.MINIMATCH_OPTIONS));
      };
      pattern = null;
      matchers = {
        file: [],
        directory: []
      };
      r = patterns.length;
      while (r--) {
        pattern = patterns[r].trim();
        if (pattern.length === 0 || pattern[0] === '#') {
          continue;
        }
        endsWithSeparatorOrStar = RegExp("" + ('\\' + path.sep) + "$|" + ('\\' + path.sep) + "\\**$");
        if (endsWithSeparatorOrStar.test(pattern)) {
          addDirectoryMatcher(matchers, pattern, deepMatch);
        } else if (pattern.indexOf('.') < 1 && pattern.indexOf('*') < 0) {
          addDirectoryMatcher(matchers, pattern + path.sep + '**', deepMatch);
        } else {
          addFileMatcher(matchers, pattern);
        }
      }
      return matchers;
    };

    return PathFilter;

  })();

}).call(this);
