import { Interpolator, base64ToUint8Array, uint8ArrayToBase64, AABB, Vector3, Matrix4x4, Quaternion } from '@zephyr3d/base';
import { AnimationClip } from '../../../animation/animation.js';
import { NodeRotationTrack } from '../../../animation/rotationtrack.js';
import { NodeEulerRotationTrack } from '../../../animation/eulerrotationtrack.js';
import { NodeTranslationTrack } from '../../../animation/translationtrack.js';
import { NodeScaleTrack } from '../../../animation/scaletrack.js';
import { Skeleton } from '../../../animation/skeleton.js';
import { AnimationTrack } from '../../../animation/animationtrack.js';
import { PropertyTrack } from '../../../animation/proptrack.js';
import { MorphTargetTrack } from '../../../animation/morphtrack.js';
import { FixedGeometryCacheTrack } from '../../../animation/fixed_geometry_cache_track.js';
import { BoundingBox } from '../../bounding_volume.js';
import { PCAGeometryCacheTrack } from '../../../animation/pca_geometry_cache_track.js';
import '@zephyr3d/device';
import '../../../animation/joint_dynamics/collision.js';
import '../../../animation/joint_dynamics/solver.js';
import '../../../animation/joint_dynamics/joint_dynamics_system.js';
import { defineProps } from '../types.js';
import '../../../scene/scene.js';
import '../../../values.js';
import '../../../render/render_queue.js';
import '../../../render/primitive.js';
import '../../../material/shader/helper.js';
import '../../../material/lambert.js';
import '../../../material/blinn.js';
import '../../../material/unlit.js';
import '../../../material/particle.js';
import '../../../material/meshmaterial.js';
import '../../../material/grassmaterial.js';
import '../../../material/terrain-cm.js';
import '../../../material/pbrmr.js';
import '../../../material/pbrsg.js';
import '../../../material/pbrblueprint.js';
import '../../../material/sprite.js';
import '../../../material/sprite_std.js';
import '../../blueprint/material/texture.js';
import '../../../render/rendergraph/forward_plus_builder.js';
import '../../../render/sky.js';
import '../../../render/clipmap.js';
import '../../../shaders/atmosphere.js';
import { SceneNode } from '../../../scene/scene_node.js';
import '../../../shadow/shadowmapper.js';
import '../../../scene/mesh.js';
import '../../../scene/basesprite.js';
import '../../../scene/water.js';
import '../../../scene/particlesys.js';
import '../../../scene/batchgroup.js';
import '../../../scene/terrain-cm/terrain-cm.js';
import '../../../scene/terrain-cm/grass.js';
import '../../../scene/raycast_visitor.js';

