#!/bin/bash

# lsn-interseat: script to facilitate playing Laser Squad Nemesis over the
# network without requiring a third party server. Essentially emulates a
# hotseat game, by passing files across the network.
#
# version 0.2, first released version
#
# Run the script to create a config file ~/.lsn/config, which you should then
# edit.

function die ()
{
    echo "$1" 1>&2
    exit 1
}

function waitUntilExists ()
{
    while ! [ -e "$1" ]; do
	$HIGH_RES_SLEEP 0.1;
    done
}

function waitUntilDead ()
{
    while [ ps $1 &>/dev/null ]; do
	$HIGH_RES_SLEEP 0.2;
    done
}

[[ -d ~/.lsn ]] || mkdir ~/.lsn || exit 1
[[ -d ~/.lsn/tmp ]] || mkdir ~/.lsn/tmp || exit 1

if ! [[ -r ~/.lsn/lsndir/LSNClient.exe ]]; then
    rm -f ~/.lsn/lsndir >&/dev/null
    if [[ -r ./LSNClient.exe ]]; then
	ln -s "`readlink -f .`" ~/.lsn/lsndir
    else
	read -p "Please enter path to lsn directory: " lsndirpath
	lsndirpath=${lsndirpath/\~/$HOME}
	if [[ -r $lsndirpath/LSNClient.exe ]]; then
	    ln -s "`readlink -f $lsndirpath`" ~/.lsn/lsndir
	else
	    die "I don't believe you."
	fi
    fi
fi

currentConfVersion=0.2

if ! [ -e ~/.lsn/config ]; then
    cat > ~/.lsn/config <<EOF
# GET_FROM_DIR: local path where your opponent's files will appear; you need
# read permissions only
GET_FROM_DIR=

# PUT_IN_DIR: path, in the extended sense understood by scp, of the directory
# to place orders and results. Directory must exist!
PUT_IN_DIR=

# To be clear: your opponent should have GET_FROM_DIR referring to the same
# directory to which you have PUT_IN_DIR referring to, and vice versa.


# HIGH_RES_SLEEP: set to a sleep command which accepts non-integral sleep
# periods ('sleep' satisfies this on many modern systems)
HIGH_RES_SLEEP=sleep

# BEEP: set to your favourite beeping command
BEEP='echo -e \\a'

# BEEP_ON_TURN: if 'true', we beep whenever it's your turn to move; else, we
# beep only if you had to wait for your opponent to move.
BEEP_ON_TURN=false

# WINE: how to invoke wine
WINE=wine

# confVersion: don't change this
confVersion=$currentConfVersion
EOF
fi

. ~/.lsn/config

if [ "$confVersion" != "$currentConfVersion" ]; then
    echo "Warning: config file version is not current. You are advised to remove ~/.lsn/config and run this script again to create a new config file."
fi

if [ -z "$GET_FROM_DIR" ] || [ -z "$PUT_IN_DIR" ]; then
    die "Please edit ~/.lsn/config, setting GET_FROM_DIR and PUT_IN_DIR"
fi

[ -r "$GET_FROM_DIR" ] || die "GET_FROM_DIR not a readable local directory"

gameNum=00000001
lsnDir="$HOME/.lsn/lsndir"
gameDir="$HOME/.lsn/lsndir/Games/$gameNum"

cd "$lsnDir"

player=

while [ "$player" != 1 ] && [ "$player" != 2 ]; do
    read -p "Player [1/2]: " player
done

turn=1

gameName=
submitted=
cont=

while [ -z "$gameName" ] || ls "$GET_FROM_DIR/$gameName"-* &>/dev/null; do
    read -p "Game name: " gameName
    if ls "$GET_FROM_DIR/$gameName"-* &>/dev/null; then
	echo "Name already in use!"
	if [ "$player" == 2 ]; then
	    read -p "Continue game? [y/n]" cont
	    if [ x"$cont" == xy ]; then
		# now need to figure out what turn we're on... got to love
		# this shell scripting malarkey!
		lastResultsTurn="$(ls -1 "$GET_FROM_DIR/$gameName-moved_T"* |\
		sed -n 's/.*_T\([0-9]*\)$/\1/p' | sort -n | tail -1)"

		[ -n "$lastResultsTurn" ] || die "couldn't work out the turn number"

		turn=$((lastResultsTurn+1))
		echo "turn $turn"

		read -p "Have you already submitted your orders for the turn? [y/n]" submitted

		break
	    fi
	fi
    fi
done


