#!/bin/bash

# Programs invoke depends upon

updatevis="/apps/invoke/updatevis"
updatevisdev="/apps/invoke/updatevisdev"
pixelflip="/usr/lib/hubzero/bin/pixelflip"
icewm_captive="/usr/lib/hubzero/bin/icewm-captive"
ratpoison="/usr/lib/hubzero/bin/ratpoison-captive"
rappture_base="/apps/rappture"

source /apps/environ/.setup.sh

#
# Options (detailed description follows):
#
#     -A tool arguments
#     -c execute command in background
#     -C command to execute for starting the tool
#     -e environment variable (${VERSION} substituted with $TOOL_VERSION)
#     -f No FULLSCREEN
#     -p add to path          (${VERSION} substituted with $TOOL_VERSION)
#     -r rappture version
#     -t tool name
#     -T tool root directory
#     -u use envionment packages
#     -v visualization server version
#     -w specify alternate window manager
#
# Deprecated Options:
#     -a pass html file to about command
#        replaced with: -c "/apps/rappture/bin/about <path_to_html_file>"
#     -l Pass (comma separated) run.xml files to rappture for it to load
#        replaced with: -A "-load file1,file2,file3"
#     -s Execute simsim rather than rappture
#        replaced with: -C /apps/rappture/bin/simsim
#     -q PBS queue
#        not replaced
#
#
# Detailed description of the options:
#
#  -A  pass the provided enquoted arguments onto the tool. Example usage:
#      -A "-q blah1 -w blah2"
#      the options -q and -w are not parsed by invoke, but are passed on to
#      the tool.
#
#  -c  Commands to run in the background before the tool launches.
#      Example usage: -c "echo hi" -c "filexfer"
#
#  -C  Command to execute for starting tool. Tool's command line arguments
#      can be included in this option, or can be placed in the -A option.
#      Example usage: -C /apps/rappture/bin/simsim
#      Example usage: -C "/apps/rappture/bin/simsim -tool driver.xml -values random"
#      Example usage: -C /apps/rappture/bin/simsim -A "-tool driver.xml -values random"
#
#  -e  Set an environment variable. Example usage:
#      -e LD_LIBRARY_PATH=@tool/../${VERSION/lib:${LD_LIBRARY_PATH}
#      Within the value part of this option's argument, the text ${VERSION}
#      is automatically substituted with the value of the variable
#      ${TOOL_VERSION}. Similarly, the text @tool is substituted with
#      the value of ${TOOLDIR}. By setting the environment variable,
#      you are overwritting its previous value.
#
#  -f  no full screen - disable FULLSCREEN environment variable,
#      used by Rappture, to expand the window to the full available size of
#      the screen.
#
#  -p  Prepend to the PATH environment variable. Example usage:
#      -p @tool/../${VERSION}/bin. Within the value part of this option's
#      argument, the text ${VERSION} is automatically substituted with the
#      value of the variable ${TOOL_VERSION}. Similarly, the text @tool is
#      substituted with the value of ${TOOLDIR}. By setting this option
#      the PATH environment variable is adjusted, but not overwritten.
#
#  -r  sets RAPPTURE_VERSION which dictates which version of rappture is used
#      and may manipulate the version of the tool that is run. If left blank,
#      the version will be determined by looking at $SESSIONDIR/resources file.
#
#      Accpetable values include "test", "current", "dev".
#
#      When RAPPTURE_VERSION is "test", RAPPTURE_VERSION is reset to current and
#      TOOL_VERSION is set to dev. The current version of rappture is used and
#      the dev version of the tool is used when launching the program.
#
#      When RAPPTURE_VERSION is "current", TOOL_VERSION is set to "current". The
#      current version of rappture is used and the current version of the tool
#      is used when launching the program.
#
#      When RAPPTURE_VERSION is "dev", TOOL_VERSION is set to "dev". The dev
#      version of rappture is used and the dev version of the tool is used when
#      launching the tool.
#
#  -t  sets ${toolname} which is used while setting up tool paths for TOOLDIR
#      and TOOLXML. ${toolname} is the short name (or project name) of the
#      tool. It is the same as the name used in the source code repository.
#      With respect to the tool contribution process, it is the "toolname"
#      in the path /apps/toolname/version/rappture/tool.xml. Setting this
#      option will change the paths searched while trying to locate tool.xml
#      and the bin directory.
#
#  -T  Tool root directory. This is the directory holding a checked out version
#      of the code from the source code repository. It typically has the src,
#      bin, middleware, rappture, docs, data, and examples directories
#      underneath it. With respect to the tool contribution process, it is the
#      "/apps/toolname/version" in the path
#      /apps/toolname/version/rappture/tool.xml. Setting this option will
#      change the paths searched while trying to locate tool.xml and the bin
#      directory. Typically when testing this option is used to specify
#      where the tool directory is. In this case, its the present working
#      directory:  -T $PWD
#
#  -u  Set use scripts to invoke before running the tool. Example usage:
#      -u octave-3.2.4 -u petsc-3.1-real-gnu
#      These would setup octave-3.2.4 and petsc-3.1 in the environment that
#      your tool would launch in.
#
#  -v  Visualization server version. This option changes which visualization
#      servers are setup in the file $SESSIONDIR/resouces. Currently, the
#      only recognized option is dev. If left blank this option defaults to
#      the "current" visualization servers. This option essentially decides
#      whether to run the script update_vis or update_viz_dev.
#
#  -w  set the window manager. The default value is to use the ratpoison window
#      manager if it exists. If ratpoison is not installed on the system, look
#      for the icewm captive window manager setup. Use this flag to choose an
#      alternative window manager.
#
#
# Deprecated Options (that still work for compatibility):
#
#  -q  pbs queue stuff, this flag does nothing
#
#  -s  Run simsim. we still check this flag, but if you are using it,
#      you should switch to "-C simsim" command line option immediately.
#
#  -l  Send multiple files for rappture to load. This flag is still checked
#      but you should switch to the "-A '-load file1,file2.file3" command
#      line option.

########################################################################
#
# setup_visualization_servers ()
#
# Check the resources file for the most up-to-date version of the rendering
# server parameters.
#
########################################################################

setup_visualization_servers ()
{
    if [[ "$vis" == "dev" ]] ; then
       $updatevisdev
    else
       $updatevis
    fi
}

########################################################################
#
# setup_version ()
#
# Sets variables RAPPTURE_VERSION
# Exports RAPPTURE_VERSION
#
# Figure out which version of Rappture to use: test, current, or dev
# If we are in a tool session, look for the resources file. The
# resources file should be able to tell us the version of the tool that
# is running. When version is "test", this usually means the tool is in
# the contribtool state of "Installed" and was started from within
# contribtool. When version is a numeric value, this usually means the
# tool is in the contribtool state of "Published" and the case
# statement will fall through to the default case, setting
# RAPPTURE_VERSION=current.
#
# I'm not sure when version would ever be current or dev, other than
# if they were set to this by the user. Possibly if the tool was
# started from a dev.*.org machine, they may use dev.
#
########################################################################

setup_version ()
{
    if [[ "$RAPPTURE_VERSION" == "" ]] ; then
        RAPPTURE_VERSION=current
        if [[ "$SESSIONDIR" != "" ]] ; then
            if [[ -e ${SESSIONDIR}/resources ]] ; then
                version=$(grep '^version' ${SESSIONDIR}/resources | cut -d' ' -f 2)
                caseMatch=$(shopt -p nocasematch)
                shopt -s nocasematch
                case $version in
                    test )
                           RAPPTURE_VERSION=current
                           ;;
                 current )
                           RAPPTURE_VERSION=current
                           ;;
                     dev )
                           RAPPTURE_VERSION=dev
                           ;;
                       * )
                           RAPPTURE_VERSION=current
                           ;;
                esac
                $caseMatch
            fi
        fi
    fi
    export RAPPTURE_VERSION
}


