#!/bin/bash

trap "echo Exited!; exit 1;" SIGINT SIGTERM

PROJECT_DIR="$(cd "$(dirname "$0")/.."; pwd)"

function print_usage {
    echo "usage: test [subcommand] [go test args]"
    echo
    echo -e "\033[1mSubcommands:\033[0m"
    echo "   all               Run all the tests, excluding linters (default)"
    echo "   build             Build all binaries for the project"
    echo "   cleaners          Run tools that clean the code base"
    echo "   unit              Run the unit tests"
    echo "   integration       Run the integration tests"
    echo "   ~integration      Run everything except the integration tests"
    echo "   multiplatform     Run the multiplatform sanity checks"
    echo "   templates         Run the template specs"
    echo "   linters           Run common linters against the project"
    echo "   install_tools     Install all necessary binaries for these scripts"
}

function print_checkpoint {
    echo
    bold_blue "==================================  $@"
}

function green {
    echo -e "\033[32m$1\033[0m"
}

function red {
    echo -e "\033[31m$1\033[0m"
}

function bold_blue {
    echo -e "\033[1;34m$1\033[0m"
}

function check_output {
    eval "$@"
    local status=$?
    exit_on_failure $status
}

function exit_on_failure {
    if [[ $1 -ne 0 ]]; then
        red "SUITE FAILURE"
        exit $1
    fi
}

function run_cleaners {
    print_checkpoint "Running Cleaners"

    go get github.com/kisielk/gotool

    if ! which goimports > /dev/null 2>&1; then
        echo installing goimports
        go get golang.org/x/tools/cmd/goimports
    fi
    if ! which misspell > /dev/null 2>&1; then
        echo installing misspell
        go get github.com/client9/misspell/cmd/misspell
    fi
    if ! which unconvert > /dev/null 2>&1; then
        echo installing unconvert
        go get github.com/mdempsky/unconvert
    fi

    local loggregator_agent_pkg="code.cloudfoundry.org/loggregator-agent"
    local loggregator_agent_dir="$(dirname $(dirname $0))/src/$loggregator_agent_pkg"
    echo running goimports
    goimports -w "$loggregator_agent_dir"
    echo running gofmt
    gofmt -s -w "$loggregator_agent_dir"
    echo running misspell
    misspell -w "$loggregator_agent_dir"
    echo running unconvert
    unconvert -v -apply "$loggregator_agent_pkg/..."
    return 0
}

function run_multiplatform {
    print_checkpoint "Running Multi-Platform Checks"
    sed -n -e '/^properties:/,$p' jobs/loggregator_agent/spec > /tmp/a
    sed -n -e '/^properties:/,$p' jobs/loggregator_agent_windows/spec > /tmp/b
    sed '/# WINDOWS ONLY START/,/# WINDOWS ONLY END/d' /tmp/b > /tmp/c
    diff /tmp/a /tmp/c
    return $?
}

function run_templates {
    print_checkpoint "Running Template Specs"
    if which rspec > /dev/null ; then
        rspec
        return $?
    fi
    return 0
}

function run_build {
    print_checkpoint "Make Sure Loggregator Agent Packages Compile"
    go test -run xxxxxxxxxxxxxxxxx code.cloudfoundry.org/loggregator-agent/... > /dev/null
    exit_code=$?
    if [ $exit_code -ne 0 ]; then
        return $exit_code
    fi

    print_checkpoint "Building Binaries"
    "$(dirname $0)/build"
    return $?
}

function run_unit {
    pushd $PROJECT_DIR/src/code.cloudfoundry.org/loggregator-agent > /dev/null
        print_checkpoint "Running Unit Tests"
        go test -race $(go list ./...) \
            -ginkgo.randomizeAllSpecs \
            -ginkgo.slowSpecThreshold 20 \
            $@
        exit_code=$?
    popd > /dev/null
    return $exit_code
}

function run_all {
    check_output run_cleaners
    check_output run_build
    check_output run_multiplatform
    check_output run_templates
    check_output run_unit $@
}

function parse_argc {
    command=run_all
    if [[ $# -eq 0 ]]; then
        return
    fi

    arg=$1
    case "$arg" in
        -h|-help|--help|help)
            print_usage
            exit 0
            ;;
        all|unit|build|cleaners|multiplatform|templates|linters|install_tools)
            command=run_$arg
            ;;
        *)
            echo "Invalid command: $arg\n"
            print_usage
            exit 1
            ;;
    esac
}

function run_install_tools {
    print_checkpoint "Installing Tools"

    # testing
    go get github.com/onsi/ginkgo/ginkgo

    # cleaners
    go get golang.org/x/tools/cmd/goimports
    go get github.com/client9/misspell/cmd/misspell
    go get github.com/mdempsky/unconvert

    # linters
    go get github.com/tsenart/deadcode
    go get github.com/golang/lint/golint
    go get github.com/opennota/check/cmd/aligncheck
    go get github.com/opennota/check/cmd/structcheck
    go get github.com/opennota/check/cmd/varcheck
    go get github.com/kisielk/errcheck
    go get github.com/gordonklaus/ineffassign
    go get mvdan.cc/interfacer
    go get honnef.co/go/tools/cmd/megacheck
}

function run_linters {
    print_checkpoint "Running Linters"

    local loggregator_agent_pkg
    if [ "$1" = "" ]; then
        loggregator_agent_pkg="code.cloudfoundry.org/loggregator-agent"
    else
        loggregator_agent_pkg="$1"
    fi
    local loggregator_agent_dir="$(dirname $(dirname $0))/src/$loggregator_agent_pkg"

    echo running go vet
    go vet "$loggregator_agent_pkg/..."
    echo running deadcode
    find "$loggregator_dir" -type d | xargs deadcode
    echo running golint
    golint "$loggregator_agent_pkg/..."
    echo running aligncheck
    aligncheck "$loggregator_agent_pkg/..."
    echo running structcheck
    structcheck "$loggregator_agent_pkg/..."
    echo running varcheck
    varcheck "$loggregator_agent_pkg/..."
    echo running errcheck
    errcheck -ignore '[cC]lose' "$loggregator_agent_pkg/..."
    echo running ineffassign
    ineffassign "$loggregator_dir"
    echo running interfacer
    interfacer "$loggregator_agent_pkg/..."
    echo running megacheck
    megacheck "$loggregator_agent_pkg/..."

    return 0
}

function setup_env {
    export PATH="$PROJECT_DIR/bin:$PATH"
    export GORACE="halt_on_error=1"
}

function main {
    setup_env
    parse_argc $1
    shift
    "$command" $@
    result=$?
    exit_on_failure $result
    green "SWEET SUITE SUCCESS"
}

main $@