if [ $player == 1 ]; then
    # Player 1 is the "server"

    while true; do
	orders1="orders1_G${gameNum}_T${turn}.lsn"
	orders2="orders2_G${gameNum}_T${turn}.lsn"

	# P1's turn
	if [ $turn == 1 ]; then
	    echo "Please start a hotseat game with the agreed map and settings"

	    rm -r "$gameDir".old &>/dev/null
	    mv "$gameDir" "$gameDir".old &>/dev/null
	    $WINE ./LSNClient.exe &>/dev/null &

	    waitUntilExists "$gameDir/gamestate2_G${gameNum}_T0.lsn"
	fi

	echo "Please take your turn, and end the turn when done."
	waitUntilExists "$gameDir/Orders/$orders1"

	# P2's turn
	beeped=
	if ! [ -e "$GET_FROM_DIR/$gameName-$orders2" ]; then
	    echo "Please wait for your opponent to send seir orders. Feel free to prod sem as necessary."
	    waitUntilExists "$GET_FROM_DIR/$gameName-$orders2"
	    $BEEP
	    beeped=1
	    echo "Opponent orders are in!"
	fi
	if [ -z "$beeped" ] && [ BEEP_ON_TURN == true ]; then
	    $BEEP
	fi

	if [ $turn == 1 ]; then
	    echo "Deploy your opponent's units where'er you like."
	else
	    echo "With gaze averted: please select 'OK', wait 1s, press 's', wait 1s."
	fi

	waitUntilExists "$gameDir/Orders/$orders2"
	cp "$GET_FROM_DIR/$gameName-$orders2" "$gameDir/Orders/$orders2"

	waitUntilExists "$gameDir/results2_G${gameNum}_T${turn}.lsn"
	ln -sf "$gameDir/results2_G${gameNum}_T${turn}.lsn" \
	    ~/.lsn/tmp/"$gameName-results_G${gameNum}_T${turn}.lsn"
	ln -sf "$gameDir/gamestate2_G${gameNum}_T${turn}.lsn" \
	    ~/.lsn/tmp/"$gameName-gamestate_G${gameNum}_T${turn}.lsn"
	ln -sf "$gameDir/events2_G${gameNum}" \
	    ~/.lsn/tmp/"$gameName-events_G${gameNum}"
	touch ~/.lsn/tmp/"$gameName-moved_T$turn"
	scp ~/.lsn/tmp/"$gameName-"{results,gamestate}_G${gameNum}_T$turn.lsn \
	    ~/.lsn/tmp/"$gameName-events_G${gameNum}" \
	    ~/.lsn/tmp/"$gameName-moved_T$turn" \
	    "$PUT_IN_DIR" || die "scp failed"

	echo "turn $((turn++))"
    done

else
    # Player 2 is the "client"

    while true; do
	orders1="orders1_G${gameNum}_T${turn}.lsn"
	orders2="orders2_G${gameNum}_T${turn}.lsn"

	if [ x"$submitted" == xy ]; then
	    # already submitted orders for this turn
	    submitted=
	else
	    if [ $turn == 1 ]; then
		echo "Please start a hotseat game with the agreed map and settings"

		rm -r "$gameDir".old &>/dev/null
		mv "$gameDir" "$gameDir".old &>/dev/null
		$WINE ./LSNClient.exe &>/dev/null &

		waitUntilExists "$gameDir/gamestate2_G${gameNum}_T0.lsn"

		cp "$gameDir/gamestate2_G${gameNum}_T0.lsn" \
		"$gameDir/gamestate_G${gameNum}_T0.lsn"

		echo "Deploy your opponent's units where'er you like."
		waitUntilExists "$gameDir/Orders/$orders1"
		echo "Deploy your units, end the turn and quit the client when done."
		waitUntilExists "$gameDir/Orders/$orders2"
	    else
		cp "$GET_FROM_DIR/$gameName-gamestate_G${gameNum}_T$((turn-1)).lsn" \
		"$gameDir/gamestate_G${gameNum}_T$((turn-1)).lsn"
		cp -f "$GET_FROM_DIR/$gameName-events_G${gameNum}" \
		"$gameDir/events_G${gameNum}"

		$WINE ./LSNClient.exe "$GET_FROM_DIR/$gameName-results_G${gameNum}_T$((turn-1)).lsn"&>/dev/null &
		echo "Please take your turn; when done, select \"save file\" then quit the client."
		waitUntilExists "$gameDir/Orders/$orders2"
	    fi

	    scp "$gameDir/Orders/$orders2" "$PUT_IN_DIR/$gameName-orders2_G${gameNum}_T$turn.lsn" || die "scp failed"
	fi

	beeped=
	if ! [ -e "$GET_FROM_DIR/$gameName-moved_T$turn" ]; then
	    echo "Please wait for turn results."
	    waitUntilExists "$GET_FROM_DIR/$gameName-moved_T$turn"
	    beeped=1
	    $BEEP
	    echo "Results in!" 
	fi
	if [ -z "$beeped" ] && [ BEEP_ON_TURN == true ]; then
	    $BEEP
	fi

	echo "turn $((turn++))"
    done
fi
