 //  Released under the Apache v2 License.
 //
 //  Adapted from https://gist.github.com/blakemerryman/76312e1cbf8aec248167
+//  Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3
+
 
 import Foundation
 
 
-let GlobBehaviorBashV3 = Glob.Behavior(
+public let GlobBehaviorBashV3 = Glob.Behavior(
   supportsGlobstar: false,
   includesFilesFromRootOfGlobstar: false,
   includesDirectoriesInResults: true,
   includesFilesInResultsIfTrailingSlash: false
 )
-let GlobBehaviorBashV4 = Glob.Behavior(
+public let GlobBehaviorBashV4 = Glob.Behavior(
   supportsGlobstar: true, // Matches Bash v4 with "shopt -s globstar" option
   includesFilesFromRootOfGlobstar: true,
   includesDirectoriesInResults: true,
   includesFilesInResultsIfTrailingSlash: false
 )
-let GlobBehaviorGradle = Glob.Behavior(
+public let GlobBehaviorGradle = Glob.Behavior(
   supportsGlobstar: true,
   includesFilesFromRootOfGlobstar: true,
   includesDirectoriesInResults: false,

        adjustedPattern += "*"
      }
    }
    
    let patterns = behavior.supportsGlobstar ? expandGlobstar(adjustedPattern) : [adjustedPattern]
    
    for pattern in patterns {
      var gt = glob_t()
      if executeGlob(pattern, gt: &gt) {
        populateFiles(gt, includeFiles: includeFiles)
      }
      
      globfree(&gt)
    }
    
    paths = Array(Set(paths)).sort { lhs, rhs in
      lhs.compare(rhs) != NSComparisonResult.OrderedDescending
    }
    
    clearCaches()
  }
  
  // MARK: Private
  
  private var globalFlags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK
  
  private func executeGlob(pattern: UnsafePointer<CChar>, gt: UnsafeMutablePointer<glob_t>) -> Bool {
    return 0 == glob(pattern, globalFlags, nil, gt)
  }
  
  private func expandGlobstar(pattern: String) -> [String] {
    guard pattern.containsString("**") else {
      return [pattern]
    }
    
    var results = [String]()
    var parts = pattern.componentsSeparatedByString("**")
    let firstPart = parts.removeFirst()
    var lastPart = parts.joinWithSeparator("**")
    
    let fileManager = NSFileManager.defaultManager()
    
    var directories: [String]
    
    do {
      directories = try fileManager.subpathsOfDirectoryAtPath(firstPart).flatMap { subpath in
        let fullPath = NSString(string: firstPart).stringByAppendingPathComponent(subpath)
        var isDirectory = ObjCBool(false)
        if fileManager.fileExistsAtPath(fullPath, isDirectory: &isDirectory) && isDirectory {
          return fullPath
        } else {
          return nil

/**
 Finds files on the file system using pattern matching.
 */
public class Glob: Collection {

  /**
   * Different glob implementations have different behaviors, so the behavior of this
   * implementation is customizable.
   */
  public struct Behavior {
    // If true then a globstar ("**") causes matching to be done recursively in subdirectories.
    // If false then "**" is treated the same as "*"
    let supportsGlobstar: Bool

    // If true the results from the directory where the globstar is declared will be included as well.
    // For example, with the pattern "dir/**/*.ext" the fie "dir/file.ext" would be included if this
    // property is true, and would be omitted if it's false.
    let includesFilesFromRootOfGlobstar: Bool

    // If false then the results will not include directory entries. This does not affect recursion depth.
    let includesDirectoriesInResults: Bool

    // If false and the last characters of the pattern are "**/" then only directories are returned in the results.
    let includesFilesInResultsIfTrailingSlash: Bool
  }

  static var defaultBehavior = GlobBehaviorBashV4

  private var isDirectoryCache = [String: Bool]()

  public let behavior: Behavior
  var paths = [String]()
  public var startIndex: Int { return paths.startIndex }
  public var endIndex: Int   { return paths.endIndex   }

  public init(pattern: String, behavior: Behavior = Glob.defaultBehavior) {

    self.behavior = behavior

    var adjustedPattern = pattern
    let hasTrailingGlobstarSlash = pattern.hasSuffix("**/")
    var includeFiles = !hasTrailingGlobstarSlash

    if behavior.includesFilesInResultsIfTrailingSlash {
      includeFiles = true
      if hasTrailingGlobstarSlash {
