#!/bin/sh

MANIFEST_FILE_PATH="Packages/manifest.json"
PROJECT_SETTINGS_FILE_PATH="ProjectSettings/ProjectSettings.asset"
TEMP_FILE_PATH="temp.txt"

HT_PLUGGABLE_SYMBOLS_BEGIN="HT_PLUGGABLE_SYMBOLS_BEGIN"
HT_PLUGGABLE_SYMBOLS_END="HT_PLUGGABLE_SYMBOLS_END"
HT_PLUGGABLE_PACKAGES_BEGIN="com.ubisoft.hotel.pluggablepackages.begin"
HT_PLUGGABLE_PACKAGES_END="com.ubisoft.hotel.pluggablepackages.end"

NO_ERROR=""

ACTION_NONE="none"
ACTION_RESET="reset"
ACTION_WRITE="write"

list_new_or_modified_files()
{
    git diff --staged --name-status|sed -e '/^D/ d; /^D/! s/.\s\+//;'
}
 
unmunge()
{
    local result="${1#\"}"
    result="${result%\"}"
    env printf "$result"
}

trim()
{
    local result="$(echo "$1" | sed -e 's/^[[:space:]]*//')"
    echo "$result"
}

strip_symbols()
{
    local result=""

    stripping=false
    back_ifs=$IFS
    IFS=';' read -ra tokens <<< "$1"
    for i in "${tokens[@]}"; do
        if [[ "$i" =~ "$HT_PLUGGABLE_SYMBOLS_BEGIN" ]]; then
            stripping=true
        fi 

        if [[ $stripping = false ]]; then
            if [[ ${#result} -gt 0 ]]; then
                result="${result};"
            fi
            result="${result}${i}"
        fi

        if [[ "$i" =~ "$HT_PLUGGABLE_SYMBOLS_END" ]]; then
            stripping=false
        fi
    done

    IFS=back_ifs

    echo "$result"
}

process_symbols()
{
    local prefix=""
    local stripped_symbols=""

    count=0
    back_ifs=$IFS
    IFS=':' read -ra tokens <<< "$1"
    for i in "${tokens[@]}"; do
        if [[ $count -eq 0 ]]; then
            prefix="${i}"
        else
            trimmed="$(trim "$i")"
            stripped_symbols="$(strip_symbols "$trimmed")"
        fi
        count=$(($count + 1))
    done

    IFS=back_ifs

    echo "${prefix}: ${stripped_symbols}"
}

patch_project_settings()
{
    action="$1"

    reset=false
    write=false
    if [[ "$action" = "$ACTION_RESET" ]]; then
        reset=true
    elif [[ "$action" = "$ACTION_WRITE" ]]; then
        reset=true
        write=true
    else
        return 0;
    fi

    file="$PROJECT_SETTINGS_FILE_PATH"
    temp_file="$TEMP_FILE_PATH"

    # Loop through all symbols in ProjectSettings.asset to exclude the pluggable ones
    patching=false
    inner_count=0
    processed_line=""
    has_changed=false
    while IFS= read -r line || [[ -n "$line" ]]; do
        processed_line="$line"

        if [[ "$line" =~ "scriptingDefineSymbols" ]]; then
            trimmed="$(trim "$line")"
            inner_count=$(( (${#line}) - (${#trimmed}) ))
            patching=true
            processed_line=$line
            has_changed=true
        else
            if $patching ; then
                trimmed="$(trim "$line")"
                count=$(( (${#line}) - (${#trimmed}) ))
                if [[ $count -eq $inner_count ]]; then
                    patching=false
                else
                    processed_line="$(process_symbols "$line")"
                fi
            fi
        fi
        echo "$processed_line"
    done < "$file" > "$temp_file"

    if [[ $has_changed = true && $reset = true ]]; then
        cp "$temp_file" "$file"

        if [[ $write = true ]]; then
            git add "$file"
        fi
    fi

    #rm "$temp_file"
}

patch_manifest()
{
    action="$1"

    reset=false
    write=false
    if [[ "$action" = "$ACTION_RESET" ]]; then
        reset=true
    elif [[ "$action" = "$ACTION_WRITE" ]]; then
        reset=true
        write=true
    else
        return 0;
    fi

    file="$MANIFEST_FILE_PATH"
    temp_file="$TEMP_FILE_PATH"

    # Loop through all packages in manifest.json to exclude the pluggable ones
    patching=false
    has_changed=false
    last_line=false
    error="$NO_ERROR"
    while IFS= read -r line || [[ -n "$line" ]]; do
        #if [[ "$line" = "}" ]]; then
        #    last_line=true
        #fi

        if [[ "$line" =~ "$HT_PLUGGABLE_PACKAGES_BEGIN" ]]; then
            patching=true
            add_line=false
        elif [[ "$line" =~ "$HT_PLUGGABLE_PACKAGES_END" ]]; then
            if [[ $patching = true ]]; then
                has_changed=true
                patching=false
            else
                error="Malformed ${file}: Missing ${HT_PLUGGABLE_PACKAGES_BEGIN} package."
            fi
        elif [[ $patching = false ]]; then
            #if [[ $last_line = true ]]; then
            #    printf "${line}"
            #else
            #    echo "${line}"
            #fi
            echo "${line}"
        fi
    done < "$file" > "$temp_file"

    if [[ $patching = true ]]; then
            error="Malformed ${file}: Missing ${HT_PLUGGABLE_PACKAGES_END} package."
    fi

    if [[ "$error" = "$NO_ERROR" && $has_changed = true && $reset = true ]]; then
        cp "$temp_file" "$file"
    fi

    if [[ $write = true ]]; then
        if [[ "$error" != "$NO_ERROR" ]]; then
            env "$error"
        elif [[ $has_changed = true ]]; then
            git add "$file"
        fi
    fi

    rm "$temp_file"
}

process_files_to_commit()
{
    manifest_action="$ACTION_NONE"
    project_settings_action="$ACTION_NONE"

    # manifest.json
    local diff="$(git diff --staged "$MANIFEST_FILE_PATH")"
    if [ -n "$diff" ]; then
        manifest_action="$ACTION_WRITE"
    fi

    # Define symbols in ProjectSettings. It only needs to be patched if it contains pluggable symbols
    local diff="$(git diff --staged "$PROJECT_SETTINGS_FILE_PATH")"
    if [[ "$diff" =~ "$HT_PLUGGABLE_SYMBOLS_BEGIN" ]]; then        
        project_settings_action="$ACTION_WRITE"
    fi

    # If manifest is going to be changed then project settings is reseted to make sure that the game will compile, 
    # otherwise pluggable packages will be deleted from manifest.json but pluggable symbols linked to pluggable packages
    # will still be defined which will lead to compilation errors.
    if [[ "$manifest_action" = "$ACTION_WRITE" && "$project_settings_action" = "$ACTION_NONE" ]]; then
        project_settings_action=$ACTION_RESET
    fi

    patch_manifest "$manifest_action"
    patch_project_settings "$project_settings_action"
}

process_files_to_commit
