/// @desc 对句柄进行每帧例行初始化
function _handle_init(){
	if (!variable_global_exists("input_handles_list")) global.input_handles_list = [];
	global.input_consumed = {}; 

	var _max_priority = 0;
	for(var i = 0; i < array_length(global.input_handles_list); i++){
		var _ch = global.input_handles_list[i];
		if(_ch.active){
			_max_priority = max(_max_priority, _ch.priority);
		}
	}
	global.current_priority = _max_priority
}

/// @desc Get gamepad and maintain a list through Async System events... Well, ungracefully.
function _gamepad_get(){
	if (!variable_global_exists("gamepads_list")) global.gamepads_list = [];
	if (async_load[? "event_type"] == "gamepad discovered")
	{
	    var _pad = async_load[? "pad_index"];
	    gamepad_set_axis_deadzone(_pad, 0.1);
	    array_push(global.gamepads_list, _pad);
	}
	else if (async_load[? "event_type"] == "gamepad lost")
	{
	    var _pad = async_load[? "pad_index"];
	    var _index = array_get_index(global.gamepads_list, _pad);
	    array_delete(global.gamepads_list, _index, 1);
	}
}

/// @desc 尝试对按键进行消费
/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _try_input_consume(_key, _priority){
	//如果低于最高优先级 且 非debugger级优先级( -1 ), 则拒绝访问
	if(_priority < global.current_priority && _priority != -1) return false;
	
	//同一帧内已经被同级句柄/更高级句柄访问( 消费 ), 则拒绝访问
	var _key_id = string(_key);
	if (struct_exists(global.input_consumed, _key_id)) return false;
	
	return true;
}	

/// @desc 强制消费给定键盘按键
/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
function _force_input_consume(_key){
    var _id = key_get_id(_key);
    global.input_consumed[$ string(_id)] = true;
}

