#!/bin/sh

# Copyright (c)2024 John Lawson & Sons
# Licensed under the MIT License

# ANSI color codes
BOLD="\033[1m"
CYAN="\033[36m"
GREEN="\033[32m"
RESET="\033[0m"

json_output=false
param=""

show_help() {
    echo -e "${BOLD}${CYAN}Hardware Revision Script${RESET}"
    echo -e "${GREEN}Version: 1.4.0${RESET}"
    echo
    echo -e "${BOLD}Usage:${RESET} $(basename "$0") [OPTIONS]"
    echo
    echo -e "${BOLD}${CYAN}Options:${RESET}"
    echo -e "  ${GREEN}-j${RESET}, ${GREEN}--json${RESET}           Output in JSON format"
    echo -e "      ${GREEN}--model${RESET}          Display the model"
    echo -e "      ${GREEN}--revision${RESET}       Display the revision code"
    echo -e "      ${GREEN}--serial${RESET}         Display the serial number"
    echo -e "      ${GREEN}--warranty${RESET}       Display warranty void status"
    echo -e "      ${GREEN}--overvoltage${RESET}    Display overvoltage status"
    echo -e "      ${GREEN}--otp-program${RESET}    Display OTP programming status"
    echo -e "      ${GREEN}--otp-read${RESET}       Display OTP read status"
    echo -e "      ${GREEN}--new${RESET}            Display revision format (new-style or old-style)"
    echo -e "      ${GREEN}--memory${RESET}         Display memory size"
    echo -e "      ${GREEN}--manufacturer${RESET}   Display manufacturer"
    echo -e "      ${GREEN}--processor${RESET}      Display processor code"
    echo -e "      ${GREEN}--cpu${RESET}            Display processor name"
    echo -e "      ${GREEN}--type${RESET}           Display type code"
    echo -e "      ${GREEN}--type-name${RESET}      Display board type"
    echo -e "      ${GREEN}--revnum${RESET}         Display revision number"
    echo -e "      ${GREEN}--decoded${RESET}        Display decoded model name"
    echo -e "      ${GREEN}--license${RESET}        Display license information"
    echo -e "  ${GREEN}-v${RESET}, ${GREEN}--version${RESET}        Show version information"
    echo -e "  ${GREEN}-h${RESET}, ${GREEN}--help${RESET}           Show this help message"
}

show_license() {
    echo -e "${BOLD}${CYAN}License:${RESET}"
    echo -e "${GREEN}MIT License${RESET}"
    cat <<EOF

Copyright (c) 2024 John Lawson & Sons

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction...
EOF
}

while [[ "$#" -gt 0 ]]; do
    case "$1" in
        -j|--json)
            json_output=true
            shift
            ;;
        --model|--revision|--serial|--warranty|--new|--memory|--manufacturer|--processor|--cpu|--type|--type-name|--revnum|--decoded|--overvoltage|--otp-program|--otp-read)
            param="$1"
            shift
            ;;
        --license)
            show_license
            exit 0
            ;;
        -v|--version)
            echo "Hardware Revision Script v1.3.0"
            exit 0
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
done

# Gather hardware info
revision=$(grep Revision /proc/cpuinfo | awk '{print $3}')
model=$(grep Model /proc/cpuinfo | cut -d ':' -f2 | sed 's/^ //')
serial=$(grep Serial /proc/cpuinfo | awk '{print $3}')
rev_code=$((16#$revision))

# Bitfield decoding
overvoltage=$(( (rev_code >> 31) & 1 ))
otp_program=$(( (rev_code >> 30) & 1 ))
otp_read=$(( (rev_code >> 29) & 1 ))
warranty=$(( (rev_code >> 25) & 1 ))
new_flag=$(( (rev_code >> 23) & 1 ))
mem_code=$(( (rev_code >> 20) & 7 ))
manufacturer_code=$(( (rev_code >> 16) & 15 ))
processor_code=$(( (rev_code >> 12) & 15 ))
type_code=$(( (rev_code >> 4) & 255 ))
revision_num=$(( rev_code & 15 ))

mem_sizes="256MB 512MB 1GB 2GB 4GB 8GB 16GB"
mem_size=$(echo $mem_sizes | cut -d ' ' -f $(($mem_code + 1)))
[ -z "$mem_size" ] && mem_size="Unknown"

manufacturers="SonyUK Egoman Embest SonyJapan Embest Stadium"
manufacturer=$(echo $manufacturers | cut -d ' ' -f $(($manufacturer_code + 1)))
[ -z "$manufacturer" ] && manufacturer="Unknown"

processors="BCM2835 BCM2836 BCM2837 BCM2711 BCM2712 BCM2712B0 BCM2712C0 Unknown Unknown Unknown Unknown Unknown Unknown Unknown Unknown Unknown"
processor_name=$(echo $processors | cut -d ' ' -f $(($processor_code + 1)))
[ -z "$processor_name" ] && processor_name="Unknown"

types=(
    "A" "B" "A+" "B+" "2B" "Alpha" "CM1" "Unknown" "3B" "Zero"
    "CM3" "Unknown" "Zero W" "3B+" "3A+" "Internal" "CM3+" "4B"
    "Zero 2 W" "400" "CM4" "CM4S" "Internal" "5" "CM5" "500" "CM5 Lite"
)
type_name="Unknown"
[ "$type_code" -lt ${#types[@]} ] && type_name="${types[$type_code]}"

# Dynamic model lookup from external JSON
json_db="$(dirname "$0")/pi_models.json"
if [ -f "$json_db" ]; then
    decoded_model=$(jq -r --arg rev "$revision" '.[$rev] // "Unknown or Old-Style Revision"' "$json_db")
else
    decoded_model="Unknown or Old-Style Revision"
fi

if [ -n "$param" ]; then
    case "$param" in
        --model) echo "$model";;
        --revision) echo "$revision";;
        --serial) echo "$serial";;
        --warranty) echo $([ "$warranty" -eq 1 ] && echo "Yes" || echo "No");;
        --overvoltage) echo $([ "$overvoltage" -eq 1 ] && echo "Disallowed" || echo "Allowed");;
        --otp-program) echo $([ "$otp_program" -eq 1 ] && echo "Disallowed" || echo "Allowed");;
        --otp-read) echo $([ "$otp_read" -eq 1 ] && echo "Disallowed" || echo "Allowed");;
        --new) echo $([ "$new_flag" -eq 1 ] && echo "New-style revision" || echo "Old-style revision");;
        --memory) echo "$mem_size";;
        --manufacturer) echo "$manufacturer";;
        --processor) echo "$processor_code";;
        --cpu) echo "$processor_name";;
        --type) echo "$type_code";;
        --type-name) echo "$type_name";;
        --revnum) echo "$revision_num";;
        --decoded) echo "$decoded_model";;
    esac
elif [ "$json_output" = true ]; then
    cat <<EOF
{
  "model": "$model",
  "revision": "$revision",
  "serial": "$serial",
  "warranty_void": $([ "$warranty" -eq 1 ] && echo true || echo false),
  "revision_style": "$([ "$new_flag" -eq 1 ] && echo "new" || echo "old")",
  "overvoltage": "$([ "$overvoltage" -eq 1 ] && echo "Disallowed" || echo "Allowed")",
  "otp_program": "$([ "$otp_program" -eq 1 ] && echo "Disallowed" || echo "Allowed")",
  "otp_read": "$([ "$otp_read" -eq 1 ] && echo "Disallowed" || echo "Allowed")",
  "memory_size": "$mem_size",
  "manufacturer": "$manufacturer",
  "processor_code": $processor_code,
  "processor_name": "$processor_name",
  "type_code": $type_code,
  "type_name": "$type_name",
  "revision_num": $revision_num,
  "decoded_model": "$decoded_model"
}
EOF
else
    echo -e "${BOLD}${CYAN}Model           :${RESET} ${GREEN}$model${RESET}"
    echo -e "${BOLD}${CYAN}Revision        :${RESET} ${GREEN}$revision${RESET}"
    echo -e "${BOLD}${CYAN}Decoded Model   :${RESET} ${GREEN}$decoded_model${RESET}"
    echo -e "${BOLD}${CYAN}Serial Number   :${RESET} ${GREEN}$serial${RESET}"
    echo -e "${BOLD}${CYAN}Revision Style  :${RESET} ${GREEN}$([ "$new_flag" -eq 1 ] && echo "New-style revision" || echo "Old-style revision")${RESET}"
    echo -e "${BOLD}${CYAN}Warranty Void   :${RESET} ${GREEN}$([ "$warranty" -eq 1 ] && echo "Yes" || echo "No")${RESET}"
    echo -e "${BOLD}${CYAN}Overvoltage     :${RESET} ${GREEN}$([ "$overvoltage" -eq 1 ] && echo "Disallowed" || echo "Allowed")${RESET}"
    echo -e "${BOLD}${CYAN}OTP Program     :${RESET} ${GREEN}$([ "$otp_program" -eq 1 ] && echo "Disallowed" || echo "Allowed")${RESET}"
    echo -e "${BOLD}${CYAN}OTP Read        :${RESET} ${GREEN}$([ "$otp_read" -eq 1 ] && echo "Disallowed" || echo "Allowed")${RESET}"
    echo -e "${BOLD}${CYAN}Memory Size     :${RESET} ${GREEN}$mem_size${RESET}"
    echo -e "${BOLD}${CYAN}Manufacturer    :${RESET} ${GREEN}$manufacturer${RESET}"
    echo -e "${BOLD}${CYAN}Processor Code  :${RESET} ${GREEN}$processor_code${RESET}"
    echo -e "${BOLD}${CYAN}Processor       :${RESET} ${GREEN}$processor_name${RESET}"
    echo -e "${BOLD}${CYAN}Type Code       :${RESET} ${GREEN}$type_code${RESET}"
    echo -e "${BOLD}${CYAN}Type            :${RESET} ${GREEN}$type_name${RESET}"
    echo -e "${BOLD}${CYAN}Revision Num    :${RESET} ${GREEN}$revision_num${RESET}"
fi
