import { Container, Sprite } from "../2d/display";
import { IBoneData, Bone } from "./Bone";
import { Texture } from "../2d/texture";

import { AnimationClip } from "../2d/AnimationClip";
import { AnimationManager } from "../2d/AnimationManager";
import { Slot, ISlotData } from "./Slot";
import { Skin } from "./Skin";
import { RegionAttachment } from "./attachment/RegionAttachment";
import { MeshAttachment } from "./attachment/MeshAttachment";
import { Transform } from "../2d/math";
import { Mesh } from "../2d/mesh";

import { rgb2hex } from "../2d/utils";
import { IBoneAniData, SpineBoneAniTrack } from "./animation/SpineBoneAniTrack";
import { IColorAniData, SpineColorAniTrack } from "./animation/SpineColorAniTrack";
import { IDeformAniData, SpineDeformAniTrack } from "./animation/SpineDeformAniTrack";
import { IAttachmentAniData, AttachmentAniTrack } from "./animation/AttachmentAniTrack";
import { IDrawOrderAniData, DrawOrderAniTrack } from "./animation/DrawOrderAniTrack";
import { newArray } from "./animation/utils";
import { SpineAniClip, SpineAniManager } from "./SpineAniManager";
import { IkConstraint } from "./constraint/IkConstraint";
import { ClippingAttachment } from "./attachment/ClippingAttachment";
import { VertexAttachment } from "./attachment/Attachment";
import { Graphics } from "../2d/graphics";


export interface ISkeletonData {
    skeleton: {
        //图片相对路径，不用自行匹配
        images: string,
        //spine版本
        spine: number
    },
    //纹理数据
    textures?: { [key: string]: Texture },
    bones: IBoneData[],
    //附着的皮肤
    skins: { [key: string]: { [key: string]: { [key: string]: ISkinData } } },
    slots: ISlotData[],
    animations: {
        [key: string]: {
            bones: {
                [key: string]: {
                    rotate: IBoneAniData[],
                    translate: IBoneAniData[]
                    scale: IBoneAniData[]
                    shear: IBoneAniData[]
                }
            },
            //网格变形数据
            deform: {
                [key: string]: {
                    [key: string]: {
                        [key: string]: IDeformAniData[]
                    }
                }
            },
            slots: {
                [key: string]: {
                    //附着皮肤修改
                    attachment: IAttachmentAniData[],
                    //颜色变化
                    color: IColorAniData[]
                }
            },
            drawOrder: IDrawOrderAniData[]
            ik: { [key: string]: { time: number, mix: number, bendPositive: boolean }[] }
        }
    },
    transform: {
        bones: string[]
        name: string
        order: number
        rotateMix: number
        rotation: number
        scaleMix: number
        shearMix: number
        target: string
        translateMix: number
    }[],
    ik: {
        bendPositive: boolean,
        bones: string[]
        mix: number
        name: string
        order: number
        target: string,
        uniform: boolean
        softness: number
        bendDirection: boolean
        compress: boolean
        stretch: boolean
    }[]
}

interface ISkinData {
    path?: string,//图片路径，没有用name
    //类型，没有就是region图片
    type?: SkinType,
    width?: number,//默认0
    height?: number,//默认0
    //图片的数据
    x?: number,//默认0
    y?: number,//默认0
    scaleX?: number,//默认1
    scaleY?: number,//默认1
    rotation?: number,//默认0

    //网格数据
    edges: number[],//暂时没用到
    hull: number,//暂时没用到
    triangles: number[]
    uvs: number[],//uv标准顶点长度

    vertices: number[],//
    //遮罩的数据
    color: string,//"ce3a3aff"
    end: string,//"head-bb"
    vertexCount: number,

}


enum SkinType {
    //区域，纯图片，没有类型字段就是默认region
    region = "region",
    mesh = "mesh",
    //遮罩
    clipping = "clipping",
    linkedmesh = "linkedmesh",
    path = "path",
    point = "point"
}