/// @desc 优雅地检测此帧某给定键盘按键是否被按住
/// @desc 使用{HandleName}.kc()而非此函数
/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _kc(_key, _priority = 0)
{
    var _id = key_get_id(_key);
    if (_try_input_consume(_id, _priority) && keyboard_check(_id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}  
/// @desc 优雅地检测此帧某给定键盘按键是否被按住
/// @desc 使用{HandleName}.kcp()而非此函数
/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _kcp( _key, _priority = 0) {
    var _id = key_get_id(_key);
    if (_try_input_consume(_id, _priority) && keyboard_check_pressed(_id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}
/// @desc 优雅地检测此帧某给定键盘按键是否被松开
/// @desc 使用{HandleName}.kcr()而非此函数
/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _kcr(_key, _priority = 0) {
    var _id = key_get_id(_key);
    if (_try_input_consume(_id, _priority) && keyboard_check_released(_id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}

/// @desc Get the first gamepad
function _firstpad(){
	if (variable_global_exists("gamepads_list") && array_length(global.gamepads_list) > 0) {
        return global.gamepads_list[0];
    }
    return 0
}

/// @desc 优雅地检测此帧某给定手柄按键是否被按住
/// @desc 使用{HandleName}.gc()而非此函数
/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _gc(_id, _priority = 0)
{
    var _pad = _firstpad();
    if (_try_input_consume(_id, _priority) && gamepad_button_check(_pad, _id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}  
/// @desc 优雅地检测此帧某给定手柄按键是否被按住
/// @desc 使用{HandleName}.gcp()而非此函数
/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _gcp( _id, _priority = 0) {
    var _pad = _firstpad();
    if (_try_input_consume(_id, _priority) && gamepad_button_check_pressed(_pad, _id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}
/// @desc 优雅地检测此帧某给定手柄按键是否被松开
/// @desc 使用{HandleName}.gcr()而非此函数
/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
/// @param {Constant.Real} _priority 当前句柄的优先级
function _gcr(_id, _priority = 0) {
    var _pad = _firstpad();
    if (_try_input_consume(_id, _priority) && gamepad_button_check_released(_pad, _id)) {
        //判定成功则对按键进行消费
        global.input_consumed[$ string(_id)] = true; 
        return true;
    }
    return false;
}
/// @desc 不优雅地检测此帧 gamepad axis
/// @desc 使用{HandleName}.ga()而非此函数
/// @param {Constant.VirtualKey|Real} _id 检测的手柄 axis
/// @param {Constant.Real} _priority 当前句柄的优先级
function _ga(_id, _priority = 0) {
    var _pad = _firstpad();
    if (_try_input_consume(_id, _priority)) {
        //判定成功则对 axis 进行消费
        //global.input_consumed[$ string(_id)] = true; 
        return gamepad_axis_value(_pad, _id);
    }
    return 0;
}

function input_handle(_reg_name, _priority) constructor {
	reg_name = _reg_name;
	priority = _priority;
	// 理论上，你不应该修改active来控制启用情况，而是使用标准的注册注销流程
	active = true;
	
	if (!variable_global_exists("input_handles_list")) global.input_handles_list = [];
	array_push(global.input_handles_list, self);
	
	/// @desc 优雅地检测此帧某给定键盘按键是否被按住
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
    static kc = function(_key) {
        if (!active) return false;
        // 自动将自己的 priority 传给底层函数
        return _kc(_key, self.priority);
    }

	/// @desc 优雅地检测此帧某给定键盘按键是否被按住
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
    static kcp = function(_key) {
        if (!active) return false;
        return _kcp(_key, self.priority);
    }

	/// @desc 优雅地检测此帧某给定键盘按键是否被松开
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _key 检测的键盘按键
    static kcr = function(_key) {
        if (!active) return false;
        return _kcr(_key, self.priority);
    }
		
	/// @desc 优雅地检测此帧某给定手柄按键是否被按住
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
    static gc = function(_id) {
        if (!active) return false;
        // 自动将自己的 priority 传给底层函数
        return _gc(_id, self.priority);
    }

	/// @desc 优雅地检测此帧某给定手柄按键是否被按住
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
    static gcp = function(_id) {
        if (!active) return false;
        return _gcp(_id, self.priority);
    }

	/// @desc 优雅地检测此帧某给定手柄按键是否被松开
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
    static gcr = function(_id) {
        if (!active) return false;
        return _gcr(_id, self.priority);
    }
	
	/// @desc 不优雅地检测此帧某给定手柄按键是否被松开
	/// @desc priority继承自其句柄
	/// @param {Constant.VirtualKey|Real} _id 检测的手柄按键
    static ga = function(_id) {
        if (!active) return false;
        return _ga(_id, self.priority);
    }
	
	/// @desc 注销当前句柄
    static destroy = function() {
		if (!variable_global_exists("input_handles_list")) return;
		
        var _len = array_length(global.input_handles_list);
        for (var i = 0; i < _len; i++) {
            if (global.input_handles_list[i] == self) {
                array_delete(global.input_handles_list, i, 1);
                break;
            }
        }
    }
}

/// @desc 通过注册名寻找句柄
/// @param {String} _reg_name 注册名
function input_handle_find(_reg_name) {
    var _len = array_length(global.input_handles_index);
    for (var i = 0; i < _len; i++) {
        if (global.input_handles_list[i].reg_name == _reg_name) {
            return global.input_handles_list[i];
        }
    }
    return undefined;
}

/// @desc 创建空句柄
function create_dummy_handle(){
	global.handle_dummy = {
        kc:  function() { return false; },
        kcp: function() { return false; },
        kcr: function() { return false; },
        gc:  function() { return false; },
        gcp: function() { return false; },
        gcr: function() { return false; },
        ga:  function() { return false; },
        destroy: function() {  },
        active: false,
        priority: -9999
    };
}

/// @desc 自动化注册句柄，核心部分等效于 _new_handle = new input_handle(_reg_name, _priority)
/// @param {String} _func_name handle变量名
/// @param {String} _reg_name 注册名
/// @param {Real} _priority 优先级
function autoreg_handle(_func_name, _reg_name, _priority){
	var _found = false;
	var _len = array_length(global.input_handles_index);
	for (var i = 0; i < _len; i++) {
		if (global.input_handles_index[i] == _func_name) {
			_found = true;
			break;
		}
	}
	if (!_found) throw("ERROR:尝试注册的变量名'" + _func_name + "'不在input_handles_index内")
	
	var _current = variable_instance_get(id, _func_name);
    
    // 如果已经存在，则销毁旧的
    if (is_struct(_current) && _current != global.handle_dummy) {
        _current.destroy();
    }
	var _new_handle = new input_handle(_reg_name, _priority);
	variable_instance_set(id, _func_name, _new_handle);
}

/// @desc 自动化注销句柄
/// @param {String} _func_name handle变量名
function autodel_handle(_func_name){
    var _handle = variable_instance_get(id, _func_name);
    if (is_struct(_handle) && _handle != global.handle_dummy) {
        if (variable_struct_exists(_handle, "destroy")) {
            _handle.destroy(); 
        }
    }
	variable_instance_set(id, _func_name, global.handle_dummy);
}