# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>

if "bpy" in locals():
    import importlib
    importlib.reload(defaults)
else:
    from . import action_map_io, defaults

import bpy
from bpy.app.handlers import persistent
from bpy_extras.io_utils import ExportHelper, ImportHelper
import importlib.util
import os.path


def vr_actionset_active_update(context):
    session_state = context.window_manager.xr_session_state
    if not session_state or len(session_state.actionmaps) < 1:
        return

    scene = context.scene

    if scene.vr_actions_use_gamepad and session_state.actionmaps.find(session_state, defaults.VRDefaultActionmaps.GAMEPAD.value):
        session_state.active_action_set_set(context, defaults.VRDefaultActionmaps.GAMEPAD.value)
    else:
        # Use first action map.
        session_state.active_action_set_set(context, session_state.actionmaps[0].name)


def vr_actions_use_gamepad_update(self, context):
    vr_actionset_active_update(context)


@persistent
def vr_create_actions(context: bpy.context):
    context = bpy.context
    session_state = context.window_manager.xr_session_state
    if not session_state:
        return

    # Check if actions are enabled.
    scene = context.scene
    if not scene.vr_actions_enable:
        return

    # Ensure default action maps.
    if not defaults.vr_ensure_default_actionmaps(session_state):  
        return

    for am in session_state.actionmaps:    
        if len(am.actionmap_items) < 1:
            continue

        ok = session_state.action_set_create(context, am)
        if not ok:
            return

        controller_grip_name = ""
        controller_aim_name = ""

        for ami in am.actionmap_items:
            if len(ami.bindings) < 1:
                continue
            
            ok = session_state.action_create(context, am, ami)
            if not ok:
                return

            if ami.type == 'POSE':
                if ami.pose_is_controller_grip:
                    controller_grip_name = ami.name
                if ami.pose_is_controller_aim:
                    controller_aim_name = ami.name

            for amb in ami.bindings:
                # Check for bindings that require OpenXR extensions.
                if amb.name == defaults.VRDefaultActionbindings.REVERB_G2.value:
                   if not scene.vr_actions_enable_reverb_g2:
                       continue
                elif amb.name == defaults.VRDefaultActionbindings.COSMOS.value:
                   if not scene.vr_actions_enable_cosmos:
                       continue
                elif amb.name == defaults.VRDefaultActionbindings.HUAWEI.value:
                   if not scene.vr_actions_enable_huawei:
                       continue

                ok = session_state.action_binding_create(context, am, ami, amb)
                if not ok:
                    return

        # Set controller pose actions.
        if controller_grip_name and controller_aim_name:
            session_state.controller_pose_actions_set(context, am.name, controller_grip_name, controller_aim_name)

    # Set active action set.
    vr_actionset_active_update(context)


def vr_load_actionmaps(session_state, filepath):
    if not os.path.exists(filepath):
        return False

    spec = importlib.util.spec_from_file_location(os.path.basename(filepath), filepath)
    file = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(file)

    action_map_io.actionconfig_init_from_data(session_state, file.actionconfig_data, file.actionconfig_version)

    return True


def vr_save_actionmaps(session_state, filepath, sort=False):
    action_map_io.actionconfig_export_as_data(session_state, filepath, sort=sort)

    print("Saved XR actionmaps: " + filepath)
    
    return True


def register():
    bpy.types.Scene.vr_actions_enable = bpy.props.BoolProperty(
        name="Use Controller Actions",
        description="Enable default VR controller actions, including controller poses and haptics",
        default=True,
    )
    bpy.types.Scene.vr_actions_use_gamepad = bpy.props.BoolProperty(
        description="Use input from gamepad (Microsoft Xbox Controller) instead of motion controllers",
        default=False,
        update=vr_actions_use_gamepad_update,
    )
    bpy.types.Scene.vr_actions_enable_cosmos = bpy.props.BoolProperty(
        description="Enable bindings for the HTC Vive Cosmos controllers. Note that this may not be supported by all OpenXR runtimes",
        default=False,
    )
    bpy.types.Scene.vr_actions_enable_huawei = bpy.props.BoolProperty(
        description="Enable bindings for the Huawei controllers. Note that this may not be supported by all OpenXR runtimes",
        default=False,
    )
    bpy.types.Scene.vr_actions_enable_reverb_g2 = bpy.props.BoolProperty(
        description="Enable bindings for the HP Reverb G2 controllers. Note that this may not be supported by all OpenXR runtimes",
        default=False,
    )

    bpy.app.handlers.xr_session_start_pre.append(vr_create_actions)


def unregister():
    del bpy.types.Scene.vr_actions_enable
    del bpy.types.Scene.vr_actions_use_gamepad
    del bpy.types.Scene.vr_actions_enable_cosmos
    del bpy.types.Scene.vr_actions_enable_huawei
    del bpy.types.Scene.vr_actions_enable_reverb_g2

    bpy.app.handlers.xr_session_start_pre.remove(vr_create_actions)
