#!/bin/bash

# Set variables
INFO_MAP_FILENAME="Info_Map.imp"
VERBOSE=0
GENERATEXML=0
MAP_FOLDER=""
ARCHIVE_FILE=""
DIRECT_FILE=""
LOG_FILE="./script.log"
DEFAULT=""
DEPENDENCIES=("7z" "hexdump" "awk")

# Functions declaration

# Check if all required commands are available
check_dependencies() {
    for cmd in "${DEPENDENCIES[@]}"; do
        if ! command -v "$cmd" &> /dev/null; then
            echo "ERROR: Required command '$cmd' is not installed. Please install it and try again."
            exit 1
        fi
    done
}

# Log message to console and file
log_message() {
    if [[ $VERBOSE -eq 1 ]]; then
        echo "$1" | tee -a "$LOG_FILE"
    else
        echo "$1" >> "$LOG_FILE"
    fi
}

# Clean up temporary files when script exits
cleanup() {
    if [[ -f "/tmp/$INFO_MAP_FILENAME" ]]; then
        rm "/tmp/$INFO_MAP_FILENAME"
    fi
    log_message "Cleaned up temporary files."
}
trap cleanup EXIT

# Progress bar for long operations
show_progress() {
    for i in {1..4}; do
        sleep 1
        case $i in
            1) echo -ne 'Processing: [#                         ] (0%)\r' ;;
            2) echo -ne 'Processing: [#####                     ] (25%)\r' ;;
            3) echo -ne 'Processing: [##########                ] (50%)\r' ;;
            4) echo -ne 'Processing: [###############           ] (75%)\r' ;;
        esac
    done
    echo -ne 'Processing: [#######################   ] (100%)\r\n'
}

# Parse Info_Map.imp file
parseInfoMapFile() {
    log_message "Parsing file..."
    
    MAP_NAME=$(hexdump -C "$INFOMAP_FILE" | awk -F"|" '{ print $2 }' | tr -d "\n" | cut -c 21-200)
    MAP_SWID_FscShort=$(hexdump -C "$INFOMAP_FILE" | awk 'NR==1 {print toupper($10$11$12$13)}')
    MAP_REGION=$(hexdump -C "$INFOMAP_FILE" | awk 'NR==1 {print "0x" toupper($11)}')
    MAP_YEAR=$(hexdump -C "$INFOMAP_FILE" | awk 'NR==1 {print "0x" toupper($13)}')
    log_message "Parsing completed [OK]"
}

# Display map information
showMapInfos() {
    echo -e "\n===================== Map Information ========================="
    echo -e "Map Name      : \"$MAP_NAME\""
    echo -e "SWID_FscShort : \"$MAP_SWID_FscShort\""
    echo -e "Map Region    : \"$MAP_REGION\""
    echo -e "Map Year      : \"$MAP_YEAR\""
    echo -e "===============================================================\n"
}

# Show the XML entry to add
showLookupXMLEntry() {
    LONG_MAP_NAME="$MAP_NAME (SWID_FscShort=$MAP_SWID_FscShort, MapRegion=$MAP_REGION, MapYear=$MAP_YEAR)"
    echo -e "\n===================== XML Generation ==========================="
    echo -e "Add this entry at the end of the maps list in your Lookup.xml file:\n"
    echo -e "<SgbmId id=\"NAVD_000024A8_255_007_034\" SWID_FscShort=\"$MAP_SWID_FscShort\" name=\"$LONG_MAP_NAME\" supplier=\"NTQ\" sop=\"01.05.2021\" version=\"10_09\" MapOrderNumberBMW=\"\" MapOrderNumberMINI=\"\" MapOrderNumberRR=\"\" successorMapOrderNumberBMW=\"\" successorMapOrderNumberMINI=\"\" successorMapOrderNumberRR=\"\" NextNo=\"01826\">\n\t<EcuVariant CompatibilityIdentifier=\"NBTevo-HB\" Format=\"CIC\" />\n\t<SwUpdate SwUpdateEntry=\"\"/>\n</SgbmId>"
    echo -e "\n===============================================================\n"
}

# Validate input file permissions
validate_file() {
    if [[ ! -r "$1" ]]; then
        echo "ERROR: Cannot read file $1. Check permissions."
        exit 2
    fi
}

