# history/queue implementation on mpd via client manipulation :(
require 'mpd'

class HistQueue
  attr_accessor :hist_length
  attr_reader :mpd

  def initialize
    @mpd = MPD.new
    sleep 1
    @mpd.repeat "0"
    @mpd.random "0"

    @agents = []
    stat = @mpd.status
    @mpd.play if stat["song"]

    poll
  end

  def register agent
    @agents << agent
  end
  def notify func, *args
    @agents.each do |a|
      a.send func, *args if a.respond_to? func
    end
  end

  def current
    stat = @mpd.status
    case stat["state"]
      when "play"
        stat["song"].to_i
      else
        stat["playlistlength"].to_i - 1
    end
  end
  def current_song
    @mpd.playlistinfo[current]
  end
  def poll
    @pollthread = Thread.new do
      sleep 1 # avoid false song changes
      last_stat = @mpd.status
      while true
        sleep 1
        stat = @mpd.status
        if stat["songid"] != last_stat["songid"]
          puts "changed!"
          notify :song_change, stat, last_stat
        end
        last_stat = stat
      end
    end
  end
  def join
    @pollthread.join
  end

  def song_change stat, last
    skip = false
    if last["time"]
      times = last["time"].split(":").map {|t| t.to_i }
      skip = (times[1] - times[0]) > 1
    end
    jump = stat["song"].to_i + 1 < stat["playlistlength"].to_i

    notify :song_change, skip, jump
    notify :end_playlist if !skip and stat["state"] == "stop"
  end

  # enqueue and jump_to take filenames (mpddb relative)
  def enqueue song
    tmp = @mpd.add song

    while hist_length and current > hist_length
      puts "trimming playlist..."
      @mpd.delete 0
    end
    tmp
  end
  def dequeue song
    i = @mpd.playlistinfo.map{|s| s.file}.rindex song
    unless i.nil? or i <= current
      @mpd.delete i
    end
  end
  def jump_to song
    enqueue song
    cur = current + 1
    length = @mpd.status["playlistlength"].to_i
    if cur + 1 < length
      @mpd.move length - 1, cur
    end
    @mpd.play cur
  end
  def resume
    # start playing at the last song in the list
    # (hopefully someone added a song)

    case @mpd.status["state"]
      when "pause"
        @mpd.play
      when "stop"
        @mpd.play current
    end
  end

  def last_song?
    l = @mpd.status["playlistlength"].to_i
    current == l - 1
  end
end
