#!/bin/sh

# TODO:
# - r option: force root, useful for rootless systems like Cygwin

DEP_LINK="http://blog.theseed.org/downloads/ModelSEED"

# check if running as root (sudo)
ROOT=0
if [ "$(id -u)" -eq 0 ]; then
    ROOT=1
fi

# parse the options
VERBOSE=0
CONFIRM=1
TYPE=user
SET_INSTALL=0
SET_LOCAL=0
GIT_SSH=0

while getopts ":hvyst:l:i:" optname
do
    case "$optname" in
        "h")
            # print usage
            echo ""
            echo "Usage: install.sh [options]"
            echo ""
            echo "Options:"
            echo " -h  help"
            echo " -v  verbose, all output goes to stdout"
            echo " -y  yes, skip confirm dialog"
            echo " -s  use git ssh to checkout repositories (for dev install)"
            echo " -t  (user/dev) - install type, either user or dev"
            echo " -l  (directory) - local dir, where to install dependencies"
            echo " -i  (directory) - install dir, where to put MFAToolkit and ModelSEED (for dev install)"
            echo ""
            echo "This script will install the ModelSEED distribution onto your machine. There are two types of install: user and developer (dev). If you plan on modifying the source code then you will want the dev install, otherwise you want a user install."
            echo ""
            echo "By default, a user install will put the code and dependencies into ~/local. You can change this by passing in a directory with the -l option. The dev install will put the dependencies into ~/local, and the source code into the directory where you are executing the script (you can change the install directory with the -i option)."
            echo ""
            echo "Finally, if you want to install the dependencies and/or ModelSEED code into system directories (/usr/bin/perl5/, /usr/local/bin/, etc...), run the script as root by either using sudo (sudo ./install.sh) or by logging in as root and running the script. Doing this will enable all users on your system to run the ModelSEED code."
            echo ""
            exit
            ;;
        "v")
            # verbose
            VERBOSE=1
            ;;
        "y")
            # yes
            CONFIRM=0
            ;;
        "s")
            # git ssh
            GIT_SSH=1
            ;;
        "t")
            # one of 'user' or 'dev'
            if [ $OPTARG = "user" ]; then
                TYPE=user
            elif [ $OPTARG = "dev" ]; then
                TYPE=dev
            else
                echo "Valid type (-t) options are 'user' and 'dev'."
                exit 2
            fi
            ;;
        "l")
            LOCAL=$(dirname $OPTARG)
            if [ ! -d $LOCAL ]; then
                echo ""
                echo "Error, -l argument is empty (or path doesn't exist)"
                exit 2
            fi
            LOCAL=$(cd $LOCAL; pwd)/$(basename $OPTARG)
            SET_LOCAL=1
            ;;
        "i")
            INSTALL=$(dirname $OPTARG)
            if [ ! -d $INSTALL ]; then
                echo ""
                echo "Error, -i argument is empty (or path doesn't exist)"
                exit 2
            fi
            INSTALL=$(cd $INSTALL; pwd)/$(basename $OPTARG)
            SET_INSTALL=1
            ;;
        "?")
            echo "Unknown option -$OPTARG"
            # print usage
            exit 2
            ;;
        ":")
            echo "No value for option -$OPTARG"
            # print usage
            exit 2
            ;;
    esac
done

# install only valid if type is dev
if [ $TYPE = "dev" ] && [ $SET_INSTALL -eq 0 ]; then
    INSTALL=`pwd`
fi

if [ $SET_LOCAL -eq 0 ]; then
    if [ $ROOT -eq 1 ]; then
        LOCAL="-"
    else
        LOCAL=$HOME/local
    fi
fi

if [ $LOCAL = "-" ]; then
    LOCAL_MES="system directory"
else
    LOCAL_MES=$LOCAL
fi

if [ $TYPE = "user" ]; then
    while true; do
        echo ""
        echo "Installing ModelSEED into '$LOCAL_MES', do you want to continue? (y/n)"
        if [ $CONFIRM -eq 0 ]; then
            echo "y"
            break
        fi
        read -p "" yn
        case $yn in
            [Yy]* ) break;;
            [Nn]* )
                echo "Cancelling, 'install.sh -h' for options"
                exit
                ;;
            * ) echo "Please answer yes or no.";;
        esac
    done
else
    while true; do
        echo
        echo "Installing a development ModelSEED into '$INSTALL' and installing dependencies into '$LOCAL_MES'."
        echo "Do you want to continue? (y/n)"
        if [ $CONFIRM -eq 0 ]; then
            echo "y"
            break
        fi
        read -p "" yn
        case $yn in
            [Yy]* ) break;;
            [Nn]* )
                echo "Cancelling, 'install.sh -h' for options"
                exit
                ;;
            * ) echo "Please answer yes or no.";;
        esac
    done
fi

OUT="/dev/null"
if [ $VERBOSE -eq 1 ]; then
    OUT="/dev/stdout"
fi

# setup environment if LOCAL was set
if [ $LOCAL != "-" ]; then
    export PATH=$LOCAL/bin:$PATH
    if [ -n "$PERL5LIB" ]; then
        export PERL5LIB=$LOCAL/lib/perl5:$PERL5LIB
    else
        export PERL5LIB=$LOCAL/lib/perl5
    fi
fi

# setup download client (curl or wget)
if which curl 1>/dev/null 2>&1; then
    UA='curl -o'
else
    if which wget 1>/dev/null 2>&1; then
        UA='wget -O'
    else
        echo "Please install either 'curl' or 'wget' and try again."
    fi
fi

# check for other requirements
ERROR=0
for PROGRAM in perl cc make
do
    if ! which $PROGRAM 1>/dev/null 2>&1; then
        ERROR=1
        echo "Could not find required program: '$PROGRAM'."
    fi
done

if [ $TYPE = "dev" ]; then
    if ! which git 1>/dev/null 2>&1; then
        ERROR=1
        echo "Could not find required program: 'git'."
    fi
fi

# stop if there is an error
if [ $ERROR -eq 1 ]; then
    echo "Please install program(s) listed above and try again."
    exit 2
fi

# make the install directory if it doesn't exist
if [ $TYPE = "dev" ]; then
    if [ ! -d $INSTALL ]; then
        mkdir -p $INSTALL
    fi
fi

check_error(){
    if [ $? -ne 0 ]; then
        echo "Error running install, please check $DIR/build.log for details"
        exit 2
    fi
}

RAND=$( printf '%x' $( ( echo $$ ; time ps ; w ; date ) 2>&1 | cksum | cut -f1 -d " " ) )
DIR=/tmp/$RAND
LOG=$DIR/build.log

mkdir $DIR
cd $DIR

echo "" | tee $LOG
echo "Beginning ModelSEED installation" | tee -a $LOG
echo "    install type:" $TYPE | tee -a $LOG > $OUT

if [ $ROOT -eq 1 ]; then
    echo "    root install: yes" | tee -a $LOG > $OUT
else
    echo "    root install: no" | tee -a $LOG > $OUT
fi

echo "    local dir:" $LOCAL | tee -a $LOG > $OUT
echo "    install dir:" $INSTALL | tee -a $LOG > $OUT

# check for dependencies (libxml2, glpk)
echo "" | tee -a $LOG
echo "Installing dependencies" | tee -a $LOG
echo "main(){}" > test.c

# check for glpk
if ! cc -lglpk -L$LOCAL/lib test.c 1>/dev/null 2>&1; then
    echo "  -> installing glpk" | tee -a $LOG
    $UA glpk.tgz $DEP_LINK/deps/glpk.tgz 2>&1 | tee -a $LOG > $OUT; check_error
    tar -xzvf glpk.tgz 2>&1 | tee -a $LOG > $OUT; check_error

    cd glpk
    if [ $LOCAL = "-" ]; then
        ./configure 2>&1 | tee -a $LOG > $OUT; check_error
    else
        ./configure --prefix=$LOCAL 2>&1 | tee -a $LOG > $OUT; check_error
    fi

    make 2>&1 | tee -a $LOG > $OUT; check_error
    make install 2>&1 | tee -a $LOG > $OUT; check_error
    cd ..
fi

# check for XML::LibXML (plus libxml2 and zlib if necessary)
if ! cc -lxml2 -L$LOCAL/lib test.c 1>/dev/null 2>&1; then
    # first check if we need to install zlib too
    if ! cc -lz -L$LOCAL/lib test.c 1>/dev/null 2>&1; then
        # install zlib
        echo "  -> installing zlib" | tee -a $LOG
        $UA zlib.tgz $DEP_LINK/deps/zlib.tgz 2>&1 | tee -a $LOG > $OUT; check_error
        tar -xzvf zlib.tgz 2>&1 | tee -a $LOG > $OUT; check_error

        cd zlib
        if [ $LOCAL = "-" ]; then
            ./configure 2>&1 | tee -a $LOG > $OUT; check_error
        else
            ./configure --prefix=$LOCAL 2>&1 | tee -a $LOG > $OUT; check_error
        fi

        make 2>&1 | tee -a $LOG > $OUT; check_error
        make install 2>&1 | tee -a $LOG > $OUT; check_error
        cd ..
    fi

    # install libxml2
    echo "  -> installing libxml2" | tee -a $LOG
    $UA libxml2.tgz $DEP_LINK/deps/libxml2.tgz 2>&1 | tee -a $LOG > $OUT; check_error
    tar -xzvf libxml2.tgz 2>&1 | tee -a $LOG > $OUT; check_error

    cd libxml2
    if [ $LOCAL = "-" ]; then
        ./configure 2>&1 | tee -a $LOG > $OUT; check_error
    else
        ./configure --prefix=$LOCAL 2>&1 | tee -a $LOG > $OUT; check_error
    fi

    make 2>&1 | tee -a $LOG > $OUT; check_error
    make install 2>&1 | tee -a $LOG > $OUT; check_error
    cd ..
fi

if ! which cpanm 1>/dev/null 2>&1; then
    # download cpanm.pl
    $UA cpanm.pl $DEP_LINK/deps/cpanm.pl 2>&1 | tee -a $LOG > $OUT; check_error

    # install cpanm
    if [ $LOCAL = "-" ]; then
        perl cpanm.pl App::cpanminus 2>&1 | tee -a $LOG > $OUT; check_error
    else
        perl cpanm.pl -l $LOCAL App::cpanminus 2>&1 | tee -a $LOG > $OUT; check_error
    fi
fi

echo "  -> installing perl dependencies (this may take a few minutes)" | tee -a $LOG

# download ModelSEED source code
if [ $TYPE = "dev" ]; then
    if [ $GIT_SSH -eq 0 ]; then
        git clone git://github.com/ModelSEED/ModelSEED.git 2>&1 | tee -a $LOG > $OUT; check_error
    else
        git clone git@github.com:ModelSEED/ModelSEED.git 2>&1 | tee -a $LOG > $OUT; check_error
    fi
else
    $UA ModelSEED.tgz $DEP_LINK/ModelSEED.tgz 2>&1 | tee -a $LOG > $OUT; check_error
    tar -xzvf ModelSEED.tgz 2>&1 | tee -a $LOG > $OUT; check_error
fi

cd ModelSEED
perl Build.PL 2>&1 | tee -a $LOG > $OUT; check_error

if [ $LOCAL = "-" ]; then
    ./Build installdeps --cpan_client "cpanm -n" 2>&1 | tee -a $LOG > $OUT; check_error
else
    ./Build installdeps --cpan_client "$LOCAL/bin/cpanm -n -l $LOCAL" 2>&1 | tee -a $LOG > $OUT; check_error
fi
cd ..

echo "" | tee -a $LOG
echo "Installing core code" | tee -a $LOG

echo "  -> installing MFAToolkit" | tee -a $LOG
if [ $TYPE = "dev" ]; then
    if [ $GIT_SSH -eq 0 ]; then
        git clone git://github.com/ModelSEED/MFAToolkit.git 2>&1 | tee -a $LOG > $OUT; check_error
    else
        git clone git@github.com:ModelSEED/MFAToolkit.git 2>&1 | tee -a $LOG > $OUT; check_error
    fi
else
    $UA MFAToolkit.tgz $DEP_LINK/MFAToolkit.tgz 2>&1 | tee -a $LOG > $OUT; check_error
    tar -xzvf MFAToolkit.tgz 2>&1 | tee -a $LOG > $OUT; check_error
fi

cd MFAToolkit
if [ $LOCAL = "-" ]; then
    make 2>&1 | tee -a $LOG > $OUT; check_error
else
    INC="-I$LOCAL/include -L$LOCAL/lib" LD_RUN_PATH=$LOCAL/lib make 2>&1 | tee -a $LOG > $OUT; check_error
fi

# install
if [ $TYPE = "user" ]; then
    if [ $LOCAL = "-" ]; then
        make deploy-mfatoolkit 2>&1 | tee -a $LOG > $OUT; check_error
    else
        TARGET=$LOCAL make deploy-mfatoolkit 2>&1 | tee -a $LOG > $OUT; check_error
    fi    
else
    # copy to install dir
    MFATK="MFAToolkit"
    ITER=0

    if [ -d $INSTALL/MFAToolkit ]; then
        while true; do
            if [ -d $INSTALL/$MFATK ]; then
                ITER=`expr $ITER + 1`
                MFATK="MFAToolkit"$ITER
            else
                break
            fi
        done
        echo "     '$INSTALL/MFAToolkit' already exists, installing to $INSTALL/$MFATK" | tee -a $LOG
    fi

    cp -r ../MFAToolkit $INSTALL/$MFATK
    echo "export PATH=$INSTALL/$MFATK/bin:\$PATH" > ../modelseed.env
fi
cd ..

# ModelSEED installation notes (for updating):
#  * should run the ModelSEED/scripts/package_config.pl script with
#     the package config parameters you want to include
#     see lib/ModelSEED/PackageConfiguration.pm for details
#  * there are a couple ways to get the binary files, one is to
#     simply list the files in bin. Another way is to use meta_add
#     in the Build.PL file and then parse the MYMETA.json file

echo "  -> installing ModelSEED" | tee -a $LOG
cd ModelSEED
if [ $TYPE = "user" ]; then
    if [ $LOCAL = "-" ]; then
        if [ -d /usr/local/bin ]; then
            INSTALL_OPTS='--install_path script=/usr/local/bin'
        else
            # shouldn't happen, but maybe some weird linux version
            INSTALL_OPTS='--install_path script=/usr/bin'
        fi
        perl scripts/package_config.pl DIST_OS='*nix' DIST_TYPE=user ROOT=$ROOT 2>&1 | tee -a $LOG > $OUT; check_error
    else
        INSTALL_OPTS="--install_base $LOCAL"
        perl scripts/package_config.pl DIST_OS='*nix' DIST_TYPE=user ROOT=$ROOT LOCAL=$LOCAL 2>&1 | tee -a $LOG > $OUT; check_error
    fi

    ./Build install $INSTALL_OPTS 2>&1 | tee -a $LOG > $OUT; check_error
else
    OPTS="INSTALL=$INSTALL"
    if [ $LOCAL != '-' ]; then
        OPTS=$OPTS" LOCAL=$LOCAL"
    fi

    perl scripts/package_config.pl DIST_OS='*nix' DIST_TYPE=dev ROOT=$ROOT $OPTS 2>&1 | tee -a $LOG > $OUT; check_error

    # clean up the build files
    ./Build realclean 2>&1 | tee -a $LOG > $OUT; check_error

    # copy to install dir
    MS="ModelSEED"
    ITER=0

    if [ -d $INSTALL/ModelSEED ]; then
        while true; do
            if [ -d $INSTALL/$MS ]; then
                ITER=`expr $ITER + 1`
                MS="ModelSEED"$ITER
            else
                break
            fi
        done
        echo "     '$INSTALL/ModelSEED' already exists, installing to $INSTALL/$MS" | tee -a $LOG
    fi

    cp -r ../ModelSEED $INSTALL/$MS
    echo "export PATH=$INSTALL/$MS/bin:\$PATH" >> ../modelseed.env
    echo "export PERL5LIB=$INSTALL/$MS/lib:\$PERL5LIB" >> ../modelseed.env
    cp ../modelseed.env $INSTALL/$MS/
fi
cd ..

echo "" | tee -a $LOG
echo "Finished!" | tee -a $LOG

if [ $LOCAL != "-" ]; then
    echo "" | tee -a $LOG
    echo "Note: don't forget to add $LOCAL/bin to your PATH" | tee -a $LOG
    echo " and $LOCAL/lib/perl5 to your PERL5LIB" | tee -a $LOG
fi

exit