# Process an archive file
processArchiveFile() {
    if [[ ! -f "$ARCHIVE_FILE" ]]; then
        log_message "ERROR: Archive file \"$ARCHIVE_FILE\" does not exist"
        exit 2
    fi

    log_message "File archive exists"

    PATH_TO_INFOMAP_FILE=$(7z l "$ARCHIVE_FILE" | grep "$INFO_MAP_FILENAME" | grep -v "LIGHT" | awk '{print $NF}')
    
    log_message "Looking for \"$INFO_MAP_FILENAME\" in the archive... [OK] - $PATH_TO_INFOMAP_FILE"

    filename=$(basename -- "$ARCHIVE_FILE")
    extension="${filename##*.}"

    case "$extension" in
        "7z"|"7Z")
            log_message "Extracting \"$INFO_MAP_FILENAME\" from 7zip archive..."
            show_progress
            7z -y e "$ARCHIVE_FILE" -o"/tmp" "$PATH_TO_INFOMAP_FILE"
            ;;
        "zip"|"ZIP"|"tar")
            show_progress
            7z -y e "$ARCHIVE_FILE" -o"/tmp" "$PATH_TO_INFOMAP_FILE" > /dev/null
            ;;
        *)
            log_message "Unsupported archive format: $extension"
            exit 2
            ;;
    esac

    if [[ -f "/tmp/$INFO_MAP_FILENAME" ]]; then
        INFOMAP_FILE="/tmp/$INFO_MAP_FILENAME"
    else
        log_message "ERROR: \"$INFO_MAP_FILENAME\" not found in /tmp"
        exit 2
    fi
}

# Process map folder
processFolder() {
    log_message "Processing folder \"$MAP_FOLDER\"..."
    
    if [[ -d "$MAP_FOLDER/1" ]]; then
        INFOMAP_FILE=$(find "$MAP_FOLDER/1" -name "$INFO_MAP_FILENAME" | grep -v "LIGHT" | head -n 1)
        if [[ -z "$INFOMAP_FILE" ]]; then
            log_message "ERROR: \"$INFO_MAP_FILENAME\" not found in folder(s) 1/INFO*"
            exit 2
        fi
    else
        log_message "ERROR: Folder \"$MAP_FOLDER\" does not contain expected map files"
        exit 2
    fi
}

# Batch process for multiple maps
process_batch() {
    for file in "$1"/*; do
        if [[ -d "$file" ]]; then
            log_message "Processing folder: $file"
            processFolder "$file"
        elif [[ -f "$file" ]]; then
            log_message "Processing archive: $file"
            processArchiveFile "$file"
        fi
    done
}

# Set working directory
setWorkDir() {
    if [[ -d "$MAP_FOLDER" ]]; then
        cd "$MAP_FOLDER" || exit 1
        log_message "Using map folder \"$MAP_FOLDER\"... [OK]"
    else
        log_message "ERROR: Given folder \"$MAP_FOLDER\" does not exist"
        exit 2
    fi
}

# Prompt for confirmation before overwriting
prompt_for_confirmation() {
    read -p "File $1 exists. Overwrite? (y/n): " choice
    case "$choice" in 
        y|Y ) log_message "Overwriting...";;
        n|N ) log_message "Skipping..."; exit 0;;
        * ) log_message "Invalid choice"; exit 1;;
    esac
}

# Show usage/help message
show_help() {
    echo "Usage: InfoMap.sh [OPTIONS]"
    echo "Extract hex information from downloaded BMW / Mini / RR Maps"
    echo "Options:"
    echo "  -d <dir>   Specify the map folder to process."
    echo "  -z <file>  Specify the archive file to process (zip, 7z, etc.)."
    echo "  -f <file>  Specify the Info_Map.imp file directly."
    echo "  -v         Enable verbose mode."
    echo "  -x         Generate XML entry."
    echo "  -b <dir>   Batch process multiple folders or archives in the directory."
    echo "  -h         Show this help message."
}

############# Main Program Starts #############

# Show help if no arguments are provided
if [[ $# -eq 0 ]]; then
    show_help
    exit 0
fi

POSITIONAL_ARGS=()

while getopts ":d:z:f:xb:vh" option; do
    case $option in
        d) MAP_FOLDER="$OPTARG" ;;
        z) ARCHIVE_FILE="$OPTARG" ;;
        f) DIRECT_FILE="$OPTARG" ;;
        v) VERBOSE=1 ;;
        x) GENERATEXML=1 ;;
        b) process_batch "$OPTARG"; exit 0 ;;
        h) show_help; exit 0 ;;
        *) echo "Invalid option: -$OPTARG"; show_help; exit 1 ;;
    esac
done
shift $((OPTIND-1))

# Check dependencies
check_dependencies

# Processing logic based on provided arguments
if [[ -n "$DIRECT_FILE" ]]; then
    validate_file "$DIRECT_FILE"
    INFOMAP_FILE="$DIRECT_FILE"
elif [[ -n "$MAP_FOLDER" ]]; then
    setWorkDir
    processFolder
elif [[ -n "$ARCHIVE_FILE" ]]; then
    processArchiveFile
else
    log_message "No valid input provided"
    exit 1
fi

# Parsing Info_Map.imp file
parseInfoMapFile

# Display map information
showMapInfos

# Generate XML entry if required
if [[ $GENERATEXML -eq 1 ]]; then
    showLookupXMLEntry
fi