#!/bin/bash

function usage(){
    echo "";
    echo "Usage: apollo <command>";
    echo "";
    echo "Production Commands:";
    echo "";
    echo "deploy:           Builds war file (no processing of javascript) into the target directory.";
    echo "jbrowse-tools:    Installs JBrowse tools in the ./bin directory if not preset."
    echo "run-local <port>: Runs from current directory, but not in dev-mode. ";
    echo "help:             This message.";
    echo "";
    echo "Development Commands:";
    echo "devmode:          Runs from current directory debug mode (non-minimized javascript).";
    echo "jbrowse:          Installs updated client/apollo files and JBrowse for the web.";
    echo "run-app   <port>: Runs from current directory, but does not compile annotator panel (you have to run run-local once first).";
    echo "test:             Runs test-suite.";
    echo "debug:            Runs from cuurent directory in debug mode (non-minimized javascript).";
    echo "watchman:         Creates watchman daemon to autocopy plugin files (non-minimized javascript).";
    echo "compile:          Compiled the build.";
    echo "clean:            Removes class files.";
    echo "clean-all:        Removes class files and jbrowse files.";
    echo "create-rest-doc:  Recreates REST documentation.";
};


grails_executable=""
gradle_executable=""

if [[ $# == 0 || $1 == help || $1 == --help ]]; then
    usage
    exit 1;
fi

function deploy_message(){
   echo "***************************************"
   echo "NOTE: Please set the memory for your servlet container (tomcat, jetty, etc.) or Apollo may not start correctly: http://genomearchitect.readthedocs.io/en/latest/Troubleshooting.html#suggested-tomcat-memory-settings"
   echo "***************************************"
}

function check_rest_api(){
	if [ ! -d target ]; then
		$grails_executable doc
	fi
}

function check_java(){
    javac_version=`javac -version 2>&1 | grep ^javac`
    echo "$javac_version found";
    if [[ $javac_version == javac*  ]]; then
        echo "javac installed";
        minor_version=`echo $javac_version  | cut -d\. -f2 `
        if [[ "$minor_version" != '8' ]] ; then
            echo "You must install JDK 1.8"
            exit 1 ;
        else
            echo "JDK 1.8 found: $javac_version"
        fi
    else
       echo "javac not installed.  Please install JDK 1.8."
       exit 1 ;
    fi
}

function check_node(){
    node_executable=$(which node)
    if ! [ -x "$node_executable" ] ; then
        nodejs_executable=$(which nodejs)
        if ! [ -x "$nodejs_executable" ] ; then
            echo "You must install 'Node JS' to do a release of Apollo."
            exit 1 ;
        else
            echo "STOPPING BUILD: You need to create a symlink from 'node' to 'nodejs'"
            echo "e.g., sudo ln -s $nodejs_executable /usr/bin/node"
            exit 0
        fi
    fi
    NODE_VERSION=`$node_executable -v | cut -d\. -f1`
    if [[ $NODE_VERSION == v* ]]; then
        NODE_VERSION=${NODE_VERSION:1}
    fi
    echo "Node Version: $NODE_VERSION"
    if [[ ${NODE_VERSION} -lt 6 ]] || [[ ${NODE_VERSION} -gt 13 ]]; then
        echo "node version 6 to 13 must be installed.  Please install an updated version of node.js by following the instructions appropriate for your system https://nodejs.org/en/download/package-manager/";
        exit 1
    fi


    npm_executable=$(which npm)
    NPM_VERSION=`$npm_executable -v | cut -d\. -f1`
    echo "Npm Version: $NPM_VERSION"
    if [ $NPM_VERSION -lt 3 ]; then
        echo "npm version 3 or better must be installed.  Please install an updated version of node.js by following the instructions appropriate for your system https://nodejs.org/en/download/package-manager/";
        exit 1
    fi

    yarn_executable=$(which yarn)
    if ! [ -x "$yarn_executable" ] ; then
        yarnjs_executable=$(which yarnjs)
		echo "You must install 'yarn ' to build Apollo."
		exit 1 ;
    fi


    YARN_VERSION=`$yarn_executable --version | cut -d\. -f1`
    echo "Yarn Version: $YARN_VERSION"
    if [[ -n $YARN_VERSION && $YARN_VERSION -lt 1 ]]; then
        echo "yarn version 1 or better must be installed. npm i -g yarn"
        exit 1
    fi

}


function check_perldependencies(){
    perl -e 'use Text::Markdown'
    if [ $? != 0 ] ; then
        echo "Perl package 'Text::Markdown' is required in order to do a release of Apollo."
        exit 1 ;
    fi
    perl -e 'use DateTime'
    if [ $? != 0 ] ; then
        echo "Perl package 'DateTime' is required in order to do a release of Apollo."
        exit 1 ;
    fi
}

function check_configs_for_release(){
    check_perldependencies
}

function use_gradlew(){
   if [ -f 'gradlew' ]; then
       echo "Using gradlew";
       : "${JAVA_HOME?:Need to set JAVA_HOME}"
       gradle_executable="./gradlew"
       echo "Gradle version: `$gradle_executable  -v | grep Gradle | cut -f2 -d' ' `";
   else
       echo "You must install 'gradle' to install Apollo."
       exit 1 ;
    fi
}

function check_configs(){
    grails_executable=$(which grails)
    gradle_executable=$(which gradle)
    git_executable=$(which git)

    if ! [[ -x "$grails_executable" ]] ; then
        if [[ -f 'grailsw' ]]; then
            echo "Grails not found using grailsw";
           : "${JAVA_HOME?:Need to set JAVA_HOME}"
            grails_executable="./grailsw"
        else
           echo "You must install 'grails' to install Apollo."
           exit 1 ;
        fi
    else
      echo $grails_executable
       GRAILS_VERSION=`$grails_executable  --version | grep Grails | cut -f2 -d: | xargs echo `;
       echo "Grails version: ${GRAILS_VERSION}"
       if [[ "$GRAILS_VERSION" != "2.5.5" ]];then
           echo "Grails version ${GRAILS_VERSION} not supported.  Only grails 2.5.5 supported so using local ./grailsw instead"
           : "${JAVA_HOME?:Need to set JAVA_HOME}"
            grails_executable="./grailsw"
       else
           echo "Using system grails `$grails_executable  -v | cut -f4 -d' '`";
       fi
    fi

    if ! [[ -x "$gradle_executable" ]] ; then
      use_gradlew
    else
       GRADLE_MAJOR_VERSION=`$gradle_executable  -v | grep Gradle | cut -f2 -d' ' | cut -f1 -d.`;
       echo "Gradle version: ${GRADLE_MAJOR_VERSION}"
       if [[ $GRADLE_MAJOR_VERSION -gt 3  || $GRADLE_MAJOR_VERSION -lt 2 ]];then
           echo "Gradle version ${GRADLE_MAJOR_VERSION} not supported.  Only gradle 2 or 3 supported so using local ./gradlew instead"
           use_gradlew
       else
           echo "Using system gradle `$gradle_executable  -v | grep Gradle | cut -f2 -d' '`";
       fi
    fi

    if ! [[ -x "$git_executable" ]] ; then
       echo "You must install 'git' to install Apollo."
       exit 1 ;
    fi

    check_node
    check_java
}

function copy_configs(){
    rm -f src/java/apollo-config.groovy
    cp apollo-config.groovy src/java/apollo-config.groovy
}

function clean_code(){
    $grails_executable clean
    $gradle_executable cleanAll
}

function clean_all(){
    check_configs
    rm -rf bin
    rm -rf jbrowse
    rm -rf web-app/jbrowse
    rm -rf extlib
    rm -rf node_modules
    rm -rf client/apollo/node_modules
    rm -rf package-lock.json
    rm -f *.zip
    rm -f *.tar.gz
    clean_code
}

function link_jbrowse_tools(){
        rm -rf bin
        ln -s jbrowse/bin bin
        EXTLIB=$(pwd)/extlib
        ./bin/cpanm --local-lib=${EXTLIB}          Bio::GFF3::LowLevel::Parser CGI Devel::Size Digest::Crc32 JSON File::Next Hash::Merge PerlIO::gzip Heap::Simple Heap::Simple::Perl
        ./bin/cpanm --local-lib=${EXTLIB} --notest Heap::Simple::XS
        echo "********************************************************************";
        echo "JBrowse Tools installed in './bin'";
        echo "Perl dependencies in ${EXTLIB}; add to PERL5LIB thusly:";
        echo "   export PERL5LIB=${EXTLIB}/lib/perl5:\$PERL5LIB";
        echo "********************************************************************";
        unset EXTLIB
}

if [[ $1 == "devmode" ]];then
    check_configs
    $gradle_executable installJBrowseWebOnly devmode &
    $grails_executable -reloading run-app
elif [[ $1 == "jbrowse-tools" ]];then
    check_configs
	$gradle_executable installJBrowseWebOnly && link_jbrowse_tools
elif [[ $1 == "run-local" ]];then
    check_configs
    if [[ $# == 2 ]]; then
        $gradle_executable installJBrowseWebOnly gwtc && $grails_executable -Dserver.port=$2 run-app
    else
        $gradle_executable installJBrowseWebOnly gwtc && $grails_executable run-app
    fi
elif [[ $1 == "watchman" ]]; then
    watchman_executable=$(which watchman)
    if ! [ -x "$watchman_executable" ] ; then
        echo "Watchman not found. Install watchman to automatically update the client side plugins for apollo development modes"
    fi
    if [ -x "$watchman_executable" ]; then
		$watchman_executable -- trigger $(PWD) jsfilescopy 'client/apollo/**/*.*s' -- scripts/copy_client.sh;
	fi;
elif [[ $1 == "run-app" ]];then
    check_configs
    if [[ $# == 2 ]]; then
#        $gradle_executable handleJBrowse copyResourcesDev compileJBrowse  && $grails_executable -Dserver.port=$2 run-app
        $gradle_executable installJBrowseWebOnly && $grails_executable -Dserver.port=$2 run-app
    else
        $gradle_executable installJBrowseWebOnly &&  $grails_executable run-app
    fi
elif [[ $1 == "debug" ]];then
    # TODO: feel like there is a better way to do this
    OLD_MAVEN_OPTS=$MAVEN_OPTS
    check_configs
    copy_configs
    clean_all
    export MAVEN_OPTS=-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n
    $gradle_executable installJBrowseWebOnly devmode &
    $grails_executable -reloading debug
    export MAVEN_OPTS=$OLD_MAVEN_OPTS
    unset OLD_MAVEN_OPTS
elif [[ $1 == "test" ]];then
    check_configs
    copy_configs
    $gradle_executable installJBrowseWebOnly
    check_rest_api
	$grails_executable test-app
elif [[ $1 == "test-unit" ]];then
    check_configs
    copy_configs
    $grails_executable installJBrowseWebOnly test-app :unit
elif [[ $1 == "deploy" ]];then
    check_configs
    copy_configs
    $gradle_executable installJBrowse gwtc &&  $grails_executable war && link_jbrowse_tools
    deploy_message
elif [[ $1 == "compile" ]];then
    check_configs
    $gradle_executable gwtc && $grails_executable compile
elif [[ $1 == "create-rest-doc" ]];then
    check_configs
    $grails_executable compile && $grails_executable rest-api-doc && mv -f restapidoc.json web-app/js/restapidoc/
elif [[ $1 == "clean-all" ]];then
    clean_all
elif [[ $1 == "clean" ]];then
    check_configs
    $gradle_executable clean &&  $grails_executable clean
elif [[ $1 == "jbrowse" ]];then
    check_configs
    $gradle_executable installJBrowseWebOnly
else
    usage
fi
