export default function buildMatchFn(args) {
  return function(dirtyString, dirtyOptions) {
    var string = String(dirtyString)
    var options = dirtyOptions || {}
    var width = options.width

    var matchPattern =
      (width && args.matchPatterns[width]) ||
      args.matchPatterns[args.defaultMatchWidth]
    var matchResult = string.match(matchPattern)

    if (!matchResult) {
      return null
    }
    var matchedString = matchResult[0]

    var parsePatterns =
      (width && args.parsePatterns[width]) ||
      args.parsePatterns[args.defaultParseWidth]

    var value
    if (Object.prototype.toString.call(parsePatterns) === '[object Array]') {
      value = findIndex(parsePatterns, function(pattern) {
        return pattern.test(matchedString)
      })
    } else {
      value = findKey(parsePatterns, function(pattern) {
        return pattern.test(matchedString)
      })
    }

    value = args.valueCallback ? args.valueCallback(value) : value
    value = options.valueCallback ? options.valueCallback(value) : value

    return {
      value: value,
      rest: string.slice(matchedString.length)
    }
  }
}

function findKey(object, predicate) {
  for (var key in object) {
    if (object.hasOwnProperty(key) && predicate(object[key])) {
      return key
    }
  }
}

function findIndex(array, predicate) {
  for (var key = 0; key < array.length; key++) {
    if (predicate(array[key])) {
      return key
    }
  }
}
