#! /usr/bin/ruby

require 'mpd'
require 'ncurses'
require 'livesearch'
require 'logger'

include Ncurses


$host = MPD.new ARGV[0] || ENV['MPD_HOST']
fields = [:title, :album, :artist, :file]
$searcher = LiveSearch.new $host.listallinfo do |song,str|
  words = str.split
  fields.any? do |f|
    f = song.send f
    words.all? do |w|
      f[/#{w}/i] if f
    end
  end
end

def queue list
  list.each do |s|
    puts s.title if list.length <= 10
    $host.add s.file
  end
  puts "enqeued #{list.length}"
end
def jump list
  song = list.first
  $host.stop
  $host.add song.file
  target = $host.currentsong.pos + 1
  if target < $host.playlistlength - 1
    $host.move $host.playlistlength - 1, target
  end
  $host.play target
  puts "jumped to #{song.title}"
end
def cancel *args
  puts "Canceled!"
end

$actions = {
  ?\n => :queue,
  Ncurses::KEY_ENTER => :queue,
  Ncurses::KEY_END => :jump,
  27 => :cancel,
  ?q => :cancel
}

def print_results list, selected = nil
  cols = (list.length.to_f / (Ncurses.LINES - 2)).ceil
  cols = 1 if cols < 1
  cols = 5 if cols > 5
  w = Ncurses.COLS / cols
  i = 0
  cols.times do |c|
    (Ncurses.LINES-2).times do |l|
      i = (c * (Ncurses.LINES - 2)) + l
      break unless i < list.length
      song = list[i]
      if selected == i
        str = "> #{song.artist}::#{song.album}::#{song.title}"
      else
        str = "  #{song.title}"
      end
      Ncurses::mvaddstr(l+2, (c * w), str[0,w])
    end
  end
  str = "#{list.length} results"
  Ncurses::mvaddstr 1, Ncurses.COLS - str.length, str
end
def print_str str, str_index
  Ncurses::mvaddstr 0, 0, str
  Ncurses::mvaddstr 0, str.length - str_index, ''
end

def remote_loop
  str = ""
  str_index = 0 # spaces backwards into the string from the end
  results = []
  selected = nil

  while ch = Ncurses::getch
    if ch == Ncurses::KEY_RESIZE
      Ncurses::clear
      mvaddstr 0, 0, str
      print_results results
      Ncurses::refresh
    end
    puts "foooo"
    case ch
      when *$actions.keys # ESC, ctrl-alt-j
        break
      when Ncurses::KEY_DOWN
        selected ||= -1
        selected = selected + 1
      when Ncurses::KEY_UP
        if selected
          selected = selected - 1
          selected = nil if selected < 0
        end
      when Ncurses::KEY_NPAGE
        selected ||= 0
        selected = selected + Ncurses.LINES - 2
      when Ncurses::KEY_PPAGE
        if selected
          selected = selected - (Ncurses.LINES - 2)
          selected = nil if selected < 0
        end
      when Ncurses::KEY_LEFT
        str_index = [str_index + 1, str.length].min
      when Ncurses::KEY_RIGHT
        str_index = [str_index - 1, 0].max
      when Ncurses::KEY_BACKSPACE
        if str.length > 0
          if str_index > 0
            str = str[0,str.length - str_index - 1] + str[-str_index, str_index]
          else
            str = str[0,str.length - 1]
          end
          str_index = [str_index, str.length].min
          results = $searcher.search str
        end
      when (0..255)
        if str_index > 0
          str =
            str[0, str.length - str_index] +
            ch.chr +
            str[-str_index, str_index]
        else
          str = str + ch.chr
        end
        results = $searcher.search str
    end
    Ncurses::clear
    print_results results, selected
    print_str str, str_index
    Ncurses::refresh
  end
  [results, ch, selected]
end
begin
  Ncurses::initscr
  Ncurses::noecho
  Ncurses::cbreak
  Ncurses::keypad Ncurses::stdscr, TRUE

  Ncurses::mvaddstr Ncurses.LINES - 1, 0, "Ready..."
  results, ch, selected = remote_loop
ensure
  Ncurses::endwin
end

if selected and selected < results.length
  results = results[selected,1]
end
send $actions[ch], results if $actions[ch]