/** @internal */ function getInterpolatorClass() {
    return {
        ctor: Interpolator,
        name: 'Interpolator',
        createFunc (ctx, init) {
            const inputs = init.inputs ? new Float32Array(base64ToUint8Array(init.inputs).buffer) : new Float32Array();
            const outputs = init.outputs ? new Float32Array(base64ToUint8Array(init.outputs).buffer) : new Float32Array();
            return {
                obj: new Interpolator(init.mode, init.target, inputs, outputs)
            };
        },
        getInitParams (obj) {
            const inputs = obj.inputs instanceof Float32Array ? obj.inputs : obj.inputs ? new Float32Array(obj.inputs) : new Float32Array();
            const outputs = obj.outputs instanceof Float32Array ? obj.outputs : obj.outputs ? new Float32Array(obj.outputs) : new Float32Array();
            return {
                mode: obj.mode,
                target: obj.target,
                inputs: uint8ArrayToBase64(new Uint8Array(inputs.buffer, inputs.byteOffset, inputs.byteLength)),
                outputs: uint8ArrayToBase64(new Uint8Array(outputs.buffer, outputs.byteOffset, outputs.byteLength))
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'Mode',
                    description: 'What kind of method does this interpolator use to interpolate data, possible value is `step` | `linear` | `cubicspline` | `cubicspline-natural`',
                    type: 'string',
                    get (value) {
                        value.str[0] = this.mode;
                    }
                },
                {
                    name: 'Target',
                    description: 'What type of data this interpolator handles, possible value is `number` | `vec2` | `vec3` | `vec4 | `quat`',
                    type: 'string',
                    get (value) {
                        value.str[0] = this.target ?? '';
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getMorphTrackClass() {
    return {
        ctor: MorphTargetTrack,
        name: 'MorphTargetTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'Interpolator',
                    description: 'Interpolator object for this track',
                    type: 'object',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.interpolator;
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                    }
                },
                {
                    name: 'DefaultWeights',
                    description: 'Default weights for this track',
                    type: 'object',
                    get (value) {
                        value.object[0] = this.defaultWeights ?? null;
                    },
                    set (value) {
                        this.defaultWeights = value.object[0] ?? null;
                    }
                },
                {
                    name: 'OriginBoundingBox',
                    description: 'Original bounding box',
                    type: 'object',
                    get (value) {
                        if (!this.originBoundingBox) {
                            value.object[0] = null;
                        } else {
                            const arr = [
                                ...this.originBoundingBox.minPoint,
                                ...this.originBoundingBox.maxPoint
                            ];
                            value.object[0] = arr;
                        }
                    },
                    set (value) {
                        if (!value.object[0]) {
                            this.originBoundingBox = null;
                        } else {
                            const bbox = new AABB();
                            const values = value.object[0];
                            bbox.minPoint.setXYZ(values[0], values[1], values[2]);
                            bbox.maxPoint.setXYZ(values[3], values[4], values[5]);
                            this.originBoundingBox = bbox;
                        }
                    }
                },
                {
                    name: 'BoundingBox',
                    description: 'Bounding box when this track in action',
                    type: 'object',
                    get (value) {
                        if (!this.boundingBox) {
                            value.object[0] = null;
                        } else {
                            const arr = [];
                            for (const box of this.boundingBox){
                                arr.push(...box.minPoint);
                                arr.push(...box.maxPoint);
                            }
                            value.object[0] = arr;
                        }
                    },
                    set (value) {
                        if (!value.object[0]) {
                            this.boundingBox = null;
                        } else {
                            const arr = [];
                            const values = value.object[0];
                            for(let i = 0; i < values.length / 6; i++){
                                arr.push(new BoundingBox(new Vector3(values[i * 6 + 0], values[i * 6 + 1], values[i * 6 + 2]), new Vector3(values[i * 6 + 3], values[i * 6 + 4], values[i * 6 + 5])));
                            }
                            this.boundingBox = arr;
                        }
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                }
            ]);
        }
    };
}
function encodeFloat32Array(values) {
    return uint8ArrayToBase64(new Uint8Array(values.buffer, values.byteOffset, values.byteLength));
}
function decodeFloat32Array(value) {
    return new Float32Array(base64ToUint8Array(value).buffer);
}
function getFixedGeometryCacheTrackClass() {
    return {
        ctor: FixedGeometryCacheTrack,
        name: 'FixedGeometryCacheTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                },
                {
                    name: 'Times',
                    description: 'Keyframe timestamps for this geometry cache track',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = encodeFloat32Array(this.times);
                    },
                    set (value) {
                        this.times = value.str[0] ? decodeFloat32Array(value.str[0]) : new Float32Array();
                    }
                },
                {
                    name: 'Frames',
                    description: 'Serialized geometry cache frames for this track',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.frames.map((frame)=>({
                                positions: encodeFloat32Array(frame.positions),
                                normals: frame.normals ? encodeFloat32Array(frame.normals) : '',
                                bounds: [
                                    frame.boundingBox.minPoint.x,
                                    frame.boundingBox.minPoint.y,
                                    frame.boundingBox.minPoint.z,
                                    frame.boundingBox.maxPoint.x,
                                    frame.boundingBox.maxPoint.y,
                                    frame.boundingBox.maxPoint.z
                                ]
                            }));
                    },
                    set (value) {
                        this.frames = (value.object[0] ?? []).map((frame)=>({
                                positions: decodeFloat32Array(frame.positions),
                                normals: frame.normals ? decodeFloat32Array(frame.normals) : null,
                                boundingBox: new BoundingBox(new Vector3(frame.bounds[0], frame.bounds[1], frame.bounds[2]), new Vector3(frame.bounds[3], frame.bounds[4], frame.bounds[5]))
                            }));
                    }
                }
            ]);
        }
    };
}
function getPCAGeometryCacheTrackClass() {
    return {
        ctor: PCAGeometryCacheTrack,
        name: 'PCAGeometryCacheTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                },
                {
                    name: 'Times',
                    description: 'Keyframe timestamps for this PCA geometry cache track',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = encodeFloat32Array(this.times);
                    },
                    set (value) {
                        this.times = value.str[0] ? decodeFloat32Array(value.str[0]) : new Float32Array();
                    }
                },
                {
                    name: 'Bounds',
                    description: 'Per-frame bounding boxes for the PCA geometry cache',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.bounds;
                    },
                    set (value) {
                        this.bounds = value.object[0] ?? [];
                    }
                },
                {
                    name: 'PositionReference',
                    description: 'Reference position data for the PCA geometry cache',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.positionReference ? encodeFloat32Array(this.positionReference) : '';
                    },
                    set (value) {
                        this.positionReference = value.str[0] ? decodeFloat32Array(value.str[0]) : null;
                    }
                },
                {
                    name: 'PositionMean',
                    description: 'Mean position data for the PCA geometry cache',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = encodeFloat32Array(this.positionMean);
                    },
                    set (value) {
                        this.positionMean = value.str[0] ? decodeFloat32Array(value.str[0]) : new Float32Array();
                    }
                },
                {
                    name: 'PositionBases',
                    description: 'Principal position basis vectors for the PCA geometry cache',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.positionBases.map((item)=>encodeFloat32Array(item));
                    },
                    set (value) {
                        this.positionBases = (value.object[0] ?? []).map((item)=>decodeFloat32Array(item));
                    }
                },
                {
                    name: 'PositionCoefficients',
                    description: 'Per-frame position coefficient data for the PCA geometry cache',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.positionCoefficients.map((item)=>encodeFloat32Array(item));
                    },
                    set (value) {
                        this.positionCoefficients = (value.object[0] ?? []).map((item)=>decodeFloat32Array(item));
                    }
                },
                {
                    name: 'NormalMean',
                    description: 'Mean normal data for the PCA geometry cache',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.normalMean ? encodeFloat32Array(this.normalMean) : '';
                    },
                    set (value) {
                        this.normalMean = value.str[0] ? decodeFloat32Array(value.str[0]) : null;
                    }
                },
                {
                    name: 'NormalBases',
                    description: 'Principal normal basis vectors for the PCA geometry cache',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.normalBases?.map((item)=>encodeFloat32Array(item)) ?? [];
                    },
                    set (value) {
                        this.normalBases = (value.object[0] ?? []).map((item)=>decodeFloat32Array(item)) ?? null;
                    }
                },
                {
                    name: 'NormalCoefficients',
                    description: 'Per-frame normal coefficient data for the PCA geometry cache',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.normalCoefficients?.map((item)=>encodeFloat32Array(item)) ?? [];
                    },
                    set (value) {
                        this.normalCoefficients = (value.object[0] ?? []).map((item)=>decodeFloat32Array(item)) ?? null;
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getNodeRotationTrackClass() {
    return {
        ctor: NodeRotationTrack,
        name: 'NodeRotationTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'Interpolator',
                    description: 'Interpolator object for this track',
                    type: 'object',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.interpolator;
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getNodeEulerRotationTrackClass() {
    return {
        ctor: NodeEulerRotationTrack,
        name: 'NodeEulerRotationTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'Interpolator',
                    description: 'Interpolator object for this track',
                    type: 'object',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.interpolator;
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getNodeTranslationTrackClass() {
    return {
        ctor: NodeTranslationTrack,
        name: 'NodeTranslationTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'Interpolator',
                    description: 'Interpolator object for this track',
                    type: 'object',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.interpolator;
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getNodeScaleTrackClass() {
    return {
        ctor: NodeScaleTrack,
        name: 'NodeScaleTrack',
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'Interpolator',
                    description: 'Interpolator object for this track',
                    type: 'object',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = this.interpolator;
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getPropTrackClass(manager) {
    return {
        ctor: PropertyTrack,
        name: 'PropertyTrack',
        createFunc (ctx, init) {
            return {
                obj: new PropertyTrack(manager.getPropertyByName(init))
            };
        },
        getInitParams (obj) {
            return manager.getPropertyName(obj.getProp());
        },
        getProps () {
            return defineProps([
                {
                    name: 'TrackName',
                    description: 'The track name',
                    type: 'string',
                    options: {
                        label: 'Name'
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        this.name = value.str[0];
                    }
                },
                {
                    name: 'TrackTarget',
                    description: 'Target object this track applys to',
                    type: 'string',
                    options: {
                        label: 'Target'
                    },
                    get (value) {
                        value.str[0] = this.target;
                    },
                    set (value) {
                        this.target = value.str[0];
                    }
                },
                {
                    name: 'TrackProp',
                    description: 'Which property of the target object does this track handle',
                    type: 'string',
                    get (value) {
                        value.str[0] = manager.getPropertyName(this.getProp()) ?? '';
                    }
                },
                {
                    name: 'TrackData',
                    description: 'Interpolator data used by this property track',
                    type: 'object_array',
                    options: {
                        objectTypes: [
                            Interpolator
                        ]
                    },
                    isHidden (index) {
                        return index >= 0;
                    },
                    get (value) {
                        value.object = this.interpolatorAlpha ? [
                            this.interpolator,
                            this.interpolatorAlpha
                        ] : [
                            this.interpolator
                        ];
                    },
                    set (value) {
                        this.interpolator = value.object[0];
                        this.interpolatorAlpha = value.object[1];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getSkeletonClass() {
    return {
        ctor: Skeleton,
        name: 'Skeleton',
        createFunc (ctx, init) {
            const prefabNode = ctx.getPrefabNode() ?? ctx;
            const joints = init.joints.map((id)=>prefabNode.findNodeById(id)).map((node)=>{
                node.jointTypeT = 'static';
                node.jointTypeS = 'static';
                node.jointTypeR = 'static';
                return node;
            });
            const inverseBindMatricesArray = new Float32Array(base64ToUint8Array(init.inverseBindMatrices).buffer);
            const bindPoseArray = new Float32Array(base64ToUint8Array(init.bindPose ?? init.bindPoseMatrices).buffer);
            const inverseBindMatrices = [];
            const bindPose = [];
            for(let i = 0; i < joints.length; i++){
                inverseBindMatrices.push(new Matrix4x4(inverseBindMatricesArray.slice(i * 16, i * 16 + 16)));
                if (!init.bindPose) {
                    const matrix = new Matrix4x4(bindPoseArray.slice(i * 16, i * 16 + 16));
                    const trs = {
                        position: new Vector3(),
                        rotation: new Quaternion(),
                        scale: new Vector3()
                    };
                    matrix.decompose(trs.scale, trs.rotation, trs.position);
                    bindPose.push(trs);
                } else {
                    bindPose.push({
                        position: new Vector3(bindPoseArray[i * 10 + 0], bindPoseArray[i * 10 + 1], bindPoseArray[i * 10 + 2]),
                        rotation: new Quaternion(bindPoseArray[i * 10 + 3], bindPoseArray[i * 10 + 4], bindPoseArray[i * 10 + 5], bindPoseArray[i * 10 + 6]),
                        scale: new Vector3(bindPoseArray[i * 10 + 7], bindPoseArray[i * 10 + 8], bindPoseArray[i * 10 + 9])
                    });
                }
            }
            const skeleton = new Skeleton(joints, inverseBindMatrices, bindPose);
            skeleton.persistentId = init.id;
            return {
                obj: skeleton,
                loadProps: false
            };
        },
        getInitParams (obj) {
            const inverseBindMatrices = obj.inverseBindMatrices.map((v)=>[
                    ...v
                ]).reduce((a, b)=>[
                    ...a,
                    ...b
                ], []);
            const bindPose = obj.bindPose.map((v)=>[
                    ...v.position,
                    ...v.rotation,
                    ...v.scale
                ]).reduce((a, b)=>[
                    ...a,
                    ...b
                ], []);
            return {
                joints: obj.joints.map((joint)=>joint.persistentId),
                inverseBindMatrices: uint8ArrayToBase64(new Uint8Array(new Float32Array(inverseBindMatrices).buffer)),
                bindPose: uint8ArrayToBase64(new Uint8Array(new Float32Array(bindPose).buffer)),
                id: obj.persistentId
            };
        },
        getProps () {
            return [];
        }
    };
}
/** @internal */ function getAnimationClass(manager) {
    return {
        ctor: AnimationClip,
        name: 'AnimationClip',
        createFunc (ctx, init) {
            return {
                obj: ctx.animationSet.get(init) ?? ctx.animationSet.createAnimation(init, false)
            };
        },
        getInitParams (obj) {
            return obj.name;
        },
        getProps () {
            return defineProps([
                {
                    name: 'Name',
                    description: 'The animation name, unique in `AnimationSet`',
                    type: 'string',
                    get (value) {
                        value.str[0] = this.name;
                    }
                },
                {
                    name: 'Duration',
                    description: 'Time duration of the animation in seconds',
                    type: 'float',
                    default: 1,
                    get (value) {
                        value.num[0] = this.timeDuration;
                    },
                    set (value) {
                        this.timeDuration = value.num[0];
                    }
                },
                {
                    name: 'Weight',
                    description: 'Weight of this animation, used in animation blending',
                    type: 'float',
                    default: 1,
                    get (value) {
                        value.num[0] = this.weight;
                    },
                    set (value) {
                        this.weight = value.num[0];
                    }
                },
                {
                    name: 'AutoPlay',
                    description: 'Whether this animation should automatically start playing when model is loaded',
                    type: 'bool',
                    default: false,
                    get (value) {
                        value.bool[0] = this.autoPlay;
                    },
                    set (value) {
                        this.autoPlay = value.bool[0];
                    }
                },
                {
                    name: 'Skeletons',
                    description: 'Skeleton references used by this animation clip',
                    type: 'object',
                    isHidden () {
                        return true;
                    },
                    get (value) {
                        value.object[0] = [
                            ...this.skeletons
                        ];
                    },
                    set (value) {
                        if (!this.skeletons) {
                            this.skeletons = new Set();
                        }
                        for (const val of value.object[0] ?? []){
                            this.skeletons.add(val);
                        }
                    }
                },
                {
                    name: 'Tracks',
                    description: 'Animation tracks of this animation clip',
                    type: 'object_array',
                    options: {
                        edit: 'proptrack',
                        objectTypes: [
                            PropertyTrack
                        ]
                    },
                    readonly: true,
                    isHidden (index, obj) {
                        if (index < 0) {
                            return false;
                        } else {
                            return !(obj instanceof PropertyTrack);
                        }
                    },
                    get (value) {
                        value.object = [];
                        for (const tracks of this.tracks){
                            for (const track of tracks[1]){
                                if (tracks[0] instanceof SceneNode && !(track instanceof PropertyTrack)) {
                                    track.target = tracks[0].persistentId;
                                }
                            }
                            //value.object.push(...tracks[1].filter((track) => track instanceof PropertyTrack));
                            value.object.push(...tracks[1]);
                        }
                    },
                    set (value) {
                        for (const track of value.object){
                            if (track instanceof PropertyTrack) {
                                const targetObj = manager.findAnimationTarget(this._animationSet.model, track);
                                if (targetObj) {
                                    this.addTrack(targetObj, track);
                                }
                            } else if (track instanceof AnimationTrack) {
                                const prefabNode = this._animationSet.model.getPrefabNode() ?? this._animationSet.model;
                                const node = prefabNode.findNodeById(track.target);
                                if (node) {
                                    this.addTrack(node, track);
                                } else {
                                    console.error(`No node found with id = ${track.target}`);
                                }
                            }
                        }
                    },
                    delete (index) {
                        const trackList = [];
                        for (const tracks of this.tracks){
                            trackList.push(...tracks[1].filter((track)=>track instanceof PropertyTrack));
                        }
                        const trackToRemove = trackList[index];
                        if (trackToRemove) {
                            this.deleteTrack(trackToRemove);
                        }
                    }
                }
            ]);
        }
    };
}

export { getAnimationClass, getFixedGeometryCacheTrackClass, getInterpolatorClass, getMorphTrackClass, getNodeEulerRotationTrackClass, getNodeRotationTrackClass, getNodeScaleTrackClass, getNodeTranslationTrackClass, getPCAGeometryCacheTrackClass, getPropTrackClass, getSkeletonClass };
//# sourceMappingURL=animation.js.map
