#!/bin/bash

###
# Setup colors if supported
###
if test -t 1; then
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[1;33m'
    BLUE='\033[1;34m'
    GRAY='\033[1;30m'
    NC='\033[0m' # No Color
fi

###
# Define functions
###

function help {
    section "USAGE"
    echo "
    $(basename "$0") [-b=<branch>] [-t=<type>] [-r=<remote>] [-h]
    "

    section "OPTIONS"

    describe "-r=<remote>" "use <remote> for diffs (default: origin)"
    describe "-b=<branch>" "use branch <remote>/<branch> as base for diff (default: master)"
    describe "-t=<type>" "change diff type, optional types: all, diff, staged, <path> (default: diff)

                    all     all files in repository
                    diff    diff of all changed files (staged and unstaged)
                    staged  diff of only staged files
                    <path>  path to folder or file
    "
    describe "-h" "show help"
}

function describe {
    echo -e "${YELLOW}$1${NC}\n\t\t${2}\n"
}

function section {
    echo
    echo -e "${BLUE}$1${NC}"
    echo
}

function skip {
    echo -e "${GRAY}$1${NC}"
}

function command {
    echo
    echo -e "${YELLOW}$1${NC}"
}

function success {
    echo
    echo -e "${GREEN}$1${NC}"
}

function failure {
    echo
    echo -e "${RED}$1${NC}"
}

for ARGUMENT in "$@"
do
    KEY=$(echo $ARGUMENT | cut -f1 -d=)
    VALUE=$(echo $ARGUMENT | cut -f2 -d=)

    case "$KEY" in
        -b)
            BRANCH=$VALUE
            ;;
        -t)
            TYPE=$VALUE
            ;;
        -r)
            REMOTE=$VALUE
            ;;
        -h)
            help
            exit 0;
            ;;
        *)
            failure "Invalid argument: $KEY"
            help
            exit 1;
            ;;
    esac
done

BRANCH="${BRANCH:-master}"
TYPE="${TYPE:-diff}"
REMOTE="${REMOTE:-origin}"

echo "       remote: $REMOTE"
echo "target branch: $BRANCH"
echo "         type: $TYPE"

DIR="$(pwd)/vendor/banovo/coding-standards"

if [ -f "$(pwd)/bin/checker" ]
then
    BINDIR="$(pwd)/bin"
else
    BINDIR="$(pwd)/vendor/bin"
fi

let "ERROR_COUNT=0"

###
# PHP checks
###

case "$TYPE" in
    all)
        # list all files in repository
        FILES_ALL=$(git ls-files)
        ;;
    staged)
        # list staged files
        FILES_ALL=$(git diff $REMOTE/$BRANCH...HEAD --diff-filter=ACM --name-only)
        ;;
    diff)
        # list changed files
        FILES_ALL=$(git diff --name-only --diff-filter=ACM $REMOTE/$BRANCH)
        ;;
    *)
        FILES_ALL=$(git ls-files $TYPE)
        ;;
esac

# include only src and tests folder and exclude all paths, which contains lib and vendor
FILES_ALL=$(printf '%s\n' $FILES_ALL | grep -e '^src\|^tests' | grep -v 'lib' | grep -v 'vendor')

REVLIST=$(git log HEAD..$REMOTE/$BRANCH --oneline)

if [ -n "$REVLIST" ] && ([ $TYPE = "staged" ] || [ $TYPE = "diff" ])
then
    failure "HEAD is not up-to-date with $BRANCH"
    failure "Missing the following commits:"
    skip "$REVLIST"
    echo ""
fi

section "FILES"
printf ' - %s\n' $FILES_ALL

FILES_PHP=$(printf '%s\n' $FILES_ALL | grep '\.php$')
FILES_PHP_FILTERED=$(printf '%s\n' $FILES_PHP | grep -v 'Migrations' | grep -v 'Tests')

if [ -s .phpcpdignore ]
then
    FILES_PHP_FILTERED=$(printf '%s\n' $FILES_PHP_FILTERED | grep -v -f .phpcpdignore)
fi

section "PHP CHECKS"

if [ -z "$FILES_PHP" ];
then
    skip "Skipping php check: no php file was changed"
else
    command "Syntax check"
    for f in $FILES_PHP
    do
        php -l $f 1> /dev/null
        [ $? -ne 0 ] && let "ERROR_COUNT++"
    done
    success "Syntax check completed"

    command "Coding Standards"
    $BINDIR/php-cs-fixer fix --config=$DIR/rulesets/phpcs.php --dry-run --using-cache=no --verbose --path-mode=intersection -- $FILES_ALL
    [ $? -ne 0 ] && let "ERROR_COUNT++"
    success "Coding Standards check completed"

    command "Mess Detector"
    $BINDIR/phpmd src ansi $DIR/rulesets/pmd.xml
    [ $? -ne 0 ] && let "ERROR_COUNT++"
    success "Mess Detector check completed"

    if [ -n "$FILES_PHP_FILTERED" ];
    then
        command "Copy/Paste Detector"
        $BINDIR/phpcpd --fuzzy $FILES_PHP_FILTERED
        [ $? -ne 0 ] && let "ERROR_COUNT++"
        success "Copy/Paste Detector check completed"
    fi
fi

if [ $ERROR_COUNT -ne 0 ] ;
then
    failure "Checking failed. Found $ERROR_COUNT errors"
    exit 1
fi

success "Checking completed"
exit 0