const tempRgb = [0, 0, 0];
/**
 * TODO 性能略差，到时考虑单独写着色器，和3d那样断批处理，单独开着色器，传骨骼矩阵等等，绘制Mesh
 * 参考spine runtime和three
 * 事件暂时不需要，基本都走播放回调，或者到时把eventTrack和监听加进来，
 */
export class Spine extends Container {
    //单独处理bones的容器
    private boneContainer: Container;
    //记录个数组，为了索引和查找
    bones: Bone[];
    //ik约束
    ikConstraints: IkConstraint[];
    //骨骼计算顺序，后续可能也加入约束
    orderCalculations: Bone[];
    skins: Skin[];
    //当前皮肤
    skin: Skin;
    //默认皮肤
    defaultSkin: Skin;
    //单独处理插槽的容器，这部分不应该进节点计算矩阵，但要进节点，为了渲染
    private slotContainer: Container;
    //为了索引和查找，slotContainer里的位置会变
    slots: Slot[];
    //
    tempClipContainers: Container[];
    //真实的绘制顺序
    drawOrder: Slot[];
    animationManager: SpineAniManager;

    constructor(private spineData: ISkeletonData, showBones: boolean = false) {
        super();
        this._instanceType = "Spine";
        //数据赋值
        var data = spineData;
        //如果没有纹理，把骨骼加上
        if (!spineData.textures) showBones = true;
        //自行反向？
        this.scaleY = -1;
        //骨骼处理
        if (data.bones) {
            this.boneContainer = this.addChild(new Container());
            this.bones = [];
            //先看看骨骼
            for (var i = 0; i < data.bones.length; i++) {
                //需要显示骨骼才传入，
                let bone = new Bone(data.bones[i], showBones ? this.boneContainer : null)
                this.bones.push(bone)
                if (!bone.data.parent) {
                    this.boneContainer.addChild(bone);
                } else {
                    var pb = this.findBone(bone.data.parent)
                    if (pb) pb.addChild(bone);
                }
                // let boneData = data.bones[i];
                // let bone: Bone;
                // if (!boneData.parent)
                //     bone = new Bone(boneData);
                // else {
                //     var pb = this.findBone(boneData.parent)
                //     bone = new Bone(boneData, pb);
                //     pb.children.push(bone);
                // }
                // this.bones.push(bone);
            }
            //排序
            // this.orderCalculations = [];
            // for (var i = 0; i < this.bones.length; i++)this.sortBone(this.bones[i]);
        }
        //ik约束,还有各种约束，到时order有用
        if (data.ik) {
            this.ikConstraints = [];
            data.ik.forEach((ik) => {
                var ikConstraint = new IkConstraint(
                    this.findBone(ik.target),
                    ik.bones.map((b) => this.findBone(b))
                );
                ikConstraint.mix = ik.mix === undefined ? 1 : ik.mix;
                ikConstraint.softness = ik.softness === undefined ? 0 : ik.softness;
                ikConstraint.bendDirection = (ik.bendDirection === undefined ? true : ik.bendDirection) ? 1 : -1;
                ikConstraint.compress = ik.compress === undefined ? false : ik.compress;
                ikConstraint.stretch = ik.stretch === undefined ? false : ik.stretch;
                ikConstraint.uniform = ik.uniform === undefined ? false : ik.uniform;

                this.ikConstraints.push(ikConstraint)
            })
        }
        //插槽
        if (data.slots) {
            this.slotContainer = this.addChildAt(new Container(), 0)
            this.slots = [];
            this.tempClipContainers = [];
            for (let i = 0; i < data.slots.length; i++) {
                let slotMap = data.slots[i];
                let bone = this.findBone(slotMap.bone);
                this.slots.push(
                    this.slotContainer.addChild(new Slot(bone, slotMap, this))
                )
                this.tempClipContainers.push(null);//新加
                // if(slotMap.attachment){//下面处理
                //     
                // }
            }
            //复制一份
            this.drawOrder = this.slots.slice();
        }
        //皮肤数据
        if (data.skins) {
            this.skins = []
            let orginSkins = data.skins;
            //是数组，那就转一下
            if (Object.prototype.toString.call(data.skins) === '[object Array]') {
                orginSkins = {};
                //@ts-ignore
                data.skins.forEach(e => {
                    orginSkins[e.name] = e.attachments
                });
            }
            for (var skinName in orginSkins) {
                var skinMap = orginSkins[skinName];
                var skin = new Skin(skinName);
                for (var slotName in skinMap) {
                    var slotIndex = this.findSlotIndex(slotName);
                    if (slotIndex == -1)
                        throw new Error("Slot not found: " + slotName);
                    var slotMap = skinMap[slotName];
                    for (var entryName in slotMap) {
                        var attachment = this.readAttachment(slotMap[entryName], skin, slotIndex, entryName, null);
                        if (attachment != null)
                            skin.addAttachment(slotIndex, entryName, attachment);
                    }
                }
                this.skins.push(skin);
                if (skin.name == "default") this.defaultSkin = skin;
            }
            //默认皮肤
            // this.skin = this.defaultSkin;
        }
        //动画数据
        if (data.animations) {
            var animationClips = [];
            //一级是总动画
            for (let aniName in data.animations) {
                //这里开始收集track;
                let tracks = [];
                let duration = 0;
                let mm = data.animations[aniName];
                //骨骼，基本没啥问题了
                if (mm.bones) {
                    for (let aboneName in mm.bones) {
                        let boneAniData = mm.bones[aboneName]
                        let bone = this.findBone(aboneName);
                        for (let boneAniName in boneAniData) {
                            //@ts-ignore
                            let boneTrack = new SpineBoneAniTrack(bone, boneAniName, boneAniData[boneAniName]);
                            tracks.push(boneTrack);
                            duration = Math.max(duration, boneTrack.times[boneTrack.times.length - 1].time);
                        }
                    }
                }
                //插槽的切换
                if (mm.slots) {
                    for (let slotName in mm.slots) {
                        let slotMap = mm.slots[slotName];
                        let slotIndex = this.findSlotIndex(slotName);
                        let slot = this.slots[slotIndex]
                        for (let timelineName in slotMap) {
                            let timelineMap = slotMap[timelineName];
                            let endTime = timelineMap[timelineMap.length - 1].time;
                            if (timelineName == "attachment") {
                                tracks.push(
                                    // 处理下
                                    new AttachmentAniTrack(
                                        slot,
                                        timelineMap,
                                        this
                                    )
                                );
                                duration = Math.max(duration, endTime || 0);
                            }
                            else if (timelineName == "color") {
                                tracks.push(new SpineColorAniTrack(slot, timelineMap));
                                duration = Math.max(duration, endTime || 0);
                            }
                            // else if (timelineName == "twoColor") {
                            //     var timeline = new core.TwoColorTimeline(timelineMap.length);
                            //     timeline.slotIndex = slotIndex;
                            //     var frameIndex = 0;
                            //     for (var i = 0; i < timelineMap.length; i++) {
                            //         var valueMap = timelineMap[i];
                            //         var light = new core.Color();
                            //         var dark = new core.Color();
                            //         light.setFromString(valueMap.light);
                            //         dark.setFromString(valueMap.dark);
                            //         timeline.setFrame(frameIndex, valueMap.time, light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b);
                            //         this.readCurve(valueMap, timeline, frameIndex);
                            //         frameIndex++;
                            //     }
                            //     timelines.push(timeline);
                            //     duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * core.TwoColorTimeline.ENTRIES]);
                            // }
                            // else
                            //     throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
                        }
                    }
                }
                //变形
                if (mm.deform) {
                    for (var deformName in mm.deform) {
                        var deformMap = mm.deform[deformName];
                        //主套皮肤
                        let skin = this.findSkin(deformName);
                        for (var slotName in deformMap) {
                            let slotMap = deformMap[slotName];
                            let slotIndex = this.findSlotIndex(slotName)
                            let slot = this.slots[slotIndex] //this.findSlot(slotName);
                            for (var timelineName in slotMap) {
                                var timelineMap = slotMap[timelineName];
                                let attachment: MeshAttachment = skin.getAttachment(slotIndex, timelineName);
                                let deformTrack = new SpineDeformAniTrack(slot, attachment, timelineMap);
                                tracks.push(deformTrack);
                                duration = Math.max(duration, deformTrack.frameTimes[deformTrack.frameTimes.length - 1]);
                            }
                        }
                    }
                }
                //顺序mm
                var drawOrderNode = mm.drawOrder //|| mm["draworder"];
                if (drawOrderNode) {//只会有一个
                    var dat = new DrawOrderAniTrack(
                        this.slots,
                        this.drawOrder,
                        drawOrderNode.map((d: IDrawOrderAniData) => {
                            return {
                                time: d.time || 0,
                                drawOrder: (() => {
                                    let offsets = d.offsets
                                    if (!offsets) return null;
                                    var slotCount = this.slots.length;
                                    var drawOrder = newArray(slotCount, -1);
                                    var unchanged = newArray(slotCount - offsets.length, 0);
                                    var originalIndex = 0, unchangedIndex = 0;
                                    for (var i = 0; i < offsets.length; i++) {
                                        var offsetMap = offsets[i];
                                        var slotIndex = this.findSlotIndex(offsetMap.slot);
                                        while (originalIndex != slotIndex)
                                            unchanged[unchangedIndex++] = originalIndex++;
                                        drawOrder[originalIndex + offsetMap.offset] = originalIndex++;
                                    }
                                    while (originalIndex < slotCount)
                                        unchanged[unchangedIndex++] = originalIndex++;
                                    for (var i = slotCount - 1; i >= 0; i--)
                                        if (drawOrder[i] == -1)
                                            drawOrder[i] = unchanged[--unchangedIndex];
                                    return drawOrder
                                })()
                            }
                        })
                    );
                    tracks.push(dat);
                    duration = Math.max(duration, dat.times[dat.times.length - 1].time);
                }
                //事件的先不管
                // if(mm.events){}
                var clip = new SpineAniClip(tracks, duration)
                clip.name = aniName;
                animationClips.push(clip);
            }
            //动画都放进manager，到时和AnimationClip都要改，传入mix和blend，现在先不管
            this.animationManager = new SpineAniManager(animationClips)
        }

        //默认皮肤搞一次
        if (data.slots) {
            //默认的皮肤先干
            for (let i = 0; i < this.slots.length; i++) {
                let slot: Slot = this.slots[i]
                if (slot.data.attachment) {
                    let attachment = this.defaultSkin.getAttachment(i, slot.data.attachment)
                    // slot.originAttachment = attachment;//原始的赋值一个
                    slot.setAttachment(attachment)
                    if (attachment instanceof RegionAttachment) {
                        var spriteName = attachment.name;
                        var sprite = this.createSprite(slot, attachment, spriteName);
                        slot.currentSprite = sprite;
                        slot.currentSpriteName = spriteName;
                        slot.addChild(sprite);
                    }
                    else if (attachment instanceof MeshAttachment) {
                        var mesh = this.createMesh(slot, attachment);
                        slot.currentMesh = mesh;
                        slot.currentMeshName = attachment.name;
                        slot.addChild(mesh);
                    }
                    else if (attachment instanceof ClippingAttachment) {
                        this.createGraphics(slot, attachment);
                        slot.addChild(slot.clippingContainer);
                        slot.addChild(slot.currentGraphics);
                    }
                }

            }
        }
    }
    private findBone(name: string): Bone {
        var bones = this.bones;
        for (var i = 0, n = bones.length; i < n; i++) {
            var bone = bones[i];
            if (bone.name == name) return bone;
        }
        return null;
    }

