#!/usr/bin/ruby -w

require 'strscan'

# io = DATA
io = ARGF

default_header = ENV['MM_SEARCH_SCOPE']
default_header = "#common" if default_header.nil?

input = io.gets.strip

# puts input

$first_value = ""
def convert (tokens, start_index, header, filter)
  return if start_index >= tokens.size

  count = 0
  conjunction = "and"
  i = start_index
  loop do
    token = tokens[i]
    if token == "("
      filter << " " + conjunction + " " if count > 0
      filter << "("
      i = convert(tokens, i+1, header, filter)
      filter << ")"
      count += 1
      conjunction = "and"
    elsif token == ")"
      return i
    elsif token[-1, 1] == ":"
      header = token[0..-2]
    elsif token == "f" # ToDo: Make it easier to specify multiple headers, e.g., "f s foo bar" (searches from/subject for 'foo' and 'bar').
      header = "from"
    elsif token == "s"
      header = "subject"
    elsif token == "t"
      header = "#recipient"
    elsif token == "a"
      header = "#any-address"
    # elsif token == "c" # This is slow for large accounts. Needs to be optimized (or dropped for use here).
    #   header = "#any-address.#correspondent"
    elsif token == "b"
      header = "#unquoted"
    elsif token == "q"
      header = "#quoted"
    elsif token == "m"
      header = "#common"
    elsif token == "A"
      header = "#filename"
    elsif token == "T"
      header = "##tags.tag.#name"
    elsif token == "K"
      header = "#flags.flag"
    elsif count > 0 and (token == "and" or token == "or")
      conjunction = token
    else
      negated = false
      if token[0] == '!'
        negated = true
        token = token[1..-1]
      end

      filter << " " + conjunction + " " if count > 0
      filter << header + " "
      filter << "!" if negated
      if header == "##tags.tag.#name" or header == "#flags.flag"
        filter << "="
      else
        filter << "~"
      end
      if header == "#common" or header == "#unquoted" or header == "#quoted" or header == "#filename"
        filter << "[a"
        filter << "x" if negated
        filter << "]"
      else
        filter << "[x]" if negated
      end
      filter << " " + "'" + token.gsub(/'/,'\'\'').gsub(/"/,'\\"') + "'"
      count += 1
      conjunction = "and"
      $first_value = token if $first_value.empty? and (header == "#common" or header == "#unquoted" or header == "#quoted" or header == "#filename")
    end

    i += 1
    break if tokens.size == i
  end
  return tokens.size
end

def tokenize (ss, tokens)
  loop do
    if ss.scan(/\(/) # Sub-conditions in parenthesis
      tokens << "("
      tokenize(ss, tokens)
      tokens << ")"
    elsif ss.scan(/\)/)
      break
    elsif word = ss.scan(/'([^']|'')*'/) # Single-quoted word. An inline quote is escaped using two single quotes
      word = word[1..-2]
      tokens << word.gsub(/''/,'\'')
    elsif word = ss.scan(/"([^"])*"/) # Double-quoted word. Doesn't allow inline (double)quotes
      tokens << word[1..-2]
    elsif word = ss.scan(/[^\s()\:]+:?/)
      tokens << word
    elsif ss.scan(/\s+/) # Skip whitespace
    else
      # Giving up...
      break
    end
  end
end

ss = StringScanner.new(input)
tokens = []
tokenize(ss, tokens)
filter = ""
convert(tokens, 0, default_header, filter)

print "{ actions = ( {"
print "type = search; "
print "filter = \"#{filter}\"; "
# print "title = \"#{title}\"; "
puts "} ); }"

`printf '#{$first_value}' | pbcopy -pboard find` if not $first_value.empty?

__END__
