###############################################

_green() { printf "\033[32m$*\033[0m"; }
_get_char() { SAVEDSTTY=`stty -g`; stty -echo; stty raw; dd if=/dev/tty bs=1 count=1 2> /dev/null; stty -raw; stty echo; stty $SAVEDSTTY; }
_list() {
    # 渲染tabs行
    text=''
    for ((i = 0; i < ${#menu_tabs[@]}; i++)); do
        _tab=${menu_tabs[$i]}
        [ "$_tab" = "${menu_tabs[$tab_index]}" ] && text="$text $(_green $_tab)" || text="$text $_tab"
    done

    [ "$text" ] && echo -e "   $text\n"

    # 渲染菜单选项行
    for ((i = 0; i < ${#menu_items[@]}; i++)); do
        _item=${menu_items[$i]}
        test "${_item}" = "${menu_items[$item_index]}" && echo -e $(_green " -> ${_item[@]}") || echo "    ${_item[@]}"
    done
}
_key() {
    # 计算新的tab_index和tab
    tab_index=$(($tab_index+$1))
    len=${#menu_tabs[*]}
    test $tab_index -lt 0 && tab_index=$((len - 1))
    test $tab_index -gt $((len - 1)) && tab_index=0
    test $tab_index -lt 0 && tab_index=0
    tab=${menu_tabs[$tab_index]}

    # 计算新的item_index和item
    item_index=$(($item_index+$2))
    len=${#menu_items[*]}
    test $item_index -lt 0 && item_index=$((len - 1))
    test $item_index -gt $((len - 1)) && item_index=0
    test $item_index -lt 0 && item_index=0
    item=${menu_items[$item_index]}

    clear

    pre_hook
    _list
    after_hook

    # 有时会存在pre_hook或after_hook操作了tab或item的情况 需要做一层保护
    tab=${menu_tabs[$tab_index]}
    item=${menu_items[$item_index]}
}

###############################################

function pre_hook() { :; }
function after_hook() { :; }
menu_tabs=()
menu_items=()

# 调用menu方法展开菜单
# 上下左右移动tab或item，回车选中 q Q ctrl-c 退出脚本
menu() {
    _key 0 0
    while :; do
        key=`_get_char`
        case "$key" in
            'q'|'Q'|'') exit 1 ;;
            '') break ;;
            '')
                secondchar=`_get_char`
                thirdchar=`_get_char`
                case "$thirdchar" in
                    A) _key 0 -1 ;;
                    B) _key 0 1 ;;
                    D) _key -1 0 ;;
                    C) _key 1 0 ;;
                esac ;;
        esac
    done
}