    private sortBone(bone: Bone) {
        if (bone.sorted) return;
        var parent = bone.parent;
        if (parent) this.sortBone(parent as Bone);
        bone.sorted = true;
        this.orderCalculations.push(bone);
    };
    /**
     * 根据插槽名字或者插槽
     * @param slotName 
     */
    findSlot(slotName: string): Slot {
        var arr = this.slots;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i].name == slotName) return arr[i];
        }
        return null
    }
    private findSlotIndex(slotName: string) {
        var arr = this.slots;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i].name == slotName) return i;
        }
        return -1
    }

    private findSkin(skinName: string) {
        var skins = this.skins;
        for (var i = 0, n = skins.length; i < n; i++) {
            var skin = skins[i];
            if (skin.name == skinName)
                return skin;
        }
        return null;
    }

    getAttachment(slotIndex: number, attachmentName: string) {
        if (this.skin) {
            var at = this.skin.getAttachment(slotIndex, attachmentName);
            if (at) return at;
        }
        if (this.defaultSkin) {
            var at = this.defaultSkin.getAttachment(slotIndex, attachmentName);
            if (at) return at;
        }
        return null;
        // return (this.skin || this.defaultSkin).getAttachment(slotIndex, attachmentName) || null
    }

    private lastTime: number
    update() {
        var now = Date.now()
        var delta = this.lastTime ? (now - this.lastTime) * 0.001 : 0.01667
        this.lastTime = now;
        //动画更新，比如bone的基础属性
        this.animationManager.update(delta);
        // this.updateSlots();
        // this.updateDrawOrder();放到下面执行
        super.update();
    }
    //重写。只有骨骼的进入计算，插槽的根着骨骼世界矩阵计算
    updateTransform() {
        //自己先算
        this.transform.updateWorldMatrix(this.parent.transform);
        this._worldAlpha = this.alpha * this.parent._worldAlpha;
        //保证先计算骨骼的
        this.boneContainer && this.boneContainer.updateTransform();
        //计算ik约束的
        this.ikConstraints && this.ikConstraints.forEach((ik) => { ik.update() });
        // for (var i = 0; i < this.orderCalculations.length; i++)this.orderCalculations[i].update();
        this.updateSlots();
        this.updateDrawOrder();
        this.slotContainer.updateTransform();
    }
    //显示对象呈现
    private updateSlots() {
        for (var i = 0, n = this.slots.length; i < n; i++) {
            var slot: Slot = this.slots[i];
            var attachment = slot.attachment;
            if (!attachment) {
                slot.visible = false;
                continue;
            }
            var attColor = (attachment as RegionAttachment).color;
            if (attachment instanceof RegionAttachment) {
                if (slot.currentMesh) {
                    slot.currentMesh.visible = false;
                    slot.currentMesh = null;
                    slot.currentMeshName = undefined;
                }
                if (!slot.currentSpriteName || slot.currentSpriteName !== attachment.name) {
                    var spriteName = attachment.name;
                    if (slot.currentSprite) {
                        slot.currentSprite.visible = false;
                    }
                    slot.sprites = slot.sprites || {};
                    if (slot.sprites[spriteName] !== undefined) {
                        slot.sprites[spriteName].visible = true;
                    }
                    else {
                        var sprite = this.createSprite(slot, attachment, spriteName);
                        slot.addChild(sprite);
                    }
                    slot.currentSprite = slot.sprites[spriteName];
                    slot.currentSpriteName = spriteName;

                }
                var transform = slot.transform;
                // slot.bone.worldMatrix.decompose(transform);
                slot.bone.matrix.decompose(transform);
                transform._localID++;

                tempRgb[0] = slot.color.r * attColor.r;
                tempRgb[1] = slot.color.g * attColor.g;
                tempRgb[2] = slot.color.b * attColor.b;
                slot.currentSprite.tint = rgb2hex(tempRgb);
                // slot.currentSprite.blendMode = slot.blendMode;
            }
            else if (attachment instanceof MeshAttachment) {
                if (slot.currentSprite) {
                    slot.currentSprite.visible = false;
                    slot.currentSprite = null;
                    slot.currentSpriteName = undefined;
                    //切换一个初始的transform
                    var transform = new Transform();
                    transform._parentID = -1;
                    transform._worldID = slot.transform._worldID;
                    slot.transform = transform;
                }
                if (!slot.currentMeshName || slot.currentMeshName !== attachment.name) {
                    var meshName = attachment.name;
                    if (slot.currentMesh) {
                        slot.currentMesh.visible = false;
                    }
                    slot.meshes = slot.meshes || {};
                    if (slot.meshes[meshName] !== undefined) {
                        slot.meshes[meshName].visible = true;
                    }
                    else {
                        var mesh = this.createMesh(slot, attachment);
                        slot.addChild(mesh);
                    }
                    slot.currentMesh = slot.meshes[meshName];
                    slot.currentMeshName = meshName;
                }
                attachment.computeWorldVerticesOld(slot, slot.currentMesh._vertices, this.bones);
                //@ts-ignore
                slot.currentMesh._vertexDirty++
                //颜色处理
                tempRgb[0] = slot.color.r * attColor.r;
                tempRgb[1] = slot.color.g * attColor.g;
                tempRgb[2] = slot.color.b * attColor.b;
                slot.currentMesh.tint = rgb2hex(tempRgb);
                // slot.currentMesh.blendMode = slot.blendMode;
            }
            else if (attachment instanceof ClippingAttachment) {
                if (!slot.currentGraphics) {
                    this.createGraphics(slot, attachment);
                    slot.addChild(slot.clippingContainer);
                    slot.addChild(slot.currentGraphics);
                }
                this.updateGraphics(slot, attachment);
            }
            else {
                slot.visible = false;
                continue;
            }
            slot.visible = true;
            slot.alpha = slot.color.a;
        }
    }
    /**
     * 遮罩的先不管，有了再说
     */
    private updateDrawOrder() {
        var drawOrder = this.drawOrder;
        var clippingAttachment: ClippingAttachment = null;
        var clippingContainer: Container = null;
        for (var i = 0, n = drawOrder.length; i < n; i++) {
            let index = this.slots.indexOf(drawOrder[i])
            let slot = this.slots[index];
            // if (!clippingContainer) {
            //     if (slot.parent && slot.parent !== this.slotContainer) {
            //         // slot.parent.removeChild(slot);
            //         // slot.parent = this;
            //     }
            // }
            if (slot.currentGraphics && slot.attachment) {
                clippingContainer = slot.clippingContainer;
                clippingAttachment = slot.attachment as ClippingAttachment;
                // clippingContainer.children.length = 0;
                clippingContainer.removeAllChildren();
                // this.slotContainer.children[i] = slot;
                this.slotContainer.addChildAt(slot, i);
                if (clippingAttachment.endSlot == slot.data) {
                    clippingAttachment.endSlot = null;
                }
            }
            else {
                if (clippingContainer) {
                    var c = this.tempClipContainers[i];
                    if (!c) {
                        c = this.tempClipContainers[i] = new Container();
                        c.visible = false;
                    }
                    // this.slotContainer.children[i] = c;
                    this.slotContainer.addChildAt(c, i);
                    // slot.parent = null;
                    clippingContainer.addChild(slot);
                    if (clippingAttachment.endSlot == slot.data) {
                        // clippingContainer.renderable = true;
                        clippingContainer = null;
                        clippingAttachment = null;
                    }
                }
                else {
                    // this.children[i] = slotContainer;
                    this.slotContainer.addChildAt(slot,i)//.children[i] = slot;
                }
            }
        }
    }

    private readAttachment(map: ISkinData, skin, slotIndex, name, skeletonData) {
        var textures = this.spineData.textures;
        //@ts-ignore
        name = map.name || name
        var type = map.type || SkinType.region
        switch (type) {
            case SkinType.region: {
                var region = new RegionAttachment(
                    name,
                    map.x,
                    map.y,
                    map.scaleX,
                    map.scaleY,
                    map.rotation,
                    map.width,
                    map.height,
                    textures && textures[map.path || name]
                );
                if (map.color) region.color.setFromString(map.color);
                return region;
            }
            case SkinType.mesh: {
                var mesh = new MeshAttachment(name);
                mesh.texture = textures && textures[map.path || name];
                // var color = this.getValue(map, "color", null);
                // if (color != null)
                //     mesh.color.setFromString(color);
                var uvs = map.uvs;
                this.readVertices(map, mesh, uvs.length);
                mesh.triangles = map.triangles;
                mesh.regionUVs = new Float32Array(uvs);
                mesh.hullLength = map.hull * 2 || 0
                return mesh;
            }
            case SkinType.clipping: {
                var clip = new ClippingAttachment(name);
                if (clip == null)
                    return null;
                var end = map.end;//不用null判断，end不会是0或false
                if (end) {
                    var slot = this.findSlot(end);
                    if (slot == null)
                        throw new Error("Clipping end slot not found: " + end);
                    clip.endSlot = slot.data;
                }
                var vertexCount = map.vertexCount;
                this.readVertices(map, clip, vertexCount << 1);
                var color = map.color;
                if (color)
                    clip.color.setFromString(color);
                return clip;
            }
        }
        return null;
    };
    private readVertices(map: ISkinData, attachment: VertexAttachment, verticesLength: number) {
        attachment.worldVerticesLength = verticesLength;
        var vertices = map.vertices;
        if (verticesLength == vertices.length) {
            var scaledVertices = new Float32Array(vertices);
            attachment.vertices = scaledVertices;
            return;
        }
        var weights = new Array();
        var bones = new Array();
        for (var i = 0, n = vertices.length; i < n;) {
            var boneCount = vertices[i++];
            bones.push(boneCount);
            for (var nn = i + boneCount * 4; i < nn; i += 4) {
                bones.push(vertices[i]);
                weights.push(vertices[i + 1]);
                weights.push(vertices[i + 2]);
                weights.push(vertices[i + 3]);
            }
        }
        attachment.bones = bones;
        attachment.vertices = new Float32Array(weights);
    };

    private createSprite(slot: Slot, attachment: RegionAttachment, defName: string) {
        var sprite = new Sprite(attachment.texture);
        sprite.rotation = attachment.rotation || 0
        sprite.anchorTexture.set(0.5, 0.5)
        // sprite.scaleY = -1;//放在这里很悬，目前没法线sprite有缩放的情况
        // sprite.anchor.x = 0.5;
        // sprite.anchor.y = 0.5;
        sprite.position.x = attachment.x;
        sprite.position.y = attachment.y;
        sprite.alpha = attachment.color.a;
        //判断纹理是否存在
        if (attachment.texture) {
            sprite.scaleX = attachment.scaleX * attachment.width / attachment.texture.width;
            //注意加个负号
            sprite.scaleY = -attachment.scaleY * attachment.height / attachment.texture.height;
        }
        slot.sprites = slot.sprites || {};
        slot.sprites[defName] = sprite;
        return sprite;
    }

    private createMesh(slot: Slot, attachment: MeshAttachment) {
        var strip = new Mesh(attachment.texture, new Float32Array(attachment.regionUVs.length), attachment.regionUVs, new Uint16Array(attachment.triangles));
        if (strip.canvasPadding) strip.canvasPadding = 1.5;
        strip.refresh(true)
        strip.multiplyUvs()
        // strip.alpha = attachment.color.a;
        slot.meshes = slot.meshes || {};
        slot.meshes[attachment.name] = strip;
        return strip;
    };
    private createGraphics(slot: Slot, clip) {
        var graphics = new Graphics();
        graphics.beginFill(0xffffff, 1);
        graphics.drawPolygon([]);
        slot.currentGraphics = graphics;
        slot.clippingContainer = new Container();
        slot.clippingContainer.mask = slot.currentGraphics;
        return graphics;
    };
    private updateGraphics(slot: Slot, clip: ClippingAttachment) {
        var geom = slot.currentGraphics;
        var vertices = geom.graphicsData[0].shape.points;
        var n = clip.worldVerticesLength;
        vertices.length = n;
        clip.computeWorldVertices(slot, 0, n, vertices, 0, 2, this.bones);
        // geom.invalidate();//暂时感觉没用
    };
    /**
     * 返回一个Spine，注意data原始数据不能修改，之前写了那些多，忘了里面有没有修改
     */
    clone(): Spine {
        return new Spine(this.spineData)
    }

    // setSkin(name: string) {
    //     var skin = this.findSkin(name);
    //     if (skin) {
    //         if (this.skin)
    //             skin.attachAll(this.slots, this.skin);
    //         else {
    //             var slots = this.slots;
    //             for (var i = 0, n = slots.length; i < n; i++) {
    //                 var slot = slots[i];
    //                 var name_1 = slot.data.attachment;
    //                 if (name_1) {
    //                     var attachment = skin.getAttachment(i, name_1);
    //                     if (attachment)
    //                         slot.setAttachment(attachment);
    //                 }
    //             }
    //         }
    //         this.skin = skin;
    //     }
    // }
    setSkin(name: string) {
        var skin = this.findSkin(name);
        //皮肤不存在
        if (!skin) return;
        //皮肤一致
        if (this.skin == skin) return;
        //
        if (this.addSkin(skin)) return;
        //如果要替换成默认的皮肤，
        if (skin == this.defaultSkin) {
            this.resetSkin();
        } else {
            //先重置皮肤，再用下面的换装，因为可能出现非一致插槽换装
            this.resetSkin();
            this.addSkin(skin)
        }
    }
    resetSkin() {
        this.skin = this.defaultSkin;
        this.slots.forEach((s) => { s.setToSetupPose(); })
    }
    /**
     * 原先是默认皮肤，然后添加新皮肤
     */
    private addSkin(skin: Skin) {
        if (this.skin && this.skin != this.defaultSkin) return false;
        var slots = this.slots;
        for (var i = 0, n = slots.length; i < n; i++) {
            var slot = slots[i];
            var name_1 = slot.data.attachment;
            if (name_1) {
                var attachment = skin.getAttachment(i, name_1);
                if (attachment) slot.setAttachment(attachment);
            }
        }
        this.skin = skin;
        return true
    }
    /**
     * 获取所有皮肤名字
     */
    get skinNames(): string[] {
        if (!this.skins || !this.skins.length) return [];
        return this.skins.map((s) => { return s.name; })
    }
    /**
     * 获取所有动画的名字
     */
    get aniNames(): string[] {
        var am = this.animationManager;
        //@ts-ignore
        if (!am || !am.animationClips || !am.animationClips.length) return [];
        //@ts-ignore
        return am.animationClips.map((s) => { return s.name; })
    }
}

// function calculateTotalTime(tracks: SpineBoneAniTrack[]) {
//     var duration = 0;
//     for (var i = 0, n = tracks.length; i !== n; ++i) {
//         var track = tracks[i];
//         duration = Math.max(duration, track.times[track.times.length - 1].time);
//     }
//     return duration
// }

