#!/bin/bash

# extuner - 数据收集和专家调优工具
# 全局变量
export LC_ALL=en_US.utf8

cmd_pre=python3
which $cmd_pre >/dev/null 2>&1
if [ $? -eq 0 ]; then
	#echo "use python3"
	:
else
	cmd_pre=python2
	#echo "use python2"
fi

working_dir=/usr/share/extuner/
install_dir=/usr/share/extuner/
output_dir=`pwd`
script_path=`pwd`
VERSION="2.0.0"
SCRIPT_NAME="extuner"
declare -a VALID_COMMANDS=(
    "collection"
    "analysis"
    "profile"
    "apply"
    "tuning"
    "confuse"
    "recommend"
)


# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 工具函数
error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

# 版本信息
show_version() {
    echo "extuner version $VERSION"
    exit 0
}

# 帮助信息
show_help() {
echo "--------------------------------------------------------------------" 
echo "extuner is a data collecting and expert tuning tool for Kylin system"
echo -e 
echo "Usage: " 
echo "    extuner COMMAND [options] "
echo "    extuner {-h|-v}"
echo -e 
echo "Examples:"
echo "    extuner collection --perf --pid -1"
echo "    extuner -v "
echo -e
echo "Commands:"
echo "    collection            collect system data, such as CPU/MEM/NET/IO"
echo "    analysis              collect system data, analysis performance and" 
echo "                          provide tuning advice"
echo "    profile               activate the preset scene profile"
echo "    apply                 apply tuned script"
echo "    tuning                use bayes to get optimal configuration parameters"
echo "    confuse               obfuscated tuned script"
echo "    recommend             recommend parameters"
echo -e
echo "Options:"
echo "    -h, --help            show this help message and exit"
echo "    -v, --version         version"
exit
}

# 检查命令是否有效
validate_command() {
    local cmd="$1"
    for valid_cmd in "${VALID_COMMANDS[@]}"; do
        if [[ "$cmd" == "$valid_cmd" ]]; then
            return 0
        fi
    done
    return 1
}

times_inter(){
    arg=""
    if [[ $# -ge 2  ]];then
    arg+="$1 "
    shift
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -i|--interval)
                if [[ -z "$2" || "$2" == -* ]]; then
                    echo "Error: --interval requires a value"
                    exit 1
                fi
            if ! [[ "$2" =~ ^[0-9]+$ ]]; then
                echo "Error: --interval must be a number"
                exit 1
            fi
                interval="$2"
            sed -i "s/\"interval\" : [0-9]*,/\"interval\" : $interval,/" $working_dir/extuner.conf
                shift 2  # 跳过 --interval 和它的值
                ;;
            -t|--times)
                if [[ -z "$2" || "$2" == -* ]]; then
                    echo "Error: --times requires a value"
                    exit 1
                fi
            if ! [[ "$2" =~ ^[0-9]+$ ]]; then
                    echo "Error: --times must be a number"
                    exit 1
                fi

                times="$2"
            sed -i "s/\"times\" : [0-9]*/\"times\" : $times/" $working_dir/extuner.conf
                shift 2  # 跳过 --times 和它的值
                ;;
            *)
            arg+="$1 "
            shift 
                ;;
        esac
    done
    cmd_exec=$cmd_pre' -B main.py '$arg
    fi

}
# ==================== 子命令函数 ====================
help_collection(){
echo "-------------------------------------------" 
echo "collect system data, such as CPU/MEM/NET/IO"
echo -e 
echo "Usage: " 
echo "    extuner collection [options] "
echo -e 
echo "Example:"
echo "    extuner collection --perf --pid -1"
echo -e
echo "Options:"
echo "    -h, --help                      show this help message and exit"
echo "    -o <path>, --out_path=<path>    Generate extunerData/, include log and reports"
echo "                                    default in /usr/share/extuner/extunerData/"
echo "    -i,--interval VALUE             collection data interval, default is 3s"
echo "    -t,--times VALUE                collection data times,default is 5"
echo "    --perf [PERF_ENABLE_TYPE]       collect perf data,"
echo "                                    default is disabled if not specified"
echo "    --offcpu                        collect offcpu data,"
echo "                                    default is disabled if not specified"
echo -e
echo "Perf required parameters:"
echo "    --pid PERF_PID                  process id to profile,"
echo "                                    -1 to profile the whole system"
echo "    --duration VALUE                duration of perf trace, in seconds"
echo -e
echo "OffCPU required parameters:"
echo "    --offcpu_pid OFFCPU_PID         process id to profile"
echo "    --offcpu_duration VALUE         duration of perf trace, in seconds"
exit
}

help_analysis(){
echo "-------------------------------------------------------------------" 
echo "collect system data, analysis performance and provide tuning advice"
echo -e 
echo "Usage: " 
echo "    extuner analysis [options] "
echo -e 
echo "Example:"
echo "    extuner analysis --perf --pid -1"
echo -e
echo "Options:"
echo "    -h, --help                      show this help message and exit"
echo "    -o <path>, --out_path=<path>    Generate extunerData/, include log and reports"
echo "                                    default in /usr/share/extuner/extunerData/"
echo "    -i,--interval VALUE             collection data interval, default is 3s"
echo "    -t,--times VALUE                collection data times,default is 5"
echo "    --test                          test mode. Default is False. Only developer use"
echo "    --perf [PERF_ENABLE_TYPE]       collect perf data,"
echo "                                    default is disabled if not specified"
echo "    --offcpu                        collect offcpu data,"
echo "                                    default is disabled if not specified"
echo -e
echo "Perf required parameters:"
echo "    --pid PERF_PID                  process id to profile,"
echo "                                    -1 to profile the whole system"
echo "    --duration VALUE                duration of perf trace, in seconds"
echo -e
echo "OffCPU required parameters:"
echo "    --offcpu_pid OFFCPU_PID         process id to profile"
echo "    --offcpu_duration VALUE         duration of perf trace, in seconds"
exit
}

help_profile(){
echo "---------------------------------" 
echo "activate the preset scene profile"
echo -e 
echo "Usage: " 
echo "    extuner profile COMMAND [options] "
echo -e 
echo "Examples:"
echo "    extuner profile mysql_config /etc/"
echo "    extuner profile recover SCENE"
echo "    extuner profile list"
echo -e
echo "Commands:"
echo "    mysql_config CONF_DIR         MySQL scene set, CONF_DIR is MySQL conf path"
echo "    kafka_config CONF_DIR         Kafka scene set, CONF_DIR is Kafka conf path"
echo "    ats_config CONF_DIR           ATS scene set, CONF_DIR is ATS conf path"
echo "    specweb_config CONF_DIR       SPECweb scene set, CONF_DIR is apache conf path"
echo "    dm_config CONF_DIR            DM scene set, CONF_DIR is DM conf path"
echo "    recover SCENE                 recover scene"
echo "    list                          list all profile"
echo -e
echo "Options:"
echo "    -h, --help                    show this help message and exit"
echo "    -o <path>, --out_path=<path>  Generate extunerData/, include log and reports"
echo "                                  default in /usr/share/extuner/extunerData/"

exit
}

help_apply(){
echo "---------------------------------" 
echo "apply the encrypted script"
echo -e 
echo "Usage: " 
echo "    extuner apply SCRIPT"
echo "    extuner apply --enc SCRIPT"
echo -e 
echo "Examples:"
echo "    extuner apply my.extu"
echo "    extuner apply --enc my.sh"
echo -e
echo "Options:"
echo "    SCRIPT                        execute the encrypted script"
echo "    --enc SCRIPT                  encrypt the tuning file"
echo "    -h, --help                    show this help message and exit"
exit
}

help_confuse(){
echo "---------------------------------" 
echo "obfuscated the tuning script"
echo -e 
echo "Usage: " 
echo "    extuner confuse SCRIPT"
echo "    extuner confuse --cnf SCRIPT"
echo -e 
echo "Examples:"
echo "    extuner confuse my.ky"
echo "    extuner confuse --cnf my.sh"
echo -e
echo "Options:"
echo "    SCRIPT                        execute the confused script"
echo "    --cnf SCRIPT                  obfuscated tuning file contents"
echo "    -h, --help                    show this help message and exit"
exit
}

help_tuning(){
echo "---------------------------------"
echo "use bayes to get optimal configuration parameters"
echo -e
echo "Usage: "
echo "    extuner tuning PROJECT_YAML"
echo -e
echo "Examples:"
echo "    extuner tuning gcc_compile.yaml"
echo -e
echo "Options:"
echo "    PROJECT_YAML                  Tuning configuration files"
echo "    -h, --help                    show this help message and exit"
exit
}

help_recommend(){
echo "---------------------------------"
echo "recommend parameters"
echo -e
echo "Usage: "
echo "    extuner recommend SCENE"
echo -e
echo "Examples:"
echo "    extuner recommend mysql"
echo -e
echo "Options:"
echo "    SCENE                         Tuning scene"
echo "    -h, --help                    show this help message and exit"
exit
}

# collection 子命令
collection() {
    
    # 参数检查
    if [[ $# -eq 0 ]]; then
        cmd_exec=$cmd_pre' -B main.py collection'  $arg
    else
        args=$*
        if [[ $args =~ '-h' ]] || [[ $args =~ '--help' ]] 
        then
            help_collection    
            exit 0        
        fi
        # 解析参数
        times_inter collection "$@"
    fi
    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?


}

# analysis 子命令
analysis() {
    # 参数检查
    if [[ $# -eq 0 ]]; then
        cmd_exec=$cmd_pre' -B main.py analysis'  $arg
    else
        args=$*
        if [[ $args =~ '-h' ]] || [[ $args =~ '--help' ]] 
        then
            help_analysis
            exit 0        
        fi
        # 解析参数
        times_inter analysis "$@"
    fi
    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?
}

# profile 子命令
profile() {
    
    if [[ $# -eq 0 ]]; then
        help_profile
        exit 1
    fi
    if [ $# -eq 1 ] && [ 'kafka_config' = $1 ];then
       echo -e "Too few arguments."
    elif [ $# -eq 1 ] && [ 'mysql_config' = $1 ];then
        echo -e "Too few arguments."
    elif [ $# -eq 1 ] && [ 'ats_config' = $1 ];then
        echo -e "Too few arguments."
    elif [ $# -eq 1 ] && [ 'specweb_config' = $1 ];then
        echo -e "Too few arguments."
    elif [ $# -eq 1 ] && [ 'dm_config' = $1 ];then
        echo -e "Too few arguments."
    elif [ $# -eq 1 ] && [ 'list' = $1 ];then
    echo "Profile:"
    echo "      * kafka_config"
    echo "      * mysql_config"
    echo "      * ats_config"
    echo "      * specweb_config"
    echo "      * dm_config"
    exit 0
    elif [ $# -ge 1 ]  && [ '-o' = $1 ];then
    echo "extuner profile: error: argument : invalid choice: '-o' (choose from 'kafka_config', 'mysql_config', 'ats_config', 'specweb_config', 'dm_config', 'recover', 'list')"
    else
        # if [ `pwd` == '/usr/share/extuner' ]; then
            cmd_exec=$cmd_pre' -B main.py profile '$@
        # else
        # 	cmd_exec=$cmd_pre' main.py '$@
        # fi
    fi
    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?
}

# apply 子命令
apply() {
    cmd_exec=$cmd_pre' -B main.py apply '$@"  --PATH=${script_path}"
    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?
}

# 其他子命令的骨架函数
tuning() {
    if [ $# -eq 1 ] ;then
        # 判断路径类型并转换相对路径为绝对路径
        input_path=$1
        if [[ "$input_path" = /* ]]; then
                abs_path="$input_path"
        else
                abs_path="$(pwd)/$input_path"
        fi
        cmd_exec=$cmd_pre' -B main.py tuning '$abs_path' --tuning_outpath='$output_dir
    else
        cmd_exec=$cmd_pre' -B main.py tuning '$@
    fi

    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?
}

confuse() {
    cmd_exec=$cmd_pre' -B main.py confuse '$@"  --PATH=${script_path}"
    pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
    exit $?
}

recommend() {
    if [ $# -eq 1 ] && [ 'list' = $1 ];then
    echo "Profile:"
    echo "      * mysql"
    echo "      * cpu"
    echo "      * io"
    echo "      * net"
    exit 0
    else
        cmd_exec=$cmd_pre' -B main.py recommend '$@
        pushd $install_dir >/dev/null 2>&1 && $cmd_exec && popd >/dev/null 2>&1
        exit $?
    fi
}

# ==================== 主程序 ====================

main() {
    # 处理全局选项
    case "$1" in
        -h|--help)
            show_help
            ;;
        -v|--version)
            show_version
            ;;
        "")
            show_help
            ;;
        *)
            # 检查是否是有效命令
            if validate_command "$1"; then
                cmd="$1"
                shift
                
                # 根据命令调用相应函数
                case "$cmd" in
                    collection)
                        collection "$@"
                        ;;
                    analysis)
                        analysis "$@"
                        ;;
                    profile)
                        profile "$@"
                        ;;
                    apply)
                        apply "$@"
                        ;;
                    tuning)
                        tuning "$@"
                        ;;
                    confuse)
                        confuse "$@"
                        ;;
                    recommend)
                        recommend "$@"
                        ;;
                esac
            else
                error "Unknown command: $1"
                echo "Valid commands: ${VALID_COMMANDS[*]}"
                exit 1
            fi
            ;;
    esac
}


# 运行主程序
main "$@"
