#!/bin/bash

usage() {
    echo ""
    echo "Greenstone script to automate CREATING and USING our docker container for generating nightlies."
    echo ""
    echo "USING:"
    echo "$0 exec       - to execute the container"
    echo "$0 start-exec - to start then execute the container"
    echo "$0 stop       - to stop the container"
    echo "$0 stop-rm    - to stop then remove the container"
    echo ""
    echo "CREATING:"
    echo "$0 prepare         - to create the container from scratch using docker commands"
    echo "$0 alt-prepare     - to create the container from scratch using the Dockerfile instead"
    echo "   $0 install      - to be run from WITHIN THE CONTAINER, sets up subversion for manylinux2014 container"
    echo "       (and gs-release-builder if not installed.)"
    echo "   $0 get-cli      - (gets automatically run by 'install') to get GS CLI tools into gs-release-builder"
    echo "   $0 get-expeditee-rk  - (part of 'install' on 64 bit) gets Expeditee-release-kits with CLI tools into /greenstone"
    echo ""
    echo "$0 more       - to see a list of common docker commands"
    echo "$0            - to see this help again"
    echo ""
}

userAcc=greenstone
# base image name. Determined from https://github.com/pypa/manylinux
imageName=quay.io/pypa/manylinux2014_x86_64
#host=/home/$userAcc
#target=/home/$userAcc
host=/greenstone
target=/greenstone

constant_imagename_32bit=quay.io/pypa/manylinux2014_i686

############################

# Since the host machine is always a 64 bit machine (the older LSB env for 32bit *emulated* a 32 bit
# env by only having 32 bit libraries installed in the system), we need to work out bitness from
# the host machine name, so we can decide if we need to get a 32 or 64 bit manylinux2014 image.
hostname=`hostname`

# Knowing the image name and the container name only makes sense for commands
# run in the host (outside the docker), not for commands inside the docker.
# These variables don't apply to and are not used in commands inside the docker.
if [ -n "$2" ]; then
    containerName=$2
else
    if [[ "$hostname" == *"linux32"* ]]; then
	#echo "hostname $hostname contains linux32, so assuming we're dealing with a 32 bit manylinux2014 docker image."
	containerName=gsb-32
	imageName=$constant_imagename_32bit
    else
	#echo "hostname $hostname doesn't contain linux32, so assuming we're dealing with a 64 bit manylinux2014 docker image."
	containerName=gsb-64
    fi
fi

# We'd be on the host machine and need to work out bitness of docker container
# Or in the container and can discover the bitness of its libraries
bit=64
if [[ "$hostname" == *"linux32"* ]]; then
	bit=32
elif [[ "$hostname" == *"linux64"* ]]; then
	bit=64
else
	# else, we're inside the docker container. To work out bitness, hostname can't help:
	bit=`getconf LONG_BIT`
fi


more_commands() {   
    echo ""
    echo "Commonly used docker commands (to be run on host machine):"
    echo ""
    echo "docker ps --all			# lists all created/started/running/exited containers"
    echo ""
    echo "docker start gsb-${bit}		# starts up created container named gsb-${bit}, still need to run exec:"
    echo "docker exec -it gsb-${bit} /bin/bash   # to get a terminal into running container"
    echo ""
    echo "docker stop gsb-${bit}		# will need docker restart before running docker exec again"
    echo "docker rm gsb-${bit}		# remove a stopped container, no longer listed with ps command"
    echo ""
    echo "docker images			# Lists pulled docked images that can be instantiated into containers"
    echo "docker rmi <image-id-or-name>	# Remove a pulled docker image"
    echo ""
    echo "To test the docker generating a nightly from the host:"
    echo "docker exec -t gsb-${bit} bash -c '$target/gs-release-builder/create-gs-caveat-linux.sh -v 2|3 -b ${bit}'"
    echo ""
    echo "For more see https://wiki.greenstone.org/doku.php?id=internal:greenstone_build_systems#one_time_docker_steps_-_manual_version"
    echo ""
}

setup_svn() {
    if [ -n "$1" ]; then
        location=$1
    else
        location=$target/gs-release-builder/packages
    fi

    # need to find and setup svn. On host machine it's already setup
    # In the docker container, env vars need to be set up to use custom-built SVN
    svn help > /dev/nul 2>&1
    if [ $? = 0 ] ; then
        # probably host machine
        echo "SVN already installed on the system"
    else
        # docker container
        if [ -n "$LD_LIBRARY_PATH" ]; then
            LD_LIBRARY_PATH=$location/subversion/linux/lib:$LD_LIBRARY_PATH
        else
            LD_LIBRARY_PATH=$location/subversion/linux/lib
        fi
        PATH=$location/subversion/linux/bin:$PATH
    fi
}

checkout_release_builder() {
    bitness=`getconf LONG_BIT`
    echo "This command will ensure you have subversion for the docker container (bitness $bitness)"
    echo "   and the gs-release-builder in $target"
    if [ ! -d "${target}/gs-release-builder" ] ; then
	    if [ -d "/app/data/gs-release-builder" ] ; then
	        echo "Found gs-release-builder in /app/data, moving it into $target"
	        mv /app/data/gs-release-builder $target/.
	        if [ -d "/app/data/subversion" ] ; then
		        echo "Found subversion in /app/data, moving it into $target"
		        mv /app/data/subversion $target/.
	        fi
	        if [ -d "/app/data/subversion-linux.tar.gz" ] ; then
		        echo "Found subversion TARBALL in /app/data, removing it"
		        rm -rf /app/data/subversion-linux.tar.gz
	        fi
	    else
	        if [ ! -d "${target}/subversion" ] ; then
		        echo "Need to check out the greenstone subversion tarball"
		        cd "$target"
		        curl https://svn.greenstone.org/main/trunk/gs2-extensions/subversion/subversion-linux${bitness}.tar.gz > subversion-linux.tar.gz
		        
		        tar -xvzf subversion-linux.tar.gz
	        fi
	        echo "Need to check out the gs-release-builder"
	        
            # subversion is now in the $target folder
            setup_svn "$target"
            #if [ -n "$LD_LIBRARY_PATH" ]; then
            #    LD_LIBRARY_PATH=$target/subversion/linux/lib:$LD_LIBRARY_PATH
            #else
            #    LD_LIBRARY_PATH=$target/subversion/linux/lib
            #fi
	        #"$target/subversion/linux/bin/svn" co https://svn.greenstone.org/main/trunk/gs-release-builder
            svn co https://svn.greenstone.org/main/trunk/gs-release-builder
	    fi
    fi
    
    # Since we have subversion and gs-release-builder, move subversion into gs-release-builder
    if [ -d "$target/subversion" ] && [ -d "$target/gs-release-builder" ] ; then        
        mv "$target/subversion" "$target/gs-release-builder/packages/."
    elif [ -d "$target/gs-release-builder" ] ; then
        if [ ! -d "$target/gs-release-builder/packages/subversion" ] ; then
            # check if svn installed on the system
            # running just svn returns 1 even when svn installed, but svn help will return 0 if installed
            svn help > /dev/nul 2>&1   
            if [ $? = 0 ] ; then
                echo "SVN already installed on the system"
            else
                echo "This is probably the docker container. Need to check out the "
		        echo "  greenstone subversion tarball into $target/gs-release-builder/packages:"
                cd "$target/gs-release-builder/packages"
		        curl https://svn.greenstone.org/main/trunk/gs2-extensions/subversion/subversion-linux${bitness}.tar.gz > subversion-linux.tar.gz
		        tar -xvzf subversion-linux.tar.gz
		        cd "$target"
            fi
        else
            echo "Found SVN at $target/gs-release-builder/packages/subversion"
        fi
    else
        echo "ERROR: don't have $target/subversion and/or $target/gs-release-builder !"
    fi
}

get_cli() {
    echo "Will check out cli tools (if not already installed)"
    cd gs-release-builder
    
    # Need svn on PATH to checkout CLI
    # subversion is now in the $target/gs-release-builder/packages folder
    #source ./setup-env.sh
    setup_svn
    `which svn`
    
    cd ext-cli
    # Check out 32 bit JDK version for linux32 and 64 bit for linux64
    if [ ! -d "selfcontained-jdk" ] ; then
        ./get-selfcontained-jdk.sh -b $bit # if $bitness, then this command can only be run from container
    fi
    if [ ! -d "selfcontained-ant" ] ; then
        ./get-selfcontained-ant.sh
    fi
    if [ ! -d "selfcontained-perl-with-cpan" ] ; then
        ./get-selfcontained-perl-with-cpan.sh
    fi
}

get_expeditee_releasekits() {
    if [ "$bit" = "64" ]; then
        echo "Will get expeditee-release-kits (if not already installed)."
    else
        echo "@@@ NOT checking out expeditee-releasekits as target docker container is 32 bit."
        return
    fi    

    if [ ! -d "$target/expeditee-release-kits" ] ; then
        
        # Need svn on PATH
        cd gs-release-builder    
        setup_svn
        `which svn`
        
        cd $target
        svn co https://svn.greenstone.org/other-projects/expeditee-release-kits/trunk expeditee-release-kits

        # checkout ext-cli for expeditee release-kits, where we want ant and jdk11fx
        cd expeditee-release-kits
        if [ ! -d "ext-cli" ] ; then
            svn co https://svn.greenstone.org/main/trunk/ext-cli
            cd ext-cli
            if [ ! -d "selfcontained-jdk" ] ; then
                ./get-selfcontained-jdk.sh -v 11fx
            fi
            if [ ! -d "selfcontained-ant" ] ; then
                ./get-selfcontained-ant.sh
            fi
        fi
        
        cd $target
    fi
    
}

usage_run_caveats() {
    echo "************** gs-docker.sh **************"
    echo "Next run:"
    echo "  cd $target/gs-release-builder"
    echo "  source ./setup-env.sh [devel] (setup-env.sh not needed for running caveats."
    echo "       If 'devel' passed in, sets up gcc, g++ for non-root users. Not needed for root.)"
    echo "(SETUP-CLI.sh already sourced by setup-env.sh and by envi/etc/environment.pl)"
    echo "******************************************"
}

install_gsbuild_tools() {
    #uname=`whoami`
    ##echo "Username: $uname"
    #if [ "$uname" != "$userAcc" ]; then
	#echo "Need to first switch to user $userAcc"
	#su - $userAcc
    #fi
    currdir=`pwd`
    if [ "$currdir" != "$target" ]; then
	    echo "Need to first cd into user home directory $target"
	    cd "$target"
    fi


    # Try to install a few things  so compiling gs3 caveat works
    yum check-update
    yum update -y
    # To sort out compiling	issues when running create-gs3-caveat-linux64.sh
    # Need libc.a
    # This also provides libcrypt.a. But it's not found when compiling apache-httpd for some reason.
    #yum groupinstall 'Development Tools'
    yum -y install glibc-static

    # only grabs gs-release-builder and sets up its ext-cli if they don't already exist
    checkout_release_builder
    get_cli
    get_expeditee_releasekits
    usage_run_caveats
}

# NO LONGER DEPRECATED. Alternative to using 'prepare' is 'alt-prepare'
# which builds and creates the docker container from a Dockerfile
alt_prepare_from_Dockerfile() {
    echo "@@@ imageName is: $imageName"
	
    # customImage is the image built by the Dockerfile
    customImage=gs-manylinux2014-x86_64
    if [[ "$hostname" == *"linux32"* ]]; then    
	customImage=gs-manylinux2014-32
    fi
    echo "@@@ customImage to be created is: $customImage"
    
    gid=$1
    uid=$2

    echo "building custom image $customImage from dockerfile with base image: $imageName"
    #cmd="docker build --no-cache -t ${customImage} --build-arg GID=${gid} --build-arg UID=${uid} ."
    cmd="docker build --no-cache -t ${customImage} --build-arg BASEIMG=${imageName} --build-arg GID=${gid} --build-arg UID=${uid} ."
    $cmd
    echo "   *** Finished running Dockerfile to build image with command:"
    echo "     $cmd"
    
    echo "creating container ${containerName} from dockerfile image $imageName"
    # https://stackoverflow.com/questions/24551592/how-to-make-sure-dockers-time-syncs-with-that-of-the-host
    cmd="docker create -v /etc/localtime:/etc/localtime:ro -it --name ${containerName} --mount type=bind,source=${host},target=${target} ${customImage}"
    echo "   *** Finished running command to create container $containerName from image $imageName:"
    #echo "    docker create -it --name ${containerName} --mount type=bind,source=${host},target=${target} ${customImage}"
    echo "     $cmd"
    $cmd

    start_container

    
    echo ""
    echo "Will now start the container and run a bash terminal in it."
    echo "After that, you'll be IN THE CONTAINER, from where you want to run the script"
    echo "****************"
    #echo "su - ${userAcc}"
    #echo "cd $target"
    echo "$0 install"
    echo "****************"
    echo "to install subversion and the gs-release-builder (release-kits, envi)"
    exec_container

    # If docker container not RUN/CREATEd with -v /etc/localtime:/etc/localtime:ro
    # the less ideal way to set the timezone is after docker EXEC with:
    ## set_timezone
}

prepare_container() {
    echo "@@@ imageName is: $imageName"
    
    #imageName=$1
    #containerName=$1
    #host=$1
    #target=$2
    gid=$1
    uid=$2
    
    docker pull $imageName # pulls specified image, its name/id can be seen by typing: docker images
    
    # https://stackoverflow.com/questions/24551592/how-to-make-sure-dockers-time-syncs-with-that-of-the-host
    docker create -v /etc/localtime:/etc/localtime:ro -it --name $containerName --mount type=bind,source=$host,target=$target $imageName
    
    docker start $containerName  # To see this container listed as running/executing, type: docker ps --all 

    # exits the docker container at end
    docker exec -it $containerName bash -c "groupadd --gid ${gid} ${userAcc} && adduser --uid ${uid} --gid ${gid} ${userAcc} && exit"
    
    #exit # exit the docker container

    
    echo ""
    echo "Will now start the container and run a bash terminal in it."
    echo "After that, you'll be IN THE CONTAINER, from where you want to run"
    echo "****************"
    #echo "su - ${userAcc}"
    echo "cd $target"
    echo "$0 install"
    echo "****************"
    echo "to install subversion and the gs-release-builder (release-kits, envi)"
    exec_container
    
    # Now the container's running again, if the container was not CREATEd with "-v /etc/localtime:/etc/localtime:ro"
    # the less ideal way to set the timezone is after docker EXEC with:
    ## set_timezone
}

# Less ideal way to set the timezone:
# When the container is running, inside it, rm the symlink to UTC and replace with symlink to NZDT (Auckland timezone)
# This is not the ideal way of doing this, as this script shouldn't have to be hardcoded to any timezone
# But if the container was already CREATED and everything was set up for release-building, then this one time step
# will be enough to get the timezone of the container synced to the host (the time is already synced, but by default
# our container uses the UTC timezone and interprets the same date-time as some other time around the same day).
# Suggested by Gemini
set_timezone() {
    echo "Setting up timezone"
    rm -f /etc/localtime
    ln -s /usr/share/zoneinfo/Pacific/Auckland /etc/localtime
}

start_container() {
    docker start $containerName
}

exec_container() {
    docker exec -it $containerName /bin/bash
}


stop_container() {
    docker stop $containerName
}

rm_container() {
    docker rm $containerName
    echo "Have left $target/gs-release-builder. Remove it manually if you want to check it out afresh."
    echo "**********"
    echo ""
}

# Print usage if we didn't get a cmdline parameter
if [ ! -n "$1" ]; then
    usage
else
    if [[ "$1" == *"help" ]]; then
        #if [ "$1" = "help" ]; then
	    usage
    elif [ "$1" = "start-exec" ]; then
	    echo "start-exec"
	    start_container
	    exec_container
    elif [ "$1" = "stop" ] ; then
	    echo "stop"
	    stop_container
    elif [ "$1" = "stop-rm" ] ; then
	    echo "stop-rm"
	    stop_container
	    rm_container
    elif [ "$1" = "get-cli" ] ; then
        get_cli
    elif [ "$1" = "get-expeditee-rk" ] ; then
        get_expeditee_releasekits
    elif [ "$1" = "prepare" ] || [ "$1" = "alt-prepare" ] ; then	
	    echo "@@@ hostname $hostname taken to indicate bitness and this will determine"
	    echo "@@@ the bitness of the manylinux2014 docker image (else defaults to 64 bit)."
	    
	    id ${userAcc}
	    #result=$?
	    #echo $result
	    # if $result == 1, then create the user $userAcc, which will create /home/$userAcc folder too
	    if [ $? = 1 ] ; then
	        adduser ${userAcc}
	    else
	        echo "User ${userAcc} exists"
	    fi
	    echo "Getting user ${userAcc}'s uid and gid:"
	    # then get the gid and uid for the new user
	    # if $result == 0 then:
	    uid=`id -u ${userAcc}`
	    gid=`id -g ${userAcc}`
	    echo "  UID: ${uid}"
	    echo "  GID: ${gid}"
	    if [ "$1" = "prepare" ] ; then
	        echo "Running 'prepare'"
	        prepare_container $gid $uid
	        echo "END 'prepare'"
	    else
	        echo "*** Running 'alt-prepare' to create docker container from Dockerfile"
	        alt_prepare_from_Dockerfile $gid $uid
	    fi
    elif [ "$1" = "install" ] ; then
	    echo "Running 'install' (within the container)"
	    install_gsbuild_tools
    elif [ "$1" = "exec" ] ; then
	    echo "exec"
        usage_run_caveats
	    exec_container
    elif [ "$1" = "more" ] ; then
	    more_commands
    else
        usage
    fi
fi    
