#!/bin/sh

set -e

canonicalname(){
  if test $# -ne 1; then
     echo Usage: canonicalname path > /dev/stderr
     return 1
  fi
  readlink $1 || echo "$(dirname $1)/$(basename $1)"
}

canonicalpath(){
  if test $# -ne 1; then
     echo Usage: canonicalpath path > /dev/stderr
     return 1
  fi
  (cd $(dirname $(canonicalname $1)) && pwd)
}

if test "x$1" = "x--debug"; then
  DEBUG=yes
fi

if test "x$DEBUG" = "xyes"; then
  set -x
  set -v
fi


# Read the modules find part
. $(canonicalpath $0)/dunemodules.inc


###
### LIB
###


#
# for each module load the $CONTROL script part and run $command
#
# parameters:
# $1 command to execute
#
build_modules() {
  command=$1
  load_opts $command
  local runcommand=run_$command
  modules=$MODULES
  if test x"$ONLY" != x; then
	modules=$ONLY
  fi  
  for module in $modules; do
    local path=$(eval "echo \$PATH_${module}")
    eval echo "--- calling $command for \$NAME_${module} ---"
    if ! (
      set -e
      cd "$path"
      eval_control $runcommand $path/$CONTROL
    ); then echo "--- Failed to build $module ---"; exit 1; fi
    echo "--- $module done ---"
  done
}

#
# load command options from an opts file
# the name of the opts file is stored in the global variable $OPTS_FILE
#
# parameters:
# $1 command
#
load_opts() {
  local command=$1
  local COMMAND=$(echo $command | tr '[:lower:]' '[:upper:]')
  if test "x$OPTS_FILE" != "x"; then
    echo "----- loading default flags \$${COMMAND}_FLAGS from $OPTS_FILE -----"
    CMD_PARAMS="$(. $OPTS_FILE; eval echo \$${COMMAND}_FLAGS)"
  fi
}

###############################################
###
### Commands
###

# list of all dunecontrol commands
COMMANDS="update autogen configure make all exec svn"

# help string for the commands
update_HELP="updated all modules from the repository"
autogen_HELP="run the autogen.sh script for each module"
configure_HELP="run configure for each module"
       # "NOTE: the --with-dune* parameters will be generated by dunecontrol"
make_HELP="run make for each module"
all_HELP="run the commands 'autogen' 'configure' and 'make' for each module"
       # "NOTE: run all for an initial setup"
exec_HELP="execute an arbitrary command in each module directory"

#
# setup command proxies
# call will be forwarded to run_default_$command
#

for command in $COMMANDS; do
  eval "run_$command () { run_default_$command; }"
done

#
# default implementations for commands... 
# these can be overwritten in the $CONTROL files
#

run_default_exec () { bash -c "eval $CMD_PARAMS"; }

run_default_update () {
  if test -d .svn; then
    svn update
    return
  fi
  if test -d CVS; then
    cvs update -dP
    return
  fi
  echo "WARNING: $module is not under a known version control system."
  echo "         We support svn and cvs."
}

run_default_autogen () {
  PARAMS="$CMD_PARAMS"
  local M4_PATH=""
  if test -x autogen.sh; then
    for m in $MODULES; do
      path=$(eval "echo \$PATH_$m")
      if test -d $path/m4; then
        M4_PATH="$path $M4_PATH"
      fi
    done
    eval ./autogen.sh "$M4_PATH" "$PARAMS" || exit 1
  fi
}

run_default_configure () {
  PARAMS="$CMD_PARAMS"
  if test -x configure; then
    if test "x$HAVE_dune_common" == "xyes"; then
      PARAMS="$PARAMS \"--with-dune-common=$PATH_dune_common\""
    fi
    if test "x$HAVE_dune_grid" == "xyes"; then
      PARAMS="$PARAMS \"--with-dune-grid=$PATH_dune_grid\""
    fi
    if test "x$HAVE_dune_istl" == "xyes"; then
      PARAMS="$PARAMS \"--with-dune-istl=$PATH_dune_istl\""
    fi
    if test "x$HAVE_dune_disc" == "xyes"; then
      PARAMS="$PARAMS \"--with-dune-disc=$PATH_dune_disc\""
    fi
    echo ./configure "$PARAMS"
    eval ./configure "$PARAMS" || exit 1
  else
    if test -f configure.in || test -f configure.ac; then
      echo "ERROR: configure.[in|ac] found, but configure missing"
      echo "did you forget to run autoconf?"
      exit 1
    fi
  fi
}

