#!/bin/bash

LANG=C
CPDB_DIR="/usr/share/grub/cpdb.d/"
DEBUG=false
GRUB_CONFIG="/etc/default/grub"
BACKUP_DIR="/opt/system/resource/grub/grub.bak"

# 定义debug函数
debug() {
    if [ "$DEBUG" = true ]; then
        echo "[DEBUG] $*" >&2
    fi
}

# 获取arch信息
get_arch_info() {
    arch_info=$(uname -m)
    if [ "x$arch_info" != "x" ];then
        echo "arch$arch_info"
    else
        echo "archunknown"
    fi
}

# 获取CPU信息
get_cpu_info() {
    local model_name
    
    model_name=$(grep "model name" "/proc/cpuinfo" | head -n 1 | cut -d: -f2 )
    model_name=$(echo "$model_name" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
    if [ "x$model_name" != "x" ];then
        echo "cpu$model_name"
    else
        echo "cpuunknown"
    fi
    
}

# 获取DMI信息
get_dmi_info() {
    if [ -e "/sys/class/dmi/id/modalias" ];then
        cat /sys/class/dmi/id/modalias
    else
        echo "dmi:unknown:"
    fi
}

# 获取oemstring信息
get_oemstring() {
    oemstring_info=$(dmidecode -t 11 2>/dev/null | grep -i "^[[:space:]]String" | cut -d: -f2- | sed 's/^[[:space:]]*//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
    if [ "x$oemstring_info" != "x" ];then
        echo "oemstring$oemstring_info"
    else
        echo "oemstringunknown"
    fi 
}

# 获取projectInfo信息
get_project_info() {
    if [ -e /etc/.kylin-osinfo ];then
        project_info=$(grep "ProjectInfo" /etc/.kylin-osinfo | cut -d: -f2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') 
    fi
    if [ "x$project_info" != "x" ];then
        echo "projectinfo$project_info"
    else
        echo "projectinfounknown"
    fi
}

#获取完整的cpdb字符串信息，用于匹配数据库中的记录项
get_cpdb_full(){
    cpdb_full="$(get_arch_info):$(get_cpu_info):$(get_dmi_info)$(get_oemstring):$(get_project_info)"
    echo "grub:$cpdb_full" 
}

# 通配符匹配函数
# 使用bash内置的模式匹配功能，直接使用*作为通配符
# [[ string == pattern ]] 中的==操作符支持模式匹配，*被视为通配符
match_with_wildcard() {
    local pattern="$1"
    local string="$2"
    
    # 转换为小写后比较
    local string_lower=$(echo "$string" | tr '[:upper:]' '[:lower:]')
    local pattern_lower=$(echo "$pattern" | tr '[:upper:]' '[:lower:]')
    
    if [[ "$string_lower" == $pattern_lower ]]; then
        return 0
    else
        return 1
    fi
}

#获取匹配的grub参数
get_matched_params(){
    if [ ! -n "$(ls -A "$CPDB_DIR" 2>/dev/null)" ]; then
        debug "$CPDB_DIR 为空, 退出grub-cpdb-manager程序"
        exit 0
    fi

    CPDB_FILE=$(mktemp /tmp/grub.cpdbXXXXXX)
    trap "rm -f '$CPDB_FILE'" EXIT  # 确保脚本退出时删除
    debug "Compiled CPDB to $CPDB_FILE ..."
    cat "$CPDB_DIR"/*.cpdb > "$CPDB_FILE" 2>/dev/null || true
    # cat $CPDB_FILE

    #获取当前机器的完整标识信息
    current_cpdb=$(get_cpdb_full)
    debug  "当前机器cpdb标识信息为: $current_cpdb"
    #初始化命令行参数为空，并开始匹配
    # 存储当前组的规则行
    rules=()
    matched_params=""
    # 逐行读取文件
    while IFS= read -r line || [ -n "$line" ]; do
        # 跳过空行
        # debug "line = $line"
        if [[ -z "$line" ]]; then
            # 遇到空行，清空规则缓存
            rules=()
            continue
        fi
        
        # 跳过注释行
        if [[ "$line" =~ ^#.*$ ]]; then
            continue
        fi
        
        # 检查是否为参数行（以空格开头）
        if [[ "$line" =~ ^[[:space:]]+(.*) ]]; then
            # BASH_REMATCH[1]包含第一个捕获组的内容
            # 正则表达式 ^[[:space:]]+(.*) 中的 (.*) 是第一个捕获组
            # 它捕获了去除行首空白字符后的所有内容
            params="${BASH_REMATCH[1]}"
            
            # 检查之前存储的规则是否有匹配
            for rule in "${rules[@]}"; do
                debug "当前匹配rule: $rule"
                # 使用bash内置的通配符匹配
                if match_with_wildcard "$rule" "$current_cpdb"; then
                    debug "匹配到rules: $rule, 参数为： $params"  # 确保输出到标准输出
                    matched_params=$params
                    break
                fi
            done
            
            # 清空规则缓存
            rules=()
            continue
        fi
        
        # 检查是否为grub规则行
        if [[ "$line" =~ ^grub:.* ]]; then
            # 将规则行添加到数组中
            rules+=("$line")
            continue
        fi
    done < "$CPDB_FILE"

    debug "最终匹配到的参数为："
    echo "$matched_params"
}

usage() {
    cat << EOF
Usage: $0 [OPTIONS] 

Options:
    -h, --help          Show this help message and exit
    -v, --verbose       Enable debug info output
    --arch              Get arch info
    --cpu               Get cpu info
    --dmi               Get dmi info
    --projectinfo       Get project info
    --full              Get full cpdb string
    --getparams         Get grub params of current machine
    --update-default    Update /etc/default/grub
    --get-default       Get default params in /etc/default/grub
    --backup-default    Backup /etc/default/grub in/opt/system/resource/grub/grub.bak
    --restore-default   Restore last grub.bak to /etc/default/grub

EOF
}

# 提取当前 GRUB_CMDLINE_LINUX_DEFAULT 的值
get_current_params() {
    local current_params=""
    
    # 使用 grep 和 sed 提取当前值
    current_params=$(grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' "$GRUB_CONFIG" | \
                     sed -E 's/^GRUB_CMDLINE_LINUX_DEFAULT="([^"]*)"/\1/')
    
    echo "$current_params"
}

# 检查参数是否已存在（基于整个字符串）
check_param_exists() {
    local param="$1"
    local current_params="$2"
    
    # 遍历当前参数列表
    IFS=' ' read -ra current_array <<< "$current_params"
    for current_param in "${current_array[@]}"; do
        if [ "$current_param" = "$param" ]; then
            return 0  # 存在
        fi
    done
    return 1  # 不存在
}

merge_params() {
    local current="$1"
    local extra="$2"
    local result="$current"
    local added_params=()
    
    # 如果当前参数为空，直接返回额外参数
    if [ -z "$current" ]; then
        echo "$extra"
        return
    fi
    
    # 遍历额外参数
    IFS=' ' read -ra extra_array <<< "$extra"
    for extra_param in "${extra_array[@]}"; do
        if check_param_exists "$extra_param" "$result"; then
            debug "Parameter already exists, skipping: $extra_param"
        else
            # 添加新参数到末尾
            result="$result $extra_param"
            added_params+=("$extra_param")
            debug "Adding: $extra_param"
        fi
    done
    
    # 显示添加的参数
    if [ ${#added_params[@]} -gt 0 ]; then
        debug "Added parameters: ${added_params[*]}"
    fi
    
    echo "$result"
}


# 函数: 使用日期作为序号备份
# 格式: grub.bak.20240327_143022
backup_grub_config() {
    # 检查源文件是否存在
    if [ ! -f "$GRUB_CONFIG" ]; then
        debug "GRUB config file not found: $GRUB_CONFIG"
        return 1
    fi
    
    # 创建备份目录（如果不存在）
    if [ ! -d "$BACKUP_DIR" ]; then
        mkdir -p "$BACKUP_DIR"
        if [ $? -ne 0 ]; then
            debug "Failed to create backup directory: $BACKUP_DIR"
            return 1
        fi
        debug "Created backup directory: $BACKUP_DIR"
    fi
    
    # 生成基于日期的序号（精确到秒）
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local backup_file="$BACKUP_DIR/grub.bak.$timestamp"
    
    # 如果同一秒内多次备份，添加后缀
    local counter=1
    while [ -f "$backup_file" ]; do
        backup_file="$BACKUP_DIR/grub.bak.${timestamp}_${counter}"
        ((counter++))
    done
    
    # 执行备份
    cp "$GRUB_CONFIG" "$backup_file"
    
    if [ $? -eq 0 ]; then
        debug "Backup created successfully: $backup_file"               
        return 0
    else
        debug "Failed to create backup: $backup_file"
        return 1
    fi
}

# 函数: 还原最新的备份（基于日期排序）
restore_grub_config() {
    
    # 检查备份目录是否存在
    if [ ! -d "$BACKUP_DIR" ]; then
        debug "Backup directory not found: $BACKUP_DIR"
        return 1
    fi
    
    # 查找最新的备份文件（按日期排序，最新的最后）
    local latest_backup=$(find "$BACKUP_DIR" -maxdepth 1 -name "grub.bak.*" -type f | sort -V | tail -1)
    
    # 检查是否找到备份文件
    if [ -z "$latest_backup" ]; then
        debug "No backup files found in: $BACKUP_DIR"
        return 1
    fi
    
    # 提取备份时间
    local backup_time=$(basename "$latest_backup" | sed 's/grub.bak.//')
    debug "Found latest backup: $latest_backup (created at: $backup_time)"
       
    # 执行还原
    cp "$latest_backup" "$GRUB_CONFIG"
    
    if [ $? -eq 0 ]; then
        debug "Successfully restored: $latest_backup -> $GRUB_CONFIG"        
        return 0
    else
        debug "Failed to restore: $latest_backup"
        return 1
    fi
}


update_default_grub() {

    if [ "$EUID" -ne 0 ]; then
        echo "Error: This option must be run as root (use sudo)" >&2
        exit 1
    fi

    local default_params=$(get_current_params)
    local extra_params=$(get_matched_params)
    new_params=$(merge_params "$default_params" "$extra_params")
    
    # 备份原文件
    backup_grub_config
    if [ $? -ne 0 ]; then
        echo "Failed to create grub.bak, exit"
        exit 0
    fi
    # 转义特殊字符用于 sed
    local escaped_params=$(echo "$new_params" | sed 's/[\/&]/\\&/g')
    
    # 更新配置文件
    sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT=\".*\"/GRUB_CMDLINE_LINUX_DEFAULT=\"$escaped_params\"/" "$GRUB_CONFIG"
}





for arg in "$@"; do
    if [[ "$arg" == "-v" ]] || [[ "$arg" == "--verbose" ]]; then
        DEBUG=true
        break
    fi
done

while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            usage
            shift
            ;;
        -v|--verbose)
            DEBUG=true
            shift
            ;;
        --arch)
            get_arch_info
            shift
            ;;
        --cpu)
            get_cpu_info
            shift
            ;;
        --dmi)
            get_dmi_info
            shift
            ;;
        --projectinfo)
            get_project_info
            shift
            ;;
        --full)
            get_cpdb_full
            shift
            ;;
        --getparams)
            get_matched_params
            shift
            ;;
        --update-default)
            update_default_grub
            shift
            ;;
        --get-default)
            get_current_params
            shift
            ;;
        --restore-default)
            restore_grub_config
            shift
            ;;
        --backup-default)
            backup_grub_config
            shift
            ;;

        *)
            shift
            ;;
    esac
done


