#!/bin/bash
set -e
APP_SVNID='$HeadURL: http://dione.no-ip.org/svn/ade/tags/1.7.6/bin/adegmt.sh $ $LastChangedRevision: 6122 $'

. $(ade-config ade_include_prefix)/ade.sh

ADEGMT_DEFINED_ERRORS=(
    "KEY=ADEGMT_ERR_MISC; FMT=\"%s\""
    "KEY=ADEGMT_ERR_ACCESS; FMT=\"%s: can't %s\""
    "KEY=ADEGMT_ERR_OS; FMT=\"%s: failed\""
    "KEY=ADEGMT_ERR_CONVERT; FMT=\"%s: couldn't convert from %s to %s\""
)

adegmt()
{
    local ERRSTACK_REF="$1"
    local OPTVAL LISTPATHS RC TEMP ERRSTACK_REF
    local -a DOLLARAT

    #  Shift off error stack reference.
    shift 

    ###########################################################################
    #
    #  SET ADE OPTIONS
    #
    ###########################################################################

    #  Register application-specific errors
    ade_err_registerdefderrs ADEGMT_DEFINED_ERRORS

    ###########################################################################
    #
    #  PROCESS OPTIONS
    #
    ###########################################################################

    #  Defaults for options
    OPT_SIMULATE=false
    OPT_MODE=get

    #  Register adegmt's options 
    ade_opt_register "$ERRSTACK_REF" -o nl --longoptions=simulate,list-templates --callback-template="adegmt_opt_handler_%s" || return $?
    ade_msg_register "$ERRSTACK_REF" adegmt_usage adegmt_version adegmt_listpaths || return $?

    #  Process options
    ade_opt_process "$ERRSTACK_REF" NEW_DOLLAR_AT "$@" || return $?
    set -- "${NEW_DOLLAR_AT[@]}" 

    ##########################################################################
    #
    #  ARGUMENT PROCESSING
    #
    ##########################################################################

    case $OPT_MODE in
        get)  get  "$ERRSTACK_REF" "$@" || return $? ;;
        list) list "$ERRSTACK_REF" "$@" || return $? ;;
    esac

    return $ADE_ERR_OK
}

