#!/usr/bin/env bash

file=".coke"
params=""
options=""
standard=""
standardPath=""
command="phpcs";
commandPath=""
composerPath="vendor/squizlabs/php_codesniffer/scripts/"
filesAllowed=""
filesIgnored=""

ignored=0
allowed=0
verbose=0
fix=0
onlyGitChanged=0

function allow
{
    if [ -e "$1" ]
    then
        if [ -z "$filesAllowed" ]
        then
            filesAllowed="$1"
        else
            filesAllowed="$filesAllowed $1"
        fi
    fi
}

function ignore
{
    if [ -z "$filesIgnored" ]
    then
        filesIgnored="$1"
    else
        filesIgnored="$filesIgnored,$1"
    fi
}

function output
{
    OUTPUT="[%s%s$1%s] %s$2%s"

    if [ -t 1 ] && [ $- != "*i*" ] && [ -n "$TERM" ] && which tput >/dev/null
    then
        OUTPUT=$(printf "$OUTPUT" "$(tput bold)" "$(tput setaf $3)" "$(tput sgr0)" "$(tput setaf $4)" "$(tput sgr0)" )
    else
        OUTPUT=$(printf "$OUTPUT" "" "" "" "" "" )
    fi

    echo "$OUTPUT"
}

function success
{
    output "SUCCESS" "$1" 2 6
    exit 0
}

function fail
{
    output "FAIL" "$1" 1 6
    exit 1
}

function warning
{
    output "WARNING" "$1" 3 6
    exit 0
}

function info
{
    output "INFO" "$1" 4 6
}

function debug
{
    if [ "$verbose" -eq 1 ]
    then
        info "$1"
    fi
}

# Resolve options
while [ $# -ne 0 ]
do
    CUR_PARAM="$1"

    if [ "${CUR_PARAM:0:2}" =  "--" ]            # it's a parameter
    then
        if [ "${CUR_PARAM:2:9}" =  "standard=" ]
        then
            standard="${CUR_PARAM:11}"
        elif [ "${CUR_PARAM:2:7}" =  "ignore=" ]
        then
            ignore "${CUR_PARAM:9}"
            ignored=1
        elif [ "${CUR_PARAM:2:14}" = "standard-path=" ]
        then
            standardPath="${CUR_PARAM:16}"
        elif [ "${CUR_PARAM:2:5}" = "fix" ]
        then
            fix=1
        elif [ "${CUR_PARAM:2:16}" = "only-git-changed" ]
        then
            onlyGitChanged=1
        else
            params="$params $CUR_PARAM"
        fi
    elif [ "${CUR_PARAM:0:1}" = "-" ]            # it's an option
    then
        case "${CUR_PARAM:1:1}" in
            v)
                verbose=1
            ;;
            f)
                fix=1
            ;;
        esac

        options="$options ${CUR_PARAM}"
    else                                         # it's a file
        allow "$CUR_PARAM"
        allowed=1
    fi

    shift
done

# Resolve commands path to use
if [ -d "$composerPath" ]
then
  debug "Command path used is \"$composerPath\""
  commandPath="$composerPath"
fi

if [ $fix  -eq 1 ]
then
    debug "Use phpcbf command instead of phpcs"
    command="phpcbf"
fi

# Resolve files to test
if [ -e "$file" ]
then
    output=$( grep "^[^\#]" $file )

    for ligne in $output
    do
        if [ "${ligne:0:8}" = "command=" ]
        then
            command="${ligne:8}"
        elif [ -z "$standardPath" ] && [ "${ligne:0:14}" = "standard-path=" ]
        then
            standardPath="${ligne:14}"
        elif [ -z "$standard" ] && [ "${ligne:0:9}" = "standard=" ]
        then
            standard="${ligne:9}"
        elif  [ "$verbose" -eq 0 ] && [ "${ligne:0:8}" = "verbose=" ] && [ "${ligne:8}" = "true" ]
        then
            verbose=1
        elif  [ "$onlyGitChanged" -eq 0 ] && [ "${ligne:0:17}" = "only-git-changed=" ] && [ "${ligne:17}" = "true" ]
        then
            onlyGitChanged=1
        elif [ "$ignored" -eq 0 ] && [ "${ligne:0:1}" = "!" ]
        then
            ignore "${ligne:1}"
        elif [ "$allowed" -eq 0 ] && [ -n "$ligne" ]
        then
            allow "$ligne"
        fi
    done
else
    warning "No config file found"
fi

debug "Starting sniffing"

# Prepare command

if [ -n "$filesIgnored" ]
then
    debug "Ignore files \"$filesIgnored\""
    filesIgnored="--ignore=$filesIgnored"
fi

if [ -n "$standard" ]
then
    debug "Standard used is \"$standard\""
    standard="--standard=$standard"
else
    fail "No coding standard definition provided"
fi

if [ -n "$standardPath" ]
then
    debug "Change standard path to \"$standardPath\""
    $commandPath$command --config-set installed_paths $standardPath
fi

# Check Git changes

if [ $onlyGitChanged -eq 1 ]
then
    command -v git >/dev/null 2>&1 || { fail "Cannot find git. Git is required when --only-git-changed is used."; }

    filesAllowedAndChanged=""
    for file in $(git --no-pager diff --name-only --diff-filter=MARC)
    do
        allowed=0

        for ligne in $filesAllowed
        do
            if [ "${ligne:0:1}" = '!' ] && [[ "$file" == *"${ligne:1}"* ]]
            then
                continue 2
            elif [[ "$file" == "$ligne"* ]]
            then
                allowed=1
            fi
        done

        if [ "$allowed" -eq 1 ]
        then
            filesAllowedAndChanged="$filesAllowedAndChanged $file"
        fi
    done

    filesAllowed=$filesAllowedAndChanged
fi

# Punch it!

if [ -n "$filesAllowed" ]
then
    debug "Files allowed : \"$filesAllowed\""

    $commandPath$command $filesAllowed $filesIgnored $standard $options $params

    if [ $? -ne 0 ]
    then
        fail "Some files do not match with \"${standard:11}\" requirements"
    fi
else
    warning "There was no file to test"
fi

success "All files match with \"${standard:11}\" requirements"

if [ -n "$standardPath" ]
then
    debug "Reset standard path"
    $commandPath$command --config-delete installed_paths
fi