#!/bin/bash
# Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md


#time update doesn't work below
SCRIPT=$(readlink -f $0)
SCRIPT_DIR="$(dirname ${SCRIPT})"
REPO_ROOT="${SCRIPT_DIR%/*}"

#. ${SCRIPT_DIR}/bootstrap_config
. ${SCRIPT_DIR}/common_scripts_lib
. ${SCRIPT_DIR}/format-config.sh

#printVar SCRIPT
#printVar SCRIPT_DIR
#printVar REPO_ROOT

pushd ${REPO_ROOT} >> /dev/null

CURRENT_YEAR=$(date "+%Y")

LICENSE_CHEK="\(.*\)\(Copyright (c) 2017-\)\(.*\)\(, Mudita Sp. z.o.o. All rights reserved.\).*"
LICENSE_CHEK_BASH_RE="(.*)(Copyright \(c\) 2017-)(.*)(, Mudita Sp. z.o.o. All rights reserved.)"
LICENSE1="Copyright (c) 2017-${CURRENT_YEAR}, Mudita Sp. z.o.o. All rights reserved."
LICENSE2="For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md"

CHECK_ONLY="false"
EXIT_CODE=0

#file extension; comment;checker/replacer function
declare -A FileTypes=( 
            ["c_header"]="h;cppChecker;"
            ["c_source"]="c;cppChecker;"
            ["header"]="hpp;cppChecker;"
            ["source"]="cpp;cppChecker;"
            ["python"]="py;pythonChecker;"
            ["shell"]="sh;bashChecker;"
            ["sqlite"]="sql;sqlChecker;"
        )

function addEmptyLine() {
    LINE=$1
    CHECK_EMPTY=$(sed -n "${LINE}p" ${FILE})
    if [[ -n ${CHECK_EMPTY} ]]; then
        sed -i ${LINE}'s@^\(.*\)$@\n\1@' ${FILE}
    fi
}

function updateYear() {
    if [[ ${CHECK_LICENSE} =~ ${LICENSE_CHEK_BASH_RE} ]]; then
        sed -i "1,5s|${LICENSE_CHEK}|\1\2${CURRENT_YEAR}\4|g" ${FILE}
        echo -e "${YELLOW}Updated\e[0m"
    else 
        echo -e "${OK}"
    fi
}



function codeChecker(){
    CHECK_LICENSE=$(head -n5 ${FILE} | grep "${LICENSE_CHEK}")
    if [[ -z ${CHECK_LICENSE} ]]; then
        if [[ ${CHECK_ONLY} == "true" ]]; then
            echo -e "${ERROR}"
            EXIT_CODE=1
        else 
            sed -i "1i${LICENSE_LINE1}" ${FILE}
            sed -i "2i${LICENSE_LINE2}" ${FILE}
            addEmptyLine 3
            echo -e "${FIXED}"
        fi
    else 
        updateYear
    fi
}

function cppChecker() {
    FILE=$1
    LICENSE_LINE1="// ${LICENSE1}"
    LICENSE_LINE2="// ${LICENSE2}"
    codeChecker
}

function sqlChecker() {
    FILE=$1
    LICENSE_LINE1="-- ${LICENSE1}"
    LICENSE_LINE2="-- ${LICENSE2}"
    codeChecker
}

function scriptChecker(){
    CHECK_LICENSE=$( head -n5 ${FILE} | grep "${LICENSE_CHEK}")
    if [[ -z ${CHECK_LICENSE} ]]; then
        if [[ ${CHECK_ONLY} == "true" ]]; then
            echo -e "${ERROR}"
            EXIT_CODE=1
        else
            FIST_LINE=$(head -n1 ${FILE}|grep "$SHA_BANG_EXEC")
            if [[ -n "${FIST_LINE}" ]]; then
                sed -i "2i${LICENSE_LINE1}" ${FILE}
                sed -i "3i${LICENSE_LINE2}" ${FILE}
                addEmptyLine 4
            else 
                sed -i "1i${LICENSE_LINE1}" ${FILE}
                sed -i "2i${LICENSE_LINE2}" ${FILE}
                addEmptyLine 3
            fi
            echo -e "${FIXED}"
        fi
    else 
        updateYear
    fi

}
function pythonChecker(){
    FILE=$1
    LICENSE_LINE1="# ${LICENSE1}"
    LICENSE_LINE2="# ${LICENSE2}"
    SHA_BANG_EXEC="python"
    scriptChecker
    
} 

function bashChecker(){
    FILE=$1
    LICENSE_LINE1="# ${LICENSE1}"
    LICENSE_LINE2="# ${LICENSE2}"
    SHA_BANG_EXEC="bash"
    scriptChecker
}

SUBMODULES=( $(git submodule | cut -f3 -d" " ) )

function extractValues() {
    KEY=$1

    readarray -td ';' DATA <<< ${FileTypes[${KEY}]}

    FILE_EXT=${DATA[0]}
    CHECK_FUNCTION=${DATA[1]}
}

function excludePathFromFind(){
    # ignore submodule paths
    I=0
    SUB_COUNT=${#SUBMODULES[@]}
    while [[ $I -lt ${SUB_COUNT} ]];
    do 
        module=${SUBMODULES[$I]}
        NOT_PATH="${NOT_PATH} -not ( -path ./${module} -prune )"
        I=$(( $I + 1))
    done
    
    # ignore paths excluded from format
    I=0
    IGNORE_PATHS_COUNT=${#ignore_paths[@]}
    while [[ $I -lt ${IGNORE_PATHS_COUNT} ]]
    do
        path=${ignore_paths[$I]}
        if [[ -d ${path} ]]; then
            NOT_PATH="${NOT_PATH} -not ( -path ${path%*/} -prune )"
        fi
        I=$(( $I + 1 ))
    done
}

function findFiles() {
    # find files except submodule directories
    readarray -d '' FILES_TO_CHECK < <(find . ${NOT_PATH} -iname "*.${FILE_EXT}" -printf "%P\0")
}

function shouldnt_ignore() {
    FILE=$1
    for el in ${ignore_paths[@]}; do
        if [[ ${FILE}  =~ ^${el}.* ]]; then
            echo -e "${ORANGE}Ignore: ${FILE} checking due to: $el match!\e[0m"
            return 1
        fi
    done
    return 0
}

function help() {
    cat <<END
    check and update header files with copyright notice
    usage:
        $0 [--help | --check-only]
        $0 --hook [ --check-only]
                Run as git "pre-commith.hook", checks against files in stash
        $0 --ci 
                Run on CI, check files that are new to the current master
            
            --help              - this help message
            --check-only        - only checks, do not change a file

END
    exit 0
}

function hookMain() {
    parseArgs $@
    readarray -d '' FILES_TO_CHECK < <( ${GET_FILES_CMD} )

    for FILE_TYPE in "${!FileTypes[@]}" 
    do
        echo "=== ${FILE_TYPE} ==="
        extractValues ${FILE_TYPE}
        I=0
        while [[ $I -lt ${#FILES_TO_CHECK[@]} ]]
        do
            FILE=${FILES_TO_CHECK[$I]}
            if shouldnt_ignore ${FILE}; then
                if [[ ${FILE} =~ .*\.${FILE_EXT}$ ]]; then
                    echo -en "${FILE}:"
                    ${CHECK_FUNCTION} ${FILE}
                    git add ${FILE}
                fi
            fi
            I=$(( $I + 1 ))
        done
    done
    echo "Hook ${EXIT_CODE}"
    exit ${EXIT_CODE}
}

function standAloneMain() {
    NOT_PATH=""
    excludePathFromFind
    
    for FILE_TYPE in "${!FileTypes[@]}"
    do
        echo "=== ${FILE_TYPE} ==="
        extractValues ${FILE_TYPE}
        findFiles
        I=0
        while [[ $I -lt ${#FILES_TO_CHECK[@]} ]]
        do
            FILE=${FILES_TO_CHECK[$I]}
            if shouldnt_ignore ${FILE}; then
                echo -en "${I}/${#FILES_TO_CHECK[@]}:{${FILE}: "
                ${CHECK_FUNCTION} ${FILE}
            fi
            I=$(( $I + 1 ))
        done
    done
    echo "StandAlone: ${EXIT_CODE}"
    exit ${EXIT_CODE}
}

function parseArgs() {
    if [[ $# -ge 1 ]]; then
        case $1 in
            "--help")
                help
                ;;
            "--check-only")
                CHECK_ONLY=true
                ;;
            "--hook")
                GET_FILES_CMD="git diff --cached --name-only --diff-filter=AM -z ${against:-HEAD}"
                shift
                hookMain $@
                ;;
            "--ci")
                shift
                CHECK_ONLY=true
                GET_FILES_CMD="git diff --name-only --diff-filter=A -z remotes/origin/master...HEAD"
                hookMain $@
                ;;
            *)
            ;;
        esac
    fi
}
parseArgs $@
standAloneMain
