#!/bin/bash
PATH="$PATH:/usr/local/bin:$USER/bin"
export PIANOD_USER=x10
export PIANOD_PASSWORD=SOME_PASSWORD
MSERV_USER=x10
MSERV_PASS=SOME_PASSWORD

# Mserv has built-in soundcard/volume support, but not on Mac
MSERV_VOLUME=true
OSX_VOLUME=false
OSASCRIPT=false
if [ "$(uname -s)" = "Darwin" ]
then
	MSERV_VOLUME=false
       	OSX_VOLUME=true
	OSASCRIPT=osascript
fi

LOCALJUKE=pianod
REMOTEJUKE=pianod
ACTIVEJUKE=""

STANDARDVOLUME=100
SCRIPTS=$HOME/bin/iTunesScripts
TAB="	"





# Gary and Dave's Audio Mixer
function tell_gdam {
	typeset action="$1"
	typeset message="$action"

	# Just adjust volume - don't actually pause player.
	# (Matt uses streaming audio.)
	[ "$action" = "pause" ] && message=0
	[ "$action" = "quiet" ] && message=0
	[ "$action" = "continue" ] && message=16
	[ "$action" = "skip" ] && message=next
	[ "$action" = "replay" ] && message=rewind

	(echo " $message") | nc localhost volume >/dev/null 2>&1
}




function is_itunes_playing
{
	typeset status
	status=$($OSASCRIPT "$SCRIPTS/jukebox.scpt" "status")
	[ $? -eq 0 -a "$status" = "playing" ] && return 0
	return 1
}





### mserv interface ###

function mserv
{
	# If mserv doesn't have volume/soundcard support, and this is
	# a volume command, try to handle it a different way.
	if [ "$1" = "volume" -a "$MSERV_VOLUME" = "false" ]
	then
		# OS X can only set volume, not increment/decrement it
		if [ "$OSX_VOLUME" = "true" -a $# -eq 1 ]
		then
			echo "$STANDARDVOLUME"
		elif [ "$OSX_VOLUME" = "true" -a \( \
		     "${2:0:1}" != "+" -a "${2:0:1}" != "-" \) ]
		then
			# Range is 0-7 (???) and allows decimals.
			typeset volume="$(echo "1k $2 7* 100/ p" | dc)"
			$OSASCRIPT -e "set volume $volume"
		fi
	else
		/usr/local/bin/mservcmd -u "$MSERV_USER" -p "$MSERV_PASS" "$*"
	fi
}

function is_mserv_playing
{
	mserv status | head -1 | grep -qi "playing"
	return $?
}

function adjust_rating
{
	typeset rating newrating
	[ $# -gt 1 ] && MSERV_USER="$2" && MSERV_PASS="$2"
	rating=$(mserv "info" | tail +2 | cut -s -d"$TAB" -f12)
	case "$rating" in
		AWFUL)			rating=1 ;;
		BAD)			rating=2 ;;
		UNHEARD|NEUTRAL|HEARD)	rating=3 ;;
		GOOD)			rating=4 ;;
		SUPERB)			rating=5 ;;
		*)			return 1 ;;
	esac
	if [ "$1" = "better" ]
	then
		let rating=rating+1
	elif [ "$1" = "worse" ]
	then
		let rating=rating-1
	else
		return 1
	fi
	case "$rating" in
		0)	mserv next
			return 0 ;;
		1)	rating=AWFUL ;;
		2)	rating=BAD ;;
		3)	rating=NEUTRAL ;;
		4)	rating=GOOD ;;
		5)	rating=SUPERB ;;
		*)	return 0;
	esac
	mserv "rate $rating"
	[ "$rating" = "AWFUL" ] && mserv next
	return $?
}


function tell_mserv {
	typeset message="$1"
	shift
	case "$message" in
		pause)	mserv pause ;;
		stop)	mserv repeat
			mserv next
			mserv pause
			# mserv filter off
			;;
		wake)
			if ! is_mserv_playing
			then
				# mserv filter off
				mserv volume 5
				mserv repeat
				mserv next
				mserv play
				mserv factor 0.50
				volume=10
				( while [ $volume -le $STANDARDVOLUME ]
				do
					sleep 5
					# Handle asynchronous off
					is_mserv_playing || break
					mserv volume $volume
					let volume=volume+5
				done ; mserv volume $STANDARDVOLUME ) &
			else
				mserv play
			fi ;;
		continue)
			if ! is_mserv_playing
			then
				mserv play
				mserv volume $STANDARDVOLUME
				mserv factor 0.50
			else
				mserv play
			fi ;;
		skip)	mserv next ;;
		replay)	mserv repeat
			mserv next ;;
		mute)	mserv volume 10 ;;
		unmute)	mserv volume $STANDARDVOLUME ;;
		louder)	mserv volume +10 ;;
		quieter)
			mserv volume -10 ;;
		rate)	if is_mserv_playing
			then
				adjust_rating "$@"
			fi ;;
		

	esac
}


### pianod interface ###
function is_pianod_playing
{
	piano
	return $?
}

function tell_pianod {
	typeset message="$1"
	shift
	case "$message" in
		mute)
			piano volume -30
			;;
		unmute)
			piano volume 0
			;;
		louder)
			piano volume up
			piano volume up
			piano volume up
			piano volume up
			piano volume up
			;;
		quieter)
			piano volume down
			piano volume down
			piano volume down
			piano volume down
			piano volume down
			;;
		continue)
			piano "play" || piano "play mix" ;;
		rate)
			typeset rating="$1"
			[ "$rating" = "superb" ] && rating=good
			[ "$rating" = "awful" ] && rating=bad
			piano rate "$rating"
			;;
		quiet|stop|mute)
			piano "pause" ;;
		info)
			piano status ;;
		wake)
			if ! is_pianod_playing
			then
				volume=-30
				piano volume level $volume
				piano play mix
				( while [ $volume -le 0 ]
				do
					sleep 3
					# Handle asynchronous off
					is_pianod_playing || break
					piano volume level $volume
					let volume=volume+1
				done ; piano volume level 0 ) &
			else
				piano play
			fi ;;
		*)
			piano "$message" "$@" ;;
	esac
}


### Abstract local vs. remote ###

# Determine which player is playing, if either.
# Return 0 on playing, non-0 on stopped.
function get_active_juke
{
	if [ "$ACTIVEJUKE" = "" ]
	then
		typeset localactive=false
		typeset remoteactive=false
		eval "is_${LOCALJUKE}_playing" && localactive=true
		eval "is_${REMOTEJUKE}_playing" && remoteactive=true
		case "$localactive$remoteactive" in
			truetrue)
				# Fix both playing while we're at it.
				remote pause
				ACTIVEJUKE="$LOCALJUKE"
				;;
			truefalse)
				ACTIVEJUKE="$LOCALJUKE"
				;;
			falsetrue)
				ACTIVEJUKE="$REMOTEJUKE"
				;;
			falsefalse)
				ACTIVEJUKE="none"
				;;
		esac
	fi
	[ "$ACTIVEJUKE" != "none" ]
	return $?
}


# Dispatch commands to the local, remote, or active player
function local {
	eval "tell_$LOCALJUKE \"\$@\""
}

function remote {
	eval "tell_$REMOTEJUKE \"\$@\""
}

function active {
	if get_active_juke
	then
		eval "tell_$ACTIVEJUKE \"\$@\""
	fi
}


##### Main body begins here #####

message="$1"
shift

# Turn equipment on/off in response to command
case "$message" in
	jukebox|receive|continue|quiet|wake)
		# ~/bin/action turn house_stereo on
		~/bin/action turn living_stereo on &
		~/bin/action turn basement_stereo on &
		;;
	pause)
		killall -STOP mpg123 mpg321 2>/dev/null
		;;
	stop)
		# Pause MP3 playback of whatever
		killall -STOP mpg123 mpg321 2>/dev/null
		# ~/bin/action turn house_stereo off
		# Delayed shutoff:
		# Basement stereo power supply holds a charge for a second
		# or two, and "farts" while trying to play after shutoff...
		# Give music time to pause and retain main stereo
		# long enough for basement to  shut off completely.
		(sleep 2; ~/bin/action turn basement_stereo off) &
		(sleep 5; ~/bin/action turn living_stereo off) &
		;;
	check)	if ! get_active_juke
		then
			~/bin/action turn house_stereo off
		fi
		;;
esac

# If there's something playing via mpg123, finish that.
# Otherwise, do the regular jukebox stuff.
if [ "$message" = "continue" -o "$message" = "jukebox" -o "$message" = "receive" ]
then
	killall -CONT mpg123 mpg321 2>/dev/null && exit 0
fi

# Dispatch the command to the music servers/players
case "$message" in
	check)	# No-op
		:
		;;
	info)	if get_active_juke
		then
			active info
		else
			echo "Jukebox is stopped."
		fi
		;;
	wake)	# If we're already playing, don't interrupt.
		if ! get_active_juke
		then
			local wake
		fi
		;;
	quiet)
		local pause
		remote pause
		;;
	stop)
		local stop
		remote stop
		;;
	receive)
		local pause
		remote continue
		;;
	continue|jukebox)
		remote pause
		local continue
		;;
	*)
		active "$message" "$@"
		;;
esac

exit $?

