#  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄       
#  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪    
#  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄
#  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌
#  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪
#                Magicbane Emulator Project © 2013 - 2022
#                           www.magicbane.com

from collections import OrderedDict

from arcane.util import ResStream


class ArcBone:
    def load_binary(self, stream: ResStream):
        self.bone_id = stream.read_dword()
        self.bone_name = stream.read_string()
        self.bone_direction = stream.read_tuple()
        self.bone_length = stream.read_float()
        self.bone_axis = stream.read_tuple()
        self.bone_dof = stream.read_string()
        self.bone_order = stream.read_tuple()
        self.bone_position = stream.read_tuple()
        self.bone_orientation = stream.read_tuple()
        self.bone_u0 = stream.read_bool()
        self.bone_u1 = stream.read_bool()

        num = stream.read_dword()
        self.bone_hierarchy = [ArcBone() for _ in range(num)]
        for bone in self.bone_hierarchy:
            bone.load_binary(stream)

    def save_binary(self, stream: ResStream):
        stream.write_dword(self.bone_id)
        stream.write_string(self.bone_name)
        stream.write_tuple(self.bone_direction)
        stream.write_float(self.bone_length)
        stream.write_tuple(self.bone_axis)
        stream.write_string(self.bone_dof)
        stream.write_tuple(self.bone_order)
        stream.write_tuple(self.bone_position)
        stream.write_tuple(self.bone_orientation)
        stream.write_bool(self.bone_u0)
        stream.write_bool(self.bone_u1)

        stream.write_dword(len(self.bone_hierarchy))
        for bone in self.bone_hierarchy:
            bone.save_binary(stream)

    def load_json(self, data):
        self.bone_id = data['bone_id']
        self.bone_name = data['bone_name']
        self.bone_direction = data['bone_direction']
        self.bone_length = data['bone_length']
        self.bone_axis = data['bone_axis']
        self.bone_dof = data['bone_dof']
        self.bone_order = data['bone_order']
        self.bone_position = data['bone_position']
        self.bone_orientation = data['bone_orientation']
        self.bone_u0 = data['bone_u0']
        self.bone_u1 = data['bone_u1']

        self.bone_hierarchy = []
        for bone_data in data['bone_hierarchy']:
            bone = ArcBone()
            bone.load_json(bone_data)
            self.bone_hierarchy.append(bone)

    def save_json(self):
        data = OrderedDict()
        data['bone_id'] = self.bone_id
        data['bone_name'] = self.bone_name
        data['bone_direction'] = self.bone_direction
        data['bone_length'] = self.bone_length
        data['bone_axis'] = self.bone_axis
        data['bone_dof'] = self.bone_dof
        data['bone_order'] = self.bone_order
        data['bone_position'] = self.bone_position
        data['bone_orientation'] = self.bone_orientation
        data['bone_u0'] = self.bone_u0
        data['bone_u1'] = self.bone_u1

        data['bone_hierarchy'] = []
        for bone in self.bone_hierarchy:
            data['bone_hierarchy'].append(bone.save_json())
        return data


class ArcSkeleton:
    def load_binary(self, stream: ResStream):
        self.skeleton_name = stream.read_string()

        num = stream.read_dword()
        self.skeleton_motion = [
            [
                stream.read_qword(),
                stream.read_qword(),
            ] for _ in range(num)
        ]

        self.skeleton_root = ArcBone()
        self.skeleton_root.load_binary(stream)

    def save_binary(self, stream: ResStream):
        stream.write_string(self.skeleton_name)

        stream.write_dword(len(self.skeleton_motion))
        for i in range(len(self.skeleton_motion)):
            stream.write_qword(self.skeleton_motion[i][0])
            stream.write_qword(self.skeleton_motion[i][1])

        self.skeleton_root.save_binary(stream)

    def load_json(self, data):
        self.skeleton_name = data['skeleton_name']
        self.skeleton_motion = data['skeleton_motion']
        self.skeleton_root = ArcBone()
        self.skeleton_root.load_json(data['skeleton_root'])

    def save_json(self):
        data = OrderedDict()
        data['skeleton_name'] = self.skeleton_name
        data['skeleton_motion'] = self.skeleton_motion
        data['skeleton_root'] = self.skeleton_root.save_json()
        return data