# lastfmradio: ZOMG last.fm radio functions
#   Copyright (C) 2005-2013  Clint Adams

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

typeset -A radio_host
radio_host[lastfm]=ws.audioscrobbler.com
radio_host[librefm]=alpha.libre.fm

lastfm_quit() {
  if [[ -z "$BUFFER" ]]; then
    BUFFER="q"
    zle .accept-line
  fi
}

lastfm_tune() {
  local network="$1" lastfm_session="$2" station="$3"
  local tunestatus

  status_msg "Tuning to $station... "

  tunestatus=$(wget -q --output-document=- "http://${baseurl}${basepath}/adjust.php?session=${lastfm_session}&url=${station}&debug=0")

  for i in "${(f)tunestatus}"
  do
    status_msg "$i"
  done
}

lastfm_radio_getplaylist() {
  local network="$1" session="$2"
  local i

  wget -q -O $zomgdatadir/radio_playlist.xspf "http://${radio_host[$network]}/radio/xspf.php?sk=${session}&discovery=0&desktop=1.3.0.58" || return 99
  zomghelper-xspf $zomgdatadir/radio_playlist.xspf > $zomgdatadir/radio_playlist || return 98

  unset zomg_xspf_location zomg_xspf_title zomg_xspf_id zomg_xspf_album
  unset zomg_xspf_creator zomg_xspf_duration zomg_xspf_image

  for i in ${(f)"$(<$zomgdatadir/radio_playlist)"}
  do
    case "$i" in
      ((#b)([^=]##)\[([0-9]##)\]=(*))
      eval zomg_xspf_$match[1]\[$match[2]\]="${(q)match[3]}"
      ;;
      ((#b)([^=]##)=(*))
      eval zomg_xspf_$match[1]="${(q)match[2]}"
      ;;
      (*)
      ;;
    esac
  done

  if [[ -z $zomg_xspf_location ]]; then
    status_msg "Empty playlist, quitting."
    return 99
  fi

  (( wehavecurses == 1 )) && scrollclear mw
  current_msg "$zomg_xspf_playlist_title by $zomg_xspf_playlist_creator"
  (( wehavecurses == 1 )) && scrollclear tw
  for i in {1..${#zomg_xspf_location}}
  do
    play_msg "$i. $zomg_xspf_creator[$i] / $zomg_xspf_title[$i]"
  done
}

lastfm_playchunk() {
  local network="$1" lastfm_session="$2"
  local trackkey

  lastfm_radio_getplaylist "$network" "$lastfm_session" || return 99

  for currenttrack in {1..${#zomg_xspf_location}}
  do

    for site in $submission_sites
    do

    audioscrobbler_construct_np_query "$username[$site]" "$sessionid[$site]" \
     "$zomg_xspf_creator[$currenttrack]" "$zomg_xspf_title[$currenttrack]" \
     "$zomg_xspf_album[$currenttrack]" "" \
     ${${zomg_xspf_duration[$currenttrack]}/000(#e)/} "$EPOCHSECONDS" && \
      audioscrobbler_np_submit "$site" ${(j::)reply} "$username[$site]"

    done

  time_status_msg "Now playing $zomg_xspf_creator[$currenttrack] / $zomg_xspf_title[$currenttrack] / $zomg_xspf_album[$currenttrack] / $(( $zomg_xspf_duration[$currenttrack] / 1000.0 ))"

  starttime=$EPOCHSECONDS
#  "$mp3streamer[@]" $zomg_xspf_location[$currenttrack] >/dev/null 2>&1 &
case "$network" in
  (librefm)
  ogg123 -b 2048 $zomg_xspf_location[$currenttrack] 2>/dev/null
  ;;
  (*)
  "$mp3streamer[@]" $zomg_xspf_location[$currenttrack] 2>/dev/null
esac
  endtime=$EPOCHSECONDS

  skip=0
      (( endtime - starttime <= (${${zomg_xspf_duration[$currenttrack]}/000(#e)/} / 2.0 ) )) &&
      (( endtime - starttime < 240 )) && skip=1

      (( ${${zomg_xspf_duration[$currenttrack]}/000(#e)/} < 30 )) && skip=1

      if [[ $skip -eq 1 ]];
      then
	status_msg "SKIPPING"
	skip=0
      else

      for site in $submission_sites
      do

	if [[ $site == $network ]]; then
		trackkey=L"$zomg_xspf_lastfm_trackauth[$currenttrack]"
	else
		trackkey=P
	fi

        audioscrobbler_constructquery "$sessionid[$site]" \
          "$zomg_xspf_creator[$currenttrack]" "$zomg_xspf_title[$currenttrack]" \
          "$zomg_xspf_album[$currenttrack]" "" \
          "${${zomg_xspf_duration[$currenttrack]}/000(#e)/}" "$starttime" \
          "$trackkey" &&
	    audioscrobbler_submit "$site" ${(j::)reply} "$username[$site]" || { submit[$site]=0; audioscrobbler_cache "$site" "$reply[2]" }
      done

      fi

  if (( wehavecurses == 1 )); then
  zcurses timeout bw 0
  if zcurses input bw; then
    case "$REPLY" in
    (" ")
      zcurses timeout bw -1
      pause=""
      while [[ $pause != [gqm] ]]; do
        status_msg "Paused. Press 'g' to resume playlist or 'q' to quit or 'm' to get a menu."
        zcurses input bw pause
      done
	case "$pause" in
	(q) zcurses end ; exit 0 ;;
	(m) return 1 ;;
	esac
      status_msg "Unpausing..."
      ;;
    (*)
      status_msg "I don't know what '$REPLY' means in this context."
    ;;
    esac
  fi

  fi

  done
  return 0
}

lastfm_playloop() {
  while lastfm_playchunk "$@"
  do
    status_msg "Fetching new playlist data."
  done
}

lastfm_radio() {
  local station="$1"
  local network=${${station%://*}:-lastfm}
  local passwordmd5=${${="$(print -n $password[$network] | md5sum)"}[1]}
  local -a handshake
  local lastfm_session streamurl radiocmd streamstate
  local baseurl basepath

  (( $#commands[zomghelper-xspf] )) || { print "zomghelper-xspf utility missing; we cannot play radio\n" ; exit 1; }
  [[ ! -o interactive ]] && zmodload zsh/curses && zomgcurses_init || wehavecurses=0

  if (( wehavecurses == 1 )); then
    trap "zcurses end" EXIT || exec $SHELL -i $zomg_scriptname -r $station
  else
    [[ -o interactive ]] || exec $SHELL -i $zomg_scriptname -r $station
  fi

  # we do this when we're not interactive so that the player will skip but
  # zomg will not end
  trap "status_msg 'Skip song... to get a menu, hit space and wait for a track to finish.'" INT

  status_msg "Connecting to Last.fm radio"
  log_msg "Radio handshake to http://${radio_host[$network]}/radio/handshake.php\?version=1.3.0.58\&platform=linux\&username=${username[$network]}\&passwordmd5=${passwordmd5}\&language=en"

  handshake=( ${(f)"$(wget -q --output-document=- http://${radio_host[$network]}/radio/handshake.php\?version=1.3.0.58\&platform=linux\&username=${username[$network]}\&passwordmd5=${passwordmd5}\&language=en)"} )

  lastfm_session=${${(M)handshake:#session=*}#session=}
  streamurl=${${(M)handshake:#stream_url=*}#stream_url=}
  baseurl=${${${(M)handshake:#base_url=*}#base_url=}:-ws.audioscrobbler.com}
  basepath=${${${(M)handshake:#base_path=*}#base_path=}:-/radio}

  if [[ -n "$lastfm_session" && "$lastfm_session" != FAILED ]]; then
    status_msg "Connecting to Last.fm session ${lastfm_session}"
    log_msg "Stream URL $streamurl"
  else
    status_msg "Handshake failed"
    sleep 2
    exit 47

  fi

  if [[ -n "$station" && "$station" == lastfm://* ]]; then
    lastfm_tune "$network" $lastfm_session $station
  fi

  if [[ -n "$station" && "$station" == librefm://* ]]; then
    if [[ $network == lastfm ]]; then
      status_msg "Can't do that right now."
    else
      lastfm_tune "$network" $lastfm_session $station
    fi
  fi

  if [[ -x =mpg123 ]]; then
    mp3streamer=(mpg123 -b 2048 -q)
  else
    mp3streamer=(mplayer -quiet -noconsolecontrols -cache 2048 -cache-min 1)
  fi

  lastfm_playloop "$network" "$lastfm_session"

  status_msg "Either type a menu command or hit 'h' to get some help."

  if (( wehavecurses == 1 )); then

  while true
  do

  zcurses timeout bw -1
  zcurses input bw

  case "$REPLY" in
    (f)
      status_msg "Rehandshaking..."
      if as_validate_handshake "$network" $username[$network] $password[$network]; then
        parse_submiturl "$network"
	parse_np_submiturl "$network"
	if [[ -s $zomgdatadir/cache ]]; then
	  status_msg "Flushing cache for lastfm..."
	  audioscrobbler_flushcache "$network" $username[$network] $sessionid[$network] &&
	  { submit[$network]=1; mv $zomgdatadir/cache $zomgdatadir/cache.old ; status_msg "Flushed" } ||
	  { submit[$network]=0; status_msg "Failed"; as_invalidate_handshake "$network" $username[$network] }
	else
	  status_msg "Cache is empty: nothing to flush."
	fi
      else
        status_msg "Fail"
      fi
      ;;
    (h)
      status_msg 'f: flush the cache and attempt to resume "realtime" submission'
      status_msg 'h: this help message'
      status_msg 'p: play another playlist set (usually up to 5 songs)'
      status_msg 'q: quit zomg'
      status_msg '<Ctrl-L>: attempt to refresh the screen (results may be unexpected)'
      status_msg 't: tune to another radio station'
      ;;
    (p)
      status_msg "Playing another playlist set."
      lastfm_playloop "$network" "${lastfm_session}"
      status_msg "Type 'p' to play a few more songs or 'q' to quit."
      ;;
    (q)
      zcurses end
      exit 0
      ;;
    ($'\014')
      status_msg "Refreshing screen."
      zcurses touch tw
      zcurses refresh tw
      zcurses touch mw
      zcurses refresh mw
      zcurses touch bw
      zcurses refresh bw
      zcurses refresh
      ;;
    (t)
      status_msg "r - recommended"
      status_msg "u - personal station"
      status_msg "l - loved tracks"
      status_msg "n - neighbouuuuurs"
      status_msg "any other key to abort"

      zcurses timeout bw -1
      zcurses input bw tune

      case "$tune" in
        (r) lastfm_tune "$network" ${lastfm_session} lastfm://user/${username[$network]}/recommended/100 ;;
        (u) lastfm_tune "$network" ${lastfm_session} lastfm://user/${username[$network]}/personal ;;
        (l) lastfm_tune "$network" ${lastfm_session} lastfm://user/${username[$network]}/loved ;;
        (n) lastfm_tune "$network" ${lastfm_session} lastfm://user/${username[$network]}/neighbours ;;
	(*) : ;;
      esac
      status_msg "Type 'p' to play a few more songs or 'q' to quit."
      ;;
    (*)
      status_msg "I don't know what '$REPLY' is."
      status_msg "Press h for help."
      ;;
  esac

  done
  
  else

  unset HISTFILE
  HISTSIZE=512
  SAVEHIST=512
  setopt histignorealldups
  history -ap $zomgdatadir/lastfm_history

  zle -N lastfm_quit
  bindkey '^D' lastfm_quit
  autoload -U compinit
  compinit
  bindkey '^I' _history-complete-older

  while true
  do
    [[ $#jobstates -eq 1 ]] && streamstate="" || streamstate="[broken] "

    radiocmd=""
    vared -hp "${streamstate}last.fm $username[$network] $timeleft> " radiocmd
    print -s $radiocmd

    case "$radiocmd" in
      (h)
      print "h: help"
#      print "n: show what's playing now"
      print "q: quit"
#      print "s: skip"
      print "p: play another set of songs from the same station"
      print "t lastfm://<station> : tune to another radio station"
      print "tu <lastfm user> : shortcut to tune to lastfm://user/<user>/personal"
      print "tl <lastfm user> : shortcut to tune to lastfm://user/<user>/loved"
      print "tn <lastfm user> : shortcut to tune to lastfm://user/<user>/neighbours"
#      print "love: mark this track as loved"
#      print "ban: ban this track"
#      print "discovery <on/off>: turn discovery mode on or off"
#      print "rtp: turn scrobbling on"
#      print "nortp: turn scrobbling off"
      ;;
#      (n)
#      lastfm_get_np "${lastfm_session}" 0
#      ;;
#      (ndebug)
#      lastfm_get_np "${lastfm_session}" 1
#      ;;
      (q|exit)
      kill %2
      exit 0
      ;;
#      (s)
#      print "Skipping... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=skip&debug=0")
#      lastfm_get_np "${lastfm_session}" 0
#      ;;
      (p)
      lastfm_playloop "$network" "${lastfm_session}"
      ;;
      (t (#b)(lastfm://[^ ]##))
      lastfm_tune "$network" ${lastfm_session} $match[1]
      lastfm_playloop "$network" "${lastfm_session}"
#      lastfm_get_np "${lastfm_session}" 0
      ;;
      (tu (#b)([^ ]##))
      lastfm_tune "$network" ${lastfm_session} lastfm://user/$match[1]/personal
      lastfm_playloop "$network" "${lastfm_session}"
#      lastfm_get_np "${lastfm_session}" 0
      ;;
      (tl (#b)([^ ]##))
      lastfm_tune "$network" ${lastfm_session} lastfm://user/$match[1]/loved
      lastfm_playloop "$network" "${lastfm_session}"
#      lastfm_get_np "${lastfm_session}" 0
      ;;
      (tn (#b)([^ ]##))
      lastfm_tune "$network" ${lastfm_session} lastfm://user/$match[1]/neighbours
      lastfm_playloop "$network" "${lastfm_session}"
#      lastfm_get_np "${lastfm_session}" 0
      ;;
#      (love)
#      print "Loving... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=love&debug=0")
#      ;;
#      (ban)
#      print "Banning... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=ban&debug=0")
#      ;;
#      (discovery (#b)(on|off))
#      print "Turning discovery ${match[1]}..." $(wget -q --output-document=- "http://${baseurl}${basepath}/adjust.php?session=${lastfm_session}&url=lastfm://settings/discovery/${match[1]}&debug=0")
#      ;;
#      ((#b)(rtp|nortp))
#      print "Setting ${match[1]}..." $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=${match[1]}")
#      ;;
      (*)
      print "WTF?! Try 'h' for help"
      ;;

    esac
  done

  fi
}