########################################################################
#
# setup_tool_paths ()
#
# Set and export TOOLDIR and TOOLXML variables.
#
# This function expects the variables ${toolname} and TOOL_VERSION to have
# been set prior to entry. This function painfully tries all sorts
# of combinations to correctly figure out where the tool.xml is
# located.
#
# Paths checked:
#
# /apps/${toolname}/${TOOL_VERSION}/rappture/tool.xml
# ${TOOLDIR}/rappture/tool.xml
# /apps/${toolname}/${TOOLDIR}/rappture/tool.xml
#
# TOOLDIR is the directory of the tool to be run, something like
# /apps/<toolname>/<version>
#
# TOOLXML is the full path to the tool.xml to be used while launching
# the program.
#
########################################################################

setup_check_tooldir ()
{
    newtooldir=""

    if [[ -d ${TOOLDIR} ]] ; then
        newtooldir=${TOOLDIR}
    else
        if [[ "${toolname}" != "" ]] ; then
            if [[ -d /apps/${toolname}/${TOOLDIR} ]] ; then
                # if the -t option is given, allow user to say
                # -T r43
                newtooldir="/apps/${toolname}/${TOOLDIR}"
            fi
        else
            if [[ -d /apps/${TOOLDIR} ]] ; then
                # allow users to say
                # -T toolname/r43
                newtooldir="/apps/${TOOLDIR}"
            fi
        fi
    fi

    if [[ "${newtooldir}" == "" ]] ; then
        echo "Unable to find TOOLDIR \"${TOOLDIR}\": directory does not exist"
        exit 1
    fi

    TOOLDIR=${newtooldir}

    export TOOLDIR
}

setup_find_toolxml ()
{
    # for rappture tools, we look for tool.xml
    # use ${TOOLDIR} to find tool.xml
    if [[ -e ${TOOLDIR}/rappture/tool.xml ]] ; then
        TOOLXML="${TOOLDIR}/rappture/tool.xml"
    elif [[ -e  ${TOOLDIR}/tool.xml ]] ; then
        TOOLXML="${TOOLDIR}/tool.xml"
    else
        echo "Unable to find tool.xml file. It should be located at \"${TOOLDIR}/rappture/tool.xml\""
        exit 1
    fi

    export TOOLXML
}

########################################################################
#
# start_bg_commands ()
#
# run the setup and background commands prior to starting the rappture
# program. This function starts up the about pages and runs the
# background commands set in the -c option.
#
########################################################################

start_bg_commands ()
{
    export RAPPTURE_DEBUG=1
    export FILEXFER_DEBUG=1
    export RAPPTURE_POSTERN=lumous

    # check for -a about files
    if [[ "$aboutFiles" != "" ]] ; then
      for aboutFile in $aboutFiles ; do
        (sleep 2;${about} $aboutFile)&
      done
    fi

    # check for -c commands
    if [[ "${commands[0]}" != "" ]] ; then
      for command in "${commands[@]}" ; do
        eval $command&
      done
    fi
}

########################################################################
#
# start_window_manager ()
#
# start the pixelflip daemon to keep the vnc session active?
# start a window manager.
#
########################################################################

start_window_manager ()
{
    # Start the 5-minute keepalive daemon.
    for pf in $pixelflip ""; do
        if [[ -x $pf ]] ; then
            $pf
            break
        fi
    done
    if [[ "$pf" == "" ]] ; then
        echo "No pixelflip executable found in: \"$pixelflip\""
    fi

    caseMatch=$(shopt -p nocasematch)
    shopt -s nocasematch
    case $wm in
        captive )
            if [[ `which icewm` == "" ]] ; then
                echo "Unable to find the window manager \"icewm\""
                exit 1
            fi
            if [[ ! -x ${icewm_captive} ]] ; then
                echo "Captive start script, \"${icewm_captive}\" is not executable"
                exit 1
            fi
            wm="$icewm_captive &"
            ;;
        ratpoison )
            if [[ `which ratpoison` == "" ]] ; then
                echo "Unable to find the window manager \"ratpoison\""
                exit 1
            fi
            if [[ ! -x ${ratpoison} ]] ; then
                echo "Ratpoison start script, \"${ratpoison}\" is not executable"
                exit 1
            fi
            wm="$ratpoison &"
            ;;
    esac
    $caseMatch

    # check for -f full screen
    if [[ "$fs" == "" ]] ; then
      export FULLSCREEN=yes
    fi

    # Start the window manager.
    eval $wm
}

########################################################################
#
# setup_path_envvar ()
#
# Add standard stuff to the PATH environment variable
# Currently we add submit (if we can find it) and the tool's bin dir
#
########################################################################

setup_path_envvar ()
{
    if [[ -d /apps/submit/${RAPPTURE_VERSION}/bin ]] ; then
       PATH=/apps/submit/${RAPPTURE_VERSION}/bin:${PATH}
    elif [[ -d /apps/submit/current/bin ]] ; then
       PATH=/apps/submit/current/bin:${PATH}
    fi

    if [[ -d ${TOOLDIR}/bin ]] ; then
      PATH=${TOOLDIR}/bin:${PATH}
    fi

    export PATH
}

########################################################################
#
# setup_installdir ()
#
# figure out where we are installed
# try to set TOOLDIR and toolname the best we can in case the user
# doesn't give us this information.
#
########################################################################

setup_installdir ()
{
    toolname=""
    TOOL_VERSION=""
    TOOLDIR=""

    # this won't work on a mac because they have fake
    # versions of the readlink and realpath functions
    caller=$(ps -ocommand= -p $PPID | awk -F' ' '{print $2}' | awk '{print $1}')

    if [[ "${caller}" != "" ]] ; then
        caller=$(readlink -f ${caller})
        dir=$(dirname ${caller})
        base=$(basename ${caller})
        if [[ "${base}" == "invoke" ]] ; then
            # we were started by an invoke script
            # look for a familiar directory structure
            # to help with guessing toolname and TOOLDIR
            base=$(basename ${dir})
            if [[ "${base}" == "middleware" ]] ; then
                # caller's path probably looks something like one of these:
                # /apps/<toolname>/<version>/middleware/invoke
                # /apps/<toolname>/middleware/invoke
                # /home/<hub>/<user>/<toolname>/middleware/invoke
                # in the first case, <version> could look like:
                # "r1234" or "20081103"
                dir=$(dirname ${dir})
                base=$(basename $dir)
                TOOLDIR=${dir}
                if     [[ "${base}" =~ r([0-9]+) ]] \
                    || [[ "${base}" =~ ([0-9][8]) ]] \
                    || [[ "${base}" == "current" ]] \
                    || [[ "${base}" == "dev" ]] ; then

                    # path probably looks something like this:
                    # /apps/<toolname>/<version>/middleware/invoke
                    TOOL_VERSION=${base}
                    toolname=$(basename $(dirname ${dir}))
                elif [[ "${base}" =~ [a-zA-Z0-9]+ ]] ; then
                    # path probably looks something like one of these:
                    # /apps/<toolname>/middleware/invoke
                    # /home/<hub>/<user>/<toolname>/middleware/invoke
                    TOOL_VERSION=""
                    toolname=${base}
                fi
            fi
        fi
    else
        # since the caller is blank, theres a good chance the user
        # is calling this script directly from the command line.
        # try setting the TOOLDIR to pwd. if no other information
        # is provided on the command line, we can try the obvious
        # solution of looking in pwd.
        TOOLDIR=$(pwd)
    fi


    echo "------------------------------------------------------"
    echo "guessed variable assignments before reading arguments:"
    echo "script = $(readlink -f ${0})"
    echo "caller = ${caller}"
    echo "toolname = ${toolname}"
    echo "TOOL_VERSION = ${TOOL_VERSION}"
    echo "TOOLDIR = ${TOOLDIR}"
    echo "------------------------------------------------------"
}


aboutFiles=""
let nCommands=0
wm="ratpoison"
fs=""
vis=""
runsimsim=""
queue=""
loadfiles=""
toolname=""
toolcmd=""
toolargs=""
options=":C:r:t:T:v:u:e:p:q:c:a:A:w:l:fs"

setup_installdir
setup_version

let nNamedArgs=0
let nUnnamedArgs=0
while (( "$#" ))
do
   case $1 in
      -f|-F|-s )
           namedArgs[$nNamedArgs]=$1
           let nNamedArgs++
           shift
           ;;
      -* )
           namedArgs[$nNamedArgs]=$1
           let nNamedArgs++
           shift
           namedArgs[$nNamedArgs]=$1
           let nNamedArgs++
           shift
           ;;
       * )
           unnamedArgs[$nUnnamedArgs]=$1
           let nUnnamedArgs++
           shift
           ;;
   esac
done

while getopts "${options}" Option "${namedArgs[@]}"
do
   case $Option in
      C ) toolcmd=$OPTARG;;
      r ) RAPPTURE_VERSION=$OPTARG;;
      t ) toolname=$OPTARG;;
      T ) TOOLDIR=$OPTARG;;
      v ) vis=$OPTARG;;
      q ) queue=$OPTARG;;
      c ) commands[$nCommands]=$OPTARG;let nCommands++;;
      a ) aboutFiles="$aboutFiles $OPTARG";;
      A ) toolargs="$OPTARG";;
      w ) wm=$OPTARG;;
      l ) loadfiles="-load $OPTARG";;
      f ) fs="no";;
      s ) runsimsim="yes"
   esac
done

setup_check_tooldir

rappture_bin="${rappture_base}/${RAPPTURE_VERSION}/bin"
about="${rappture_bin}/about"
rappture="${rappture_bin}/rappture"
simsim="${rappture_bin}/simsim"

if [[ "${toolcmd}" == "" ]] ; then
    # no tool command was given
    # check if the simsim flag was set
    # otherwise, default to rappture
    if [[ "${runsimsim}" == "yes" ]] ; then
        toolcmd=${simsim}
    else
        setup_find_toolxml
        toolcmd="${rappture}"
        toolargs="-tool ${TOOLXML} ${loadfiles} ${toolargs}"
    fi
fi


#
# Two passes through argument list allows arbitrary order
# Reset argument pointer to the begining
#
OPTIND=1
while getopts "${options}" Option "${namedArgs[@]}"
do
   case $Option in
      e ) $(echo "export $OPTARG" | sed -e "s/\${VERSION}/${TOOL_VERSION}/" -e "s;@tool;${TOOLDIR};g");;
      p ) $(echo "export PATH=$OPTARG:$PATH" | sed -e "s/\${VERSION}/${TOOL_VERSION}/" -e "s;@tool;${TOOLDIR};g");;
      u ) use -e -r $OPTARG;;
   esac
done

# Add standard stuff to the path,
# like submit and the tool's bin directory
setup_path_envvar

#
# If there is no tty, this is not an interactive session.
# Start a window manager.  Make the app run full screen.
#
tty -s || {
  start_window_manager
  cd ~/data/sessions/${SESSION}
}


setup_visualization_servers

#
# run the application...
#

start_bg_commands

export PROGRAM=$(echo ${toolcmd} | sed -e "s;@tool;${TOOLDIR};g")
toolargs=$(echo ${toolargs} | sed -e "s;@tool;${TOOLDIR};g")

echo "exec'ing = \"${PROGRAM} ${toolargs} ${unnamedArgs[@]}\""
${PROGRAM} ${toolargs} "${unnamedArgs[@]}"

exit $?