run_default_make () {
  PARAMS="$CMD_PARAMS"
  echo make "$PARAMS"
  eval make "$PARAMS"
}

run_default_all () {
  load_opts autogen
  run_autogen
  load_opts configure
  run_configure
  load_opts make
  run_make
}

run_default_svn () {
  if test -d .svn; then
	PARAMS="$CMD_PARAMS"
	eval svn "$PARAMS"
  fi
}

###############################################
###
### main
###

onfailure() {
  echo Execution terminated due to errors!
  exit 1
}

usage () {
    echo "Usage: $(basename $0) [OPTIONS] COMMAND [COMMAND-OPTIONS]"
    echo ""
    echo "Execute COMMAND for all Dune modules found in and below the current directory."
    echo "Dependencies are controlled by the $CONTROL files."
    echo ""
    echo "Options:"
    echo "  -h, --help         show this help"
    echo "      --debug        enable debug output of this script"
    echo "      --opts=FILE    load default options from FILE"
    echo "                     (see dune-common/doc/example.opts)"
    echo "Commands:"
    printf "  \`help'\tguess what :-)\n"
    printf "  \`print'\tprint the list of modules sorted after their dependencies\n"
    for i in $COMMANDS; do
      printf "  \`$i'\t$(eval echo \$${i}_HELP)\n"
    done
    echo
}

if test "x$1" == "x"; then
  usage
  exit 1
fi

trap onfailure EXIT

while test $# -gt 0; do
    # get option
    option=$1
    shift

    # get args
    set +e
    # stolen from configure...
    # when no option is set, this returns an error code
    arg=`expr "x$option" : 'x[^=]*=\(.*\)'`
    arg=$(eval "echo $arg")
    set -e

    # switch
    case "$option" in
    --opts=*)
      if test "x$arg" == "x"; then
        usage
        echo "ERROR: Parameter for --opts is missing"
        echo
        exit 1;
      fi
      OPTS_FILE=$(canonicalpath $arg)/$(basename $arg)
      if ! test -r "$OPTS_FILE"; then
        usage
        echo "ERROR: could not read opts file \"$OPTS_FILE\""
        echo
        exit 1;
      fi
    ;;
    -h|--help) 
      command=help
      break
    ;;
    -p|--print) 
      command=print
      break
    ;;
    --module=*)
      if test "x$arg" == "x"; then
        usage
        echo "ERROR: Parameter for --module is missing"
        echo
        exit 1;
      fi
      fix_and_assign MODULE "$arg"
    ;;
    --only=*)
      if test "x$arg" == "x"; then
        usage
        echo "ERROR: Parameter for --only is missing"
        echo
        exit 1;
      fi
      fix_and_assign ONLY "$arg"
      fix_and_assign MODULE "$arg"
    ;;
    --debug) true ;;
    *)
      command=$option
      break
    ;;
    esac
done

while test $# -gt 0; do
  # setup paramter list
  CMD_PARAMS="$CMD_PARAMS \"$1\""
  shift
  # disable usage of opts file
  if test "x$OPTS_FILE" != "x"; then
    echo "WARNING: commandline parameters will overwrite setting in opts file \"$OPTS_FILE\""
  fi 
  OPTS_FILE=""
done

# We need to run this via eval in order construct the case for the commands
eval '
case "$command" in
  '$(echo $COMMANDS | sed -e 's/ / | /g')')
    find_modules_in_path
    if test "x$MODULE" = "x"; then
      sort_modules $MODULES
    else
      sort_modules $MODULE
    fi
    echo "--- going to build $MODULES ---"
      build_modules $command
    echo "--- done ---"
    ;;
  print)
    find_modules_in_path
    if test "x$MODULE" = "x"; then
      sort_modules $MODULES
    else
      sort_modules $MODULE
    fi
    for mod in $MODULES; do
      echo -n "$(eval echo \$NAME_$mod) "
    done
    echo
    ;;
  help)
    usage
    ;;
  *)
    echo "ERROR: unknown command \"$command\""
    usage
    exit 1
    ;;
esac'

trap - EXIT