 {Point, Range, BufferedProcess} = require 'atom'
 
 LineEndingRegExp = /\n|\r\n/
+RegExpForOutPutLine = /^(.*?):(\d+):(\d+):(.*)$/
+
 unescapeRegExpForRg = (string) ->
   # Why I am unescaping for `rg` specifically?
   # History:

        args.push(unescapeRegExpForRg(@searchRegExp.source))
    args

  setRangeHintAndSort: (items) =>
    for item in items
      item.setRangeHint(@getRangeForItem)
    _.sortBy(items, (item) -> item.filePath)

  searchFilePath: (filePath) ->
    args = @getArgs()

    itemize = (data) =>
      items = []
      for line in data.split(LineEndingRegExp) when match = line.match(RegExpForOutPutLine)
        items.push(new Item(match))
      @setRangeHintAndSort(items)

    search({@command, args, filePath}).then(itemize)

  searchProjects: (projects) ->
    args = @getArgs()
    searchProject = (project) => search({@command, args, project})

    itemizeProjects = (allData) =>
      items = []
      for [project, data] in _.zip(projects, allData)
        for line in data.split(LineEndingRegExp) when match = line.match(RegExpForOutPutLine)
          items.push(new Item(match, project))
      @setRangeHintAndSort(items)

    searchPomises = projects.map(searchProject)
    Promise.all(searchPomises).then(itemizeProjects)

  getRangeForItem: (item) =>
    if @useRegex
      # FIXME: Maybe because of BUG of ag?
      # when I search \) in regexp, it find next line of line which ends with `)`.
      matchedText = item.text[item.point.column...].match(@searchRegExp)?[0] ? ''
      Range.fromPointWithDelta(item.point, 0, matchedText.length)
    else
      matchedText = @searchTerm
      Range.fromPointWithDelta(item.point, 0, matchedText.length)

searchFilePath = ->
  options =
    command: 'rg'
    useRegex: false
    searchRegExp: /onWillThrowError/g

  filePath = '/Users/t9md/github/atom-narrow/lib/provider/search.coffee'

  new Searcher(options).searchFilePath(filePath)

# searchProjects = ->
#   options =
#     command: 'rg'
#     useRegex: false
#     searchRegExp: /searchFilePath/g
#
#   projects = atom.project.getPaths()
#   new Searcher(options).searchProjects(projects)
#
# fn = searchFilePath
# # fn = searchProjects
# fn().then (items) ->
#   console.log items
#
# # searcher.searchFilePath(filePath).then (items) ->
# #   console.log items
# # searcher.searchProjects(projects).then (items) ->
# #   console.log items

  else
    ''

class Item
  constructor: (match, project, @getRangeForItem) ->
    @filePath = path.join(project, match[1])
    row = Math.max(0, parseInt(match[2]) - 1)
    column = Math.max(0, parseInt(match[3]) - 1)
    @text = match[4]
    @point = new Point(row, column)

  # this.range is populated on-need via @setRange which is externally set by provider.
  Object.defineProperty @prototype, 'range',
    get: ->
      @_range ?= @getRangeForItem(this)

runCommand = (options) ->
  new BufferedProcess(options).onWillThrowError ({error, handle}) ->
    if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0
      console.log "ERROR"
    handle()

search = ({command, args, project, filePath}) ->
  options =
    stdio: ['ignore', 'pipe', 'pipe']
    env: process.env
    cwd: project

  if filePath?
    args.push(filePath)

  allData = ""
  stdout = (data) -> allData += data

  stderrHeader = "[narrow:search stderr of #{command}]:"
  stderr = (data) -> console.warn(stderrHeader, data)