get()
{
    local ERRSTACK_REF="$1"; shift

    [ "X$2" != X ] || ade_msg_usage "$ERRSTACK_REF"
    TPLMOD_NAME="$1"
    shift
    NEWMOD_RELPATH="$1"
    shift
    NEWMOD_CMPT_RELPATHS="$@"

    ##########################################################################
    #
    #  FORKING AND LOCKING
    #
    ##########################################################################

    #ade_lck_lock "$ERRSTACK_REF" DUMMY ade_lck_getgenericlockfilename || {
    #    RC=$?
    #    ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_SEEABOVE
    #    return $RC
    #}

    ##########################################################################
    #
    #	GUTS START HERE
    #
    ##########################################################################

    #  Get absolute path of template module.
    TPLMOD_SEARCHPATH="$(ade-config ade_lib_prefix)/templates"
    ade_err_debug "$ERRSTACK_REF" 4 "main: TPLMOD_SEARCHPATH=$TPLMOD_SEARCHPATH"
    FOUND=false
    for DIR in $TPLMOD_SEARCHPATH; do
        [ ! -d $DIR/$TPLMOD_NAME ] || { FOUND=true; break; }
    done
    $FOUND || {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_ACCESS "$TPLMOD_NAME" "find"
        return $ADE_ERR_FAIL
    }
    TPLMOD_ABSPATH=$DIR/$TPLMOD_NAME
    #  And some useful stuff about the template module
    LC_TPLMOD_NAME=`echo $TPLMOD_NAME | tr '[A-Z]' '[a-z]'`
    UC_TPLMOD_NAME=`echo $TPLMOD_NAME | tr '[a-z]' '[A-Z]'`
    CL_TPLMOD_NAME=`cap_first_letter $TPLMOD_NAME`
    ade_err_debug "$ERRSTACK_REF" 4 "main: TPLMOD_ABSPATH=$TPLMOD_ABSPATH, LC_TPLMOD_NAME=$LC_TPLMOD_NAME, UC_TPLMOD_NAME=$UC_TPLMOD_NAME, CL_TPLMOD_NAME=$CL_TPLMOD_NAME"

    [ ! -e $NEWMOD_RELPATH -a ! -h $NEWMOD_RELPATH ] || {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_MISC "$NEWMOD_RELPATH: exists already"
        return $ADE_ERR_FAIL
    }
    ade_err_info "$ERRSTACK_REF" "creating root for new module ..."
    ade_std_shell "$ERRSTACK_REF" --simulate=$OPT_SIMULATE "mkdir -p $NEWMOD_RELPATH"
    #  Get absolute path of new module.
    ade_fnm_makeabsolute "$ERRSTACK_REF" $NEWMOD_RELPATH NEWMOD_ABSPATH || {
        RC=$?
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_CONVERT "$NEWMOD_RELPATH" "path" "absolute path"
        return $RC
    }
    #  And some useful stuff about the new module.
    NEWMOD_NAME=`basename $NEWMOD_ABSPATH`
    LC_NEWMOD_NAME=`echo $NEWMOD_NAME | tr '[A-Z]' '[a-z]'`
    UC_NEWMOD_NAME=`echo $NEWMOD_NAME | tr '[a-z]' '[A-Z]'`
    CL_NEWMOD_NAME=`cap_first_letter $NEWMOD_NAME`
    CREATION_YEAR=`date '+%Y'`
    CREATION_DATE_LONG="`date '+%d %B %Y'`"
    ade_err_debug "$ERRSTACK_REF" 4 "main: NEWMOD_ABSPATH=$NEWMOD_ABSPATH, LC_NEWMOD_NAME=$LC_NEWMOD_NAME, UC_NEWMOD_NAME=$UC_NEWMOD_NAME, CL_NEWMOD_NAME=$CL_NEWMOD_NAME, CREATION_YEAR=$CREATION_YEAR, CREATION_DATE_LONG=$CREATION_DATE_LONG"

    #  Get absolute path of transfer module.
    XFERMOD_ABSPATH=$ADE_TMP_DIR/$PROGNAME.$$.xfer
    #  And some useful stuff about the transfer module.
    XFERMOD_NAME=$TPLMOD_NAME
    LC_XFERMOD_NAME=`echo $XFERMOD_NAME | tr '[A-Z]' '[a-z]'`
    UC_XFERMOD_NAME=`echo $XFERMOD_NAME | tr '[a-z]' '[A-Z]'`
    CL_XFERMOD_NAME=`cap_first_letter $XFERMOD_NAME`
    ade_err_debug "$ERRSTACK_REF" 4 "main: XFERMOD_ABSPATH=$XFERMOD_ABSPATH, LC_XFERMOD_NAME=$LC_XFERMOD_NAME, UC_XFERMOD_NAME=$UC_XFERMOD_NAME, CL_XFERMOD_NAME=$CL_XFERMOD_NAME"

    ###########################################################################
    #
    #  Re-map component paths to same format 'find' would output.
    #
    ###########################################################################

    #  This will be useful in the remapping process.
    PWD=`pwd`
    #  How many have we fixed so far? None.
    FIXED_NEWMOD_CMPT_RELPATHS=
    for NEWMOD_CMPT_RELPATH in $NEWMOD_CMPT_RELPATHS; do
        #  If cwd is under <modroot> the user said something like:
        #      adegmt lxshell .. somemanpage.1
        #  from in <modroot>/man. The second arg (the component) we map to:
        #      ./man/somemanpage.1      
        if MODSUB=`expr "$PWD" : "$NEWMOD_ABSPATH/\(.*\)"`; then
            ade_err_debug "$ERRSTACK_REF" 10 "main: run from below modroot (MODSUB=$MODSUB)"
            FIXED_NEWMOD_CMPT_RELPATH="./$MODSUB/$NEWMOD_CMPT_RELPATH"

        #  If cwd is above <modroot> then the user said something like:
        #      adegmt mymodules/xyz mymodules/xyz/man/somemanpage.1
        #  from above mymodules. The second arg (the component) we map to:
        #      ./man/somemanpage.1
        elif MODSUP=`expr "$NEWMOD_ABSPATH" : "$PWD/\(.*\)"`; then
            ade_err_debug "$ERRSTACK_REF" 10 "main: run from above modroot (MODSUP=$MODSUP)"
            FIXED_NEWMOD_CMPT_RELPATH="./$(expr "$NEWMOD_CMPT_RELPATH" : "$MODSUP/\\(.*\\)")"

        #  And if we are *in* <modroot> then the user said something like:
	#      adegmt . man/somemanpage.1
        #  from in <modroot>. The second arg (the component) we map to:
        #      ./man/somemanpage.1
        elif MODEQ=`expr "$NEWMOD_ABSPATH" : "$PWD\$"` > /dev/null; then
            ade_err_debug "$ERRSTACK_REF" 10 "main: run from in modroot (MODEQ=$MODEQ)"
            FIXED_NEWMOD_CMPT_RELPATH="./$NEWMOD_CMPT_RELPATH"

        #  Otherwise I have no idea what happened. This might be possible,
        #  but I've not come across it yet.
        else
            ade_err_internal "$ERRSTACK_REF" "confused"
        fi
   
        #  A component of './' should be ignored. This arises when the 
 	#  user specifies a component that matches  the root of the 
	#  module. e.g.:
	#      adegmt .. ..
	#  which means "I'm in subdirectory of the modroot (e.g. 'bin')
        #  and I want everything that belongs under the parent directory."
        [ $FIXED_NEWMOD_CMPT_RELPATH = ./ ] && continue
        #  Trailing '/.' should be stripped too. This arises when the
	#  user specifies '.' for a component. After the stripping, this
 	#  will leave './bin' if the user was in the bin directory, but
	#  will leave '.' if the user was in the top directory: but this
        #  is acceptable: it matches what 'find' produced, and will therefore
	#  be accepted correctly.
        FIXED_NEWMOD_CMPT_RELPATH=`echo $FIXED_NEWMOD_CMPT_RELPATH | \
		sed 's/\/\.$//'`

        ade_err_debug "$ERRSTACK_REF" 4 "main: fixed cmpt=$FIXED_NEWMOD_CMPT_RELPATH"
        FIXED_NEWMOD_CMPT_RELPATHS="$FIXED_NEWMOD_CMPT_RELPATHS $FIXED_NEWMOD_CMPT_RELPATH"
    done
    #  Stick it all back in the original variable (it has a nicer name).
    NEWMOD_CMPT_RELPATHS="$FIXED_NEWMOD_CMPT_RELPATHS"

    #  Create transfer module root
    [ ! -e $XFERMOD_ABSPATH -a ! -h $XFERMOD_ABSPATH ] || {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_MISC "$XFERMOD_ABSPATH: exists already"
        return $ADE_ERR_FAIL
    }
    ade_tmp_registerfile "$ERRSTACK_REF" $XFERMOD_ABSPATH
    mkdir -p $XFERMOD_ABSPATH || {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_ACCESS "$XFERMOD_ABSPATH" "create"
        return $ADE_ERR_FAIL
    }
    #  Copy the whole of the template module to the transfer module root.
    ( cd $TPLMOD_ABSPATH && find . -depth | cpio -pudm $XFERMOD_ABSPATH 2>/dev/null ) || {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_OS "cpio"
        return $ADE_ERR_FAIL
    }

    #  Create sorted list of module components.
    XFERMOD_FSITEMS_LIST=$ADE_TMP_DIR/$PROGNAME.$$.list
    ade_tmp_registerfile "$ERRSTACK_REF" $XFERMOD_FSITEMS_LIST
    ( cd $XFERMOD_ABSPATH && find . ) | sort > $XFERMOD_FSITEMS_LIST

    #  Copy over what user specified or all if nothing specified.
    #  To flag a 'nothing copied' error.
    ACCEPTED_SOMETHING=false
    while read XFERMOD_FSITEM; do
        #  Skip .svn directories
        expr "$XFERMOD_FSITEM" : '.*/\.svn$' > /dev/null && continue
        #  Skip things under .svn directories
        expr "$XFERMOD_FSITEM" : '.*/\.svn/.*' > /dev/null && continue

        #  Work out target name
        NEWMOD_FSITEM=`echo $XFERMOD_FSITEM | sed \
                -e "s/\/$LC_XFERMOD_NAME/\/$LC_NEWMOD_NAME/g" \
                -e "s/\/$UC_XFERMOD_NAME/\/$UC_NEWMOD_NAME/g" \
                -e "s/\/$CL_XFERMOD_NAME/\/$CL_NEWMOD_NAME/g"`

        #  By default assume no match ...
        ACCEPT=false
        ade_err_debug "$ERRSTACK_REF" 10 "main: considering $NEWMOD_FSITEM (NEWMOD_CMPT_RELPATHS=\"$NEWMOD_CMPT_RELPATHS\") ..."
        #  ... and accept it if the user specified nothing ...
        if [ "X$NEWMOD_CMPT_RELPATHS" = X ]; then
            ACCEPT=true

        #  ... or if matches what user specified
        else
            for NEWMOD_CMPT_RELPATH in $NEWMOD_CMPT_RELPATHS; do
                #  accept precise matches ...
                if [ $NEWMOD_CMPT_RELPATH = $NEWMOD_FSITEM ]; then
                    ACCEPT=true
                    break

                #  ... and things under precise matches
                elif expr $NEWMOD_FSITEM : "$NEWMOD_CMPT_RELPATH/" > /dev/null; then
                    ACCEPT=true
                    break
                fi
            done
        fi

        #  Skip to next item if not accepting it.
        [ $ACCEPT = false ] && continue
        #  Suppress 'nothing copied' error.
        ACCEPTED_SOMETHING=true

        ######################################################################
        #
        #  Copy item over
        #
        ######################################################################

        #  If (desired) item in transfer module is directory, make directory 
        #  in new module.
        if [ -d $XFERMOD_ABSPATH/$XFERMOD_FSITEM -a ! -h $XFERMOD_ABSPATH/$XFERMOD_FSITEM ]; then
            ade_err_debug "$ERRSTACK_REF" 10 "main: creating dir $NEWMOD_FSITEM ..."
            ade_std_shell "$ERRSTACK_REF" --simulate=$OPT_SIMULATE "mkdir -p $NEWMOD_ABSPATH/$NEWMOD_FSITEM"

        #  If (desired) item is file, copy with substitions on content 
        #  (Substitions on name have already been made.)
        elif [ -f $XFERMOD_ABSPATH/$XFERMOD_FSITEM -a ! -h $XFERMOD_ABSPATH/$XFERMOD_FSITEM ]; then
            ade_err_debug "$ERRSTACK_REF" 10 "main: creating file $NEWMOD_FSITEM ..."
            ade_std_shell "$ERRSTACK_REF" --simulate=$OPT_SIMULATE \
		    "sed -e \"s/$LC_XFERMOD_NAME/$LC_NEWMOD_NAME/g\" \
                         -e \"s/$UC_XFERMOD_NAME/$UC_NEWMOD_NAME/g\" \
                         -e \"s/$CL_XFERMOD_NAME/$CL_NEWMOD_NAME/g\" \
                         -e \"s/ADE_\APP_TOKEN_CREATION_YEAR/$CREATION_YEAR/g\" \
                         -e \"s/ADE_\APP_TOKEN_CREATION_DATE_LONG/$CREATION_DATE_LONG/g\" \
                    < $XFERMOD_ABSPATH/$XFERMOD_FSITEM > \
		    $NEWMOD_ABSPATH/$NEWMOD_FSITEM"
            #  Copy over execute bit
            if [ -x $XFERMOD_ABSPATH/$XFERMOD_FSITEM ]; then
                ade_std_shell "$ERRSTACK_REF" --simulate=$OPT_SIMULATE "chmod a+x $NEWMOD_ABSPATH/$NEWMOD_FSITEM"
            fi

        #  If (desired) item is not file or directory, then give up.
        #  (We may handle other cases if they ever become needed; I
        #  guess this is most likely to be symlinks.)
        else
            ade_err_internal "$ERRSTACK_REF" "unknown entity type (XFERMOD_FSITEM=$XFERMOD_FSITEM, NEWMOD_FSITEM=$NEWMOD_FSITEM"
        fi
    done < $XFERMOD_FSITEMS_LIST
    rm -f $XFERMOD_FSITEMS_LIST
    ade_tmp_deregisterfile "$ERRSTACK_REF" $XFERMOD_FSITEMS_LIST

    #  We would check that something was actually copied here, but we
    #  need to delete the transfer module first either way, so we'll
    #  do the check in a moment.

    ##########################################################################
    #
    #  Tidy up.
    #
    ##########################################################################

    #  Remove transfer module.
    rm -fr $XFERMOD_ABSPATH
    ade_tmp_deregisterfile "$ERRSTACK_REF" $XFERMOD_ABSPATH

    #  Here we do that check just mentioned above.
    [ $ACCEPTED_SOMETHING = false ] && {
        ade_err_error "$ERRSTACK_REF" ADEGMT_ERR_MISC "nothing was installed!"
        return $ADE_ERR_FAIL
    }
   
    #  yes, of course, it does this anyway, but this is clearer.
    return $ADE_ERR_OK
}
    
list()
{
    local ERRSTACK_REF="$1"; shift

    [ "X$1" = X ] || ade_msg_usage "$ERRSTACK_REF"

    ls -1 "$(ade-config ade_lib_prefix)/templates"

    return $ADE_ERR_OK
}


adegmt_opt_handler_n()
{
    adegmt_opt_handler_simulate "$@"
}

adegmt_opt_handler_simulate()
{
    OPT_SIMULATE=true
}

adegmt_opt_handler_l()
{
    adegmt_opt_handler_list_templates "$@"
}

adegmt_opt_handler_list_templates()
{
    OPT_MODE=list
}

adegmt_usage()
{
    local ERRSTACK_REF="$1"; shift
    local USAGETEXT_REF="$1"; shift
    local PASSNO=$1; shift

    if [ $PASSNO = 1 ]; then
        eval "$USAGETEXT_REF=\"<tmp-mod-name> <new-mod-path> [ <component> ... ]\""
    elif [ $PASSNO = 2 ]; then
        eval "$USAGETEXT_REF=\"\
         -n        | --simulate              don't do anything\
        \""
    fi

    return $ADE_ERR_OK
}

adegmt_listpaths() 
{
    local ERRSTACK_REF="$1"; shift
    local PATHLIST_REF=$1; shift

    eval "$PATHLIST_REF=\"\
    \""

    return $ADE_ERR_OK
} 

adegmt_version() 
{
    local ERRSTACK_REF="$1"; shift
    local VERSION_REF=$1; shift

    ade_smf_extractversionfromsvnstring "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF"

    return $ADE_ERR_OK
} 

cap_first_letter()
{
    local WORD="$1"

    echo "$WORD" | sed -e '/^./ {
        h
        s/ *\(.\).*/\1/
        y/abcdefghijklmnopqrtsuvwxyz/ABCDEFGHIJKLMNOPQRTSUVWXYZ/
        G
        s/ *\(.\)\n\( *\)\(.\)\(.*\)/\2\1\4/
    }'
}

ade_gep_main adegmt "$@"
