const defaultLogger = {
    info: console.log,
    debug: console.log,
    error: console.error,
    infoAndReportMeasurement: (...i)=>{}
};

const USER_ID = "987412365"
  , PAGE_SESSION = "aaabbbccc"
  , SERVER_SESSION = "cccbbbaaa"
  , COS_PREFIX = "error-bitstreams-auto-uploaded-from-application/"
  , FRAME_COMPOSE_LENGTH = 5;

import CircularArray from "./CircularArray.js"

export default class Workers {
    constructor(e, t) {
        this.rtcp = e,
        this.cacheSize = 0,
        this.cacheBuffer = new Uint8Array(262144),
        this.cacheFrameCnt = 0,
        this.startReceiveTime = 0,
        this.cacheFrameComposes = new Array(0),
        this.cacheSizes = new Array(5).fill(0),
        this.cacheFrameCnts = new Array(5).fill(-1),
        this.cacheStartReceiveTimes = new Array(5).fill(0),
        this.cacheBuffers = [new Uint8Array(262144), new Uint8Array(262144), new Uint8Array(262144), new Uint8Array(262144), new Uint8Array(262144)],
        this.panoCacheSize = 0,
        this.panoCacheBuffer = new Uint8Array(2097152),
        this.cachePanoTileID = 0,
        this.receivedMedia = 0,
        this.receivedMedia_worker = 0,
        this.receivedYUV = 0,
        this.receivedEmit = 0,
        this.returnFrames = 0,
        this.lastReturnFrames = 0,
        this.lastReceivedEmit = 0,
        this.mediaBytesReceived = 0,
        this.metaBytesReceived = 0,
        this.noWasmBytesReceived = 0,
        this.rtcBytesReceived = 0,
        this.rtcMessageReceived = 0,
        this.packetsDrop = 0,
        this.framesAwait = 0,
        this.sendOutBuffer = 0,
        this.decodeTimePerFrame = 0,
        this.decodeTimeMaxFrame = 0,
        this.lastRenderTs = 0,
        this.JankTimes = 0,
        this.bigJankTimes = 0,
        this.DecodeJankTimes = 0,
        this.bigDecodeJankTimes = 0,
        this.saveframe = !1,
        this.SaveMediaStream = !1,
        this.packetsLost = 0,
        this.showAllReceivedMetadata = !1,
        this.firstMediaArraval = 0,
        this.firstMediaReceived = !1,
        this.firstYUVDecoded = 0,
        this.firstRender = 0,
        this.firstYUVReceived = !1,
        this.reconnectSignal = !1,
        this.serverFrameSlow = 0,
        this.serverFrameFast = 0,
        this.clientFrameSlow = 0,
        this.clientFrameFast = 0,
        this.lastServerTS = 0,
        this.lastClientTS = 0,
        this.lastSeq = 0,
        this.lastIsPureMeta = !1,
        this.lastHBPacketTs = 0,
        this.HBPacketInterval = 0,
        this.lastHBPacketSrvSentTs = 0,
        this.HBPacketIntervalSrvSent = 0,
        this.cachedLength = 2,
        this.cachedStreams = new Array(this.cachedLength),
        this.cachedMetas = new Array(this.cachedLength),
        this.cachedPtss = new Array(this.cachedLength),
        this.cachedRender = Array(this.cachedLength).fill(!1),
        this.cachedResolution = new Array(this.cachedLength),
        this.getPtr = 0,
        this.setPtr = 0,
        this.receiveIframes = 0,
        this.decodeIframes = 0,
        this.prevSenderTs = -1,
        this.serverSendTimeArray = new CircularArray(120,!1,[]),
        this.inPanoMode = !1,
        this.PanoStatus = {
            x: 0,
            y: 0,
            z: 0,
            tiles: []
        },
        this.DynamicPanoTest = !1,
        this.PanoMask = new ArrayBuffer(8),
        this.PanoView = new DataView(this.PanoMask),
        this.userId_test = "",
        this.PendingMasks = [],
        this.traceIdMap = new Map,
        this.responseTimeArray = [],
        this.processTimeArray = [],
        this.displayTimeArray = [],
        this.overallTimeArray = [],
        this.responseMiss = 0,
        this.processMiss = 0,
        this.displayMiss = 0,
        this.updateYUVCircular = new CircularArray(120,!1,[]),
        this.updateDropFrame = 0,
        this.metaParseAraay = [],
        this.responseMoveMiss = 0,
        this.processMoveMiss = 0,
        this.displayMoveMiss = 0,
        this.MovingTraceId = "",
        this.PendingMovingTraceId = "",
        this.inMovingMode = !1,
        this.StartMovingTs = 0,
        this.PendingStartMovingTs = 0,
        this.moveEvent = "",
        this.MoveToFrameCnt = 0,
        this.lastIsMoving = 0,
        this.MoveResponseDelay = 0,
        this.MoveProcessDelay = 0,
        this.MoveDisplayDelay = 0,
        this.lastMoveResponseTime = 0,
        this.lastMoveProcessTime = 0,
        this.lastMoveDisplayTime = 0,
        this.moveResponseCircular = new CircularArray(120,!0,[STUCK_STAGE_GOOD, STUCK_STAGE_WELL, STUCK_STAGE_FAIR, STUCK_STAGE_BAD]),
        this.moveProcessCircular = new CircularArray(120,!0,[STUCK_STAGE_GOOD, STUCK_STAGE_WELL, STUCK_STAGE_FAIR, STUCK_STAGE_BAD]),
        this.moveDisplayCircular = new CircularArray(120,!0,[STUCK_STAGE_GOOD, STUCK_STAGE_WELL, STUCK_STAGE_FAIR, STUCK_STAGE_BAD]),
        this.moveStartPts = -1,
        this.frameServerCircular = new CircularArray(120,!1,[]),
        this.srvMetaIntervalCircular = new CircularArray(120,!1,[]),
        this.srvMediaIntervalCircular = new CircularArray(120,!1,[]),
        this.srvHBMetaIntervalCircular = new CircularArray(120,!1,[]),
        this.srvHBMetaIntervalSrvSentCircular = new CircularArray(120,!1,[]),
        this.frameClientCircular = new CircularArray(120,!1,[]),
        this.firstUpdateYUV = !0,
        this.functionMap = new Map,
        this.WASM_VERSION = "WASM-1.1",
        this.frameHistory = [],
        this.getVersion = function() {
            return DECODER_VERSION
        }
        ,
        this.downloadBlob = (r,n,o)=>{
            const a = new Blob([r],{
                type: o
            })
              , s = window.URL.createObjectURL(a);
            this.downloadURL(s, n),
            setTimeout(function() {
                return window.URL.revokeObjectURL(s)
            }, 1e3)
        }
        ,
        this.downloadURL = function(r, n) {
            const o = document.createElement("a");
            o.href = r,
            o.download = n,
            document.body.appendChild(o),
            o.style.display = "none",
            o.click(),
            o.remove()
        }
        ,
        this.Stringify = function(r) {
            let n = "";
            for (let a = 0; a < r.length / 8192; a++)
                n += String.fromCharCode.apply(null, r.slice(a * 8192, (a + 1) * 8192));
            return n
        }
        ,
        this._rtcp = e
    }
    registerLogger(e) {
        //defaultLogger = e
    }
    registerFunction(e, t) {
        this.functionMap.set(e, t)
    }
    hasFrmCntInCache(e) {
        let t = -1;
        for (let r = 0; r < this.cacheFrameComposes.length; r++)
            this.cacheFrameComposes[r].frameCnt == e && (t = r);
        return t
    }
    requestPanoramaTest(e, t, r, n, o) {
        const a = o
          , s = {
            action_type: 16,
            change_rotation_render_type_action: {
                render_type: 5,
                player: {
                    position: {
                        x: 0,
                        y: 0,
                        z: 0
                    },
                    angle: {
                        yaw: 0,
                        pitch: 0,
                        roll: 0
                    }
                },
                camera: {
                    position: {
                        x: e,
                        y: t,
                        z: r
                    },
                    angle: {
                        yaw: 0,
                        pitch: 0,
                        roll: 0
                    }
                },
                client_pano_titles_bitmap: n
            },
            trace_id: a,
            user_id: this.userId_test,
            packet_id: a
        };
        defaultLogger.debug("send data: ", s),
        this._rtcp.sendData(s)
    }
    onRotateInPanoMode(e) {
        const t = e.traceId
          , r = {};
        r.width = 1280,
        r.height = 720,
        r.horz_fov = 92,
        r.angle = {
            yaw: 100,
            pitch: 30
        };
        const n = new ArrayBuffer(8)
          , o = new DataView(n);
        getTilesInView(r, n);
        const a = n.slice(0);
        this.PendingMasks.unshift({
            buffer: a,
            angle: r.angle
        }),
        MaskSetToOne(18, this.PanoView),
        operateForDataView(o, this.PanoView, o, (s,l)=>s ^ s & l),
        this.requestPanoramaTest(0, 0, 0, [o.getUint8(0), o.getUint8(1), o.getUint8(2), o.getUint8(3), o.getUint8(4), o.getUint8(5), o.getUint8(6), o.getUint8(7)], t)
    }
    processMetaWithTraceId(e) {
        for (const t of e.traceIds) {
            if (this.traceIdMap.has(t)) {
                const r = this.traceIdMap.get(t);
                r != null && (r.receiveTime = Date.now(),
                r.status = 1)
            }
            if (t == this.PendingMovingTraceId) {
                this.inMovingMode = !0,
                this.MovingTraceId = this.PendingMovingTraceId,
                this.StartMovingTs = this.PendingStartMovingTs,
                this.PendingMovingTraceId = "",
                this.PendingStartMovingTs = 0,
                defaultLogger.info("MoveTo TraceId match", this.StartMovingTs, Date.now());
                const r = Date.now();
                this.lastMoveResponseTime = r,
                this.lastMoveProcessTime = r,
                this.lastMoveDisplayTime = r,
                this.frameServerCircular.clear(),
                this.frameClientCircular.clear()
            }
        }
    }
    onTraceId(e, t=this) {
        const r = e.traceId
          , n = e.timestamp
          , o = e.event;
        if (o === "Rotation") {
            const a = {
                traceId: r,
                pts: 0,
                startTime: n,
                receiveTime: 0,
                readyTime: 0,
                displayTime: 0,
                status: 0
            };
            this.traceIdMap.set(r, a);
            const s = setTimeout(()=>{
                if (s && clearTimeout(s),
                this.traceIdMap.has(r)) {
                    const l = this.traceIdMap.get(r);
                    switch (l == null ? void 0 : l.status) {
                    case 0:
                        {
                            this.responseMiss += 1;
                            break
                        }
                    case 1:
                        {
                            this.processMiss += 1;
                            const u = l.receiveTime - l.startTime;
                            this.responseTimeArray.push(u);
                            break
                        }
                    case 2:
                        {
                            this.displayMiss += 1;
                            const u = l.receiveTime - l.startTime
                              , c = l.readyTime - l.receiveTime;
                            this.responseTimeArray.push(u),
                            this.processTimeArray.push(c);
                            break
                        }
                    case 3:
                        defaultLogger.debug("status is 3")
                    }
                }
            }
            , 1e3)
        } else
            o === "MoveTo" ? (defaultLogger.info("receive moveto traceId ", r, " at timestamp", n),
            this.PendingMovingTraceId = r,
            this.PendingStartMovingTs = n,
            this.moveEvent = o,
            this.frameServerCircular.clear()) : o === "GetOnAirship" || o === "GetOnVehicle" ? (defaultLogger.info("receive airship traceId ", r, " at timestamp ", n),
            this.PendingMovingTraceId = r,
            this.PendingStartMovingTs = n,
            this.moveEvent = o,
            this.frameServerCircular.clear()) : (o === "GetOffAirship" || o === "GetOffVehicle") && this.clearMoveArray()
    }
    executeFunction(e, t) {
        if (this.functionMap.has(e)) {
            const r = this.functionMap.get(e);
            r != null && r(t)
        }
    }
    UpdateStats(e) {
        var t;
        (t = this._rtcp.connection) == null || t.getStats(null).then(r=>{
            r.forEach(n=>{
                n.type == "data-channel" && (this.rtcMessageReceived = n.messagesReceived - n.messagesSent,
                this.rtcBytesReceived = n.bytesReceived)
            }
            )
        }
        ),
        this.receivedMedia_worker = e.data.framesReceived,
        this.receivedYUV = e.data.framesDecoded,
        this.receivedEmit = e.data.framesRendered,
        this.mediaBytesReceived = e.data.mediaBytesReceived,
        this.metaBytesReceived = e.data.metaBytesReceived,
        this.packetsLost = e.data.packetsLost,
        this.packetsDrop = e.data.packetsDrop,
        this.framesAwait = e.data.framesAwait,
        this.decodeTimePerFrame = e.data.decodeTimePerFrame,
        this.decodeTimeMaxFrame = e.data.decodeTimeMaxFrame,
        this.returnFrames = e.data.framesReturned,
        this.sendOutBuffer = e.data.sendOutBuffer,
        this.DecodeJankTimes = e.data.JankTimes,
        this.bigDecodeJankTimes = e.data.bigJankTimes,
        this.receiveIframes = e.data.receivedIframe,
        this.decodeIframes = e.data.decodedIframe
    }
    ReceiveDecodeMessage(e) {
        var n;
        if (!this.firstYUVReceived) {
            this.firstYUVDecoded = e.data.yuv_ts;
            const o = this.firstYUVDecoded - this.rtcp.network.room._startTime;
            defaultLogger.infoAndReportMeasurement({
                metric: "firstYUVDecodedAt",
                value: o,
                group: "joinRoom"
            }),
            this.firstRender = Date.now();
            const a = this.firstYUVDecoded - this.rtcp.network.room._startTime;
            defaultLogger.infoAndReportMeasurement({
                metric: "firstRenderAt",
                value: a,
                group: "joinRoom"
            }),
            this.firstYUVReceived = !0,
            this.lastRenderTs = Date.now()
        }
        if(!this.cachedRender[this.setPtr] && this.cachedMetas[this.setPtr] != null){
            if(this.cachedStreams[this.setPtr] != null && this.cachedStreams[this.setPtr].byteLength != 0)
            {
                if(e.data.data == null){
                    // this.executeFunction("stream", {
                    //     stream: this.cachedStreams[this.setPtr],
                    //     width: this.cachedResolution[this.setPtr].width,
                    //     height: this.cachedResolution[this.setPtr].height,
                    //     pts: this.cachedPtss[this.setPtr]
                    // }),
                    // this.executeFunction("signal", {
                    //     signal: this.cachedMetas[this.setPtr],
                    //     pts: this.cachedPtss[this.setPtr],
                    //     alreadyUpdateYUV: !0
                    // })
                }
                else{
                    this.updateDropFrame += 1
                }
                // this.decoderWorker.postMessage({
                //     t: 2,
                //     frameCnt: this.cachedPtss[this.setPtr],
                //     buffer: this.cachedStreams[this.setPtr]
                // }, [this.cachedStreams[this.setPtr].buffer])
            }
            this.getPtr = (this.getPtr + 1) % this.cachedLength
        }

        const t = e.data.metadata;
        if ((n = t == null ? void 0 : t.traceIds) != null && n.length) {
            for (const o of t.traceIds)
                if (this.traceIdMap.has(o)) {
                    const a = this.traceIdMap.get(o);
                    a != null && (a.readyTime = Date.now(),
                    a.status = 2)
                }
        }

        e.data.pts == this.moveStartPts && (this.MoveProcessDelay = Date.now() - this.StartMovingTs);
        this.userId_test = this.rtcp.network.room.userId;

        if (this.inMovingMode) {
            const o = Date.now()
            const a = o - this.lastMoveProcessTime;
            this.moveProcessCircular.add(a);
            this.lastMoveProcessTime = o;
        }
        const r = this.setPtr;
        this.cachedStreams[r] = e.data.data;
        this.cachedMetas[r] = e.data.metadata;
        this.cachedPtss[r] = e.data.pts;
        this.cachedRender[r] = !1;
        this.cachedResolution[r] = {
            width: e.data.width,
            height: e.data.height
        },
        this.setPtr = (this.setPtr + 1) % this.cachedLength
    }
    // SendCacheFrameInfo(e) {
    //     var h, f, d, _, g, m, v;
    //     const t = e.data.cachedKey
    //       , r = e.data.metadata
    //       , n = t
    //       , o = r
    //       , a = (d = (f = (h = o.newUserStates) == null ? void 0 : h.find(y=>y.userId === this.rtcp.network.room.userId)) == null ? void 0 : f.playerState) == null ? void 0 : d.roomTypeId
    //       , s = this.rtcp.network.room.skinId
    //       , l = (v = (m = (g = (_ = o.newUserStates) == null ? void 0 : _.find(y=>y.userId === this._rtcp.network.room.userId)) == null ? void 0 : g.playerState) == null ? void 0 : m.player) == null ? void 0 : v.position
    //       , u = {
    //         MsgType: 1,
    //         FrameCacheMsg: {
    //             FrameIndex: n,
    //             RoomTypeId: a,
    //             SkinID: s,
    //             Position: l
    //         }
    //     };
    //     let c = "";
    //     try {
    //         c = JSON.stringify(u)
    //     } catch (y) {
    //         defaultLogger.error(y);
    //         return
    //     }
    // }
    ReceivePanoramaDecodeMessage(e) {
        defaultLogger.info("Receive Panorama Image in Workers.ts"),
        MaskSetToOne(e.data.tileId, this.PanoView);
        let t = 0, r;
        const n = this.PendingMasks.length;
        for (t = 0; t < n; t++) {
            const o = this.PendingMasks[t].buffer
              , a = new DataView(o)
              , s = new ArrayBuffer(8)
              , l = new DataView(s);
            if (operateForDataView(this.PanoView, a, l, (u,c)=>c ^ u & c),
            IsAll0(l)) {
                r = this.PendingMasks[t].angle;
                break
            }
        }
        for (let o = t; o < n; o++)
            this.PendingMasks.pop();
        this.executeFunction("panorama", {
            data: e.data.data,
            tileId: e.data.tileId,
            pos: {
                x: e.data.x,
                y: e.data.y,
                z: e.data.z
            },
            uuid: e.data.uuid,
            finished: !0,
            matchAngle: r
        })
    }
    enable_decoder_queue_logging() {
        this.decoderWorker.postMessage({
            t: 100,
            status: !0
        })
    }
    disable_decoder_queue_logging() {
        this.decoderWorker.postMessage({
            t: 100,
            status: !1
        })
    }
    async init(e={
        width: 1280,
        height: 720
    }) {
        for (let r = 0; r < FRAME_COMPOSE_LENGTH; r++) {
            const n = {
                buffer: new Uint8Array(2621440),
                size: 0,
                startReceiveTime: 0,
                serverTime: 0,
                frameCnt: -1
            };
            this.cacheFrameComposes.push(n)
        }
    
        const t = new Blob([decoder],{
            type: "application/javascript"
        });
        
        this.decoderWorker = new Worker(URL.createObjectURL(t));
 
        this.decoderWorker.postMessage({
            t: 9,
            url: WASM_URLS[WASM_Version],
            jitterLength: DECODER_PASSIVE_JITTER
        });
        window.decoderWorker = this.decoderWorker;
        this.decoderWorker.postMessage({
            t: 1,
            config: e
        });

        return new Promise(r=>{
            this.decoderWorker.onmessage = n=>{
                switch (n.data.t) {
                case 0:
                    this.ReceiveDecodeMessage(n);
                    break;
                case 1:
                    this.UpdateStats(n);
                    break;
                case 2:
                    r();
                    break;
                case 3:
                    //this.SendCacheFrameInfo(n);
                    break;
                case 4:
                    {
                        const o = new Date().toISOString()
                          , a = USER_ID + "-" + PAGE_SESSION + "-" + SERVER_SESSION + "-" + o + ".264";
                        
                          let downloadURL = function(r, n) {
                            const o = document.createElement("a");
                            o.href = r,
                            o.download = n,
                            document.body.appendChild(o),
                            o.style.display = "none",
                            o.click(),
                            o.remove()
                        }
                        downloadURL(n.data.link, a)
                        //uploadStream(COS_PREFIX + a, n.data.fileObj);
                        break
                    }
                case 5:
                    // this.executeFunction("signal", {
                    //     signal: n.data.metadata,
                    //     pts: -1,
                    //     alreadyUpdateYUV: !1
                    // });
                    break;
                case 6:
                    defaultLogger.infoAndReportMeasurement(n.data),
                    defaultLogger.debug("WASM Ready Cost");
                    break;
                case 7:
                    this.ReceivePanoramaDecodeMessage(n);
                    break;
                case 8:
                    {
                        const o = {
                            MstType: 0
                        };
                        let a = "";
                        try {
                            a = JSON.stringify(o)
                        } catch (l) {
                            defaultLogger.error(l);
                            return
                        }
                        const s = "wasm:" + a;
                        this._rtcp.sendStringData(s);
                        break
                    }
                case 9:
                    {
                        defaultLogger.info(n.data.printMsg);
                        break
                    }
                case 10:
                    {
                        defaultLogger.error(n.data.printMsg),
                        this.executeFunction("error", {
                            code: n.data.code,
                            message: n.data.printMsg
                        });
                        break
                    }
                default:
                    defaultLogger.error("Receive unknown message event from decoder"),
                    defaultLogger.debug(n.data);
                    break
                }
            }
        }
        )
    }
    UpdateYUV() {
        if(window.initFinished){
            return
        }
        var t, r;
        const e = this.getPtr;
        if (this.cachedMetas[e] != null && !this.cachedRender[e]) {
            const n = Date.now();
            if (this.firstUpdateYUV) {
                const h = ((t = this.cachedStreams[e]) == null ? void 0 : t.byteLength) || 0;
                defaultLogger.infoAndReportMeasurement({
                    metric: "firstUpdateStreamLength",
                    value: h,
                    group: "joinRoom"
                }),
                this.firstUpdateYUV = !1
            }
            this.cachedStreams[e] != null && this.executeFunction("stream", {
                stream: this.cachedStreams[e],
                width: this.cachedResolution[e].width,
                height: this.cachedResolution[e].height,
                pts: this.cachedPtss[e]
            });
            const o = Date.now();
            this.cachedStreams[e] != null && this.decoderWorker.postMessage({
                t: 2,
                frameCnt: this.cachedPtss[e],
                buffer: this.cachedStreams[e]
            }, [this.cachedStreams[e].buffer]);
            // const a = Date.now()
            //   , s = o - n
            //   , l = a - o;
            // (s > 33 || l > 10) && defaultLogger.debug("[wwwarning] updateYUV takes ", s, " ms, postMessage takes ", l, " ms for index ", this.cachedPtss[e]),
            // o - this.lastRenderTs > 84 && this.JankTimes++,
            // o - this.lastRenderTs > 125 && this.bigJankTimes++,
            // this.lastRenderTs = o;
            // const u = o - n;
            // this.updateYUVCircular.add(u);
            // const c = this.cachedMetas[e];
            // if ((r = c == null ? void 0 : c.traceIds) != null && r.length) {
            //     for (const h of c.traceIds)
            //         if (this.traceIdMap.has(h)) {
            //             const f = this.traceIdMap.get(h);
            //             if (f != null) {
            //                 f.displayTime = Date.now(),
            //                 f.status = 3;
            //                 const d = f.receiveTime - f.startTime
            //                   , _ = f.readyTime - f.receiveTime
            //                   , g = f.displayTime - f.readyTime
            //                   , m = f.displayTime - f.startTime;
            //                 this.responseTimeArray.push(d),
            //                 this.processTimeArray.push(_),
            //                 this.displayTimeArray.push(g),
            //                 this.overallTimeArray.push(m),
            //                 this.traceIdMap.delete(h)
            //             }
            //         }
            // }
            // this.cachedPtss[e] == this.moveStartPts && (this.MoveDisplayDelay = Date.now() - this.StartMovingTs)
            // if (this.inMovingMode) {
            //     const h = Date.now()
            //       , f = h - this.lastMoveDisplayTime;
            //     this.moveDisplayCircular.add(f),
            //     this.lastMoveDisplayTime = h
            // }

            
            this.executeFunction("signal", {
                signal: this.cachedMetas[e],
                pts: this.cachedPtss[e],
                alreadyUpdateYUV: !0
            })
            this.cachedRender[e] = !0;
            this.getPtr = (this.getPtr + 1) % this.cachedLength
            
        }
    }
    unmarshalPano(e) {
        const t = new DataView(e);
        if (t.getUint32(0) != 1723558763)
            return !1;
        console.log("Receive Pano Message"),
        t.getUint16(4);
        const n = t.getUint16(6)
          , o = t.getUint32(8)
          , a = t.getUint32(12) - (1 << 30) * 2
          , s = t.getUint32(16) - (1 << 30) * 2
          , l = t.getUint32(20) - (1 << 30) * 2
          , u = t.getUint32(24)
          , c = new Uint8Array(e).subarray(28, 64)
          , h = String.fromCharCode.apply(null, c)
          , f = t.getUint32(64)
          , d = e.byteLength - n;
        if (d == u) {
            const g = {
                data: new Uint8Array(e).subarray(n),
                mediaLen: u,
                tileId: o,
                uuid: h,
                x: a,
                y: s,
                z: l
            };
            this.decoderWorker.postMessage({
                t: 8,
                data: g
            })
        } else {
            const _ = new Uint8Array(e,n,d);
            if (this.cachePanoTileID == o) {
                if (this.panoCacheBuffer.set(_, f),
                this.panoCacheSize += d,
                this.panoCacheSize === u) {
                    const m = {
                        data: new Uint8Array(this.panoCacheBuffer).slice(0, u),
                        mediaLen: u,
                        tileId: o,
                        uuid: h,
                        x: a,
                        y: s,
                        z: l
                    };
                    this.decoderWorker.postMessage({
                        t: 8,
                        data: m
                    }),
                    this.panoCacheSize = 0
                }
            } else
                this.panoCacheBuffer.set(_, f),
                this.panoCacheSize = d,
                this.cachePanoTileID = o
        }
        return !0
    }
    clearMoveArray() {
        this.MovingTraceId = "",
        this.inMovingMode = !1,
        this.StartMovingTs = 0,
        this.MoveToFrameCnt = 0,
        this.MoveResponseDelay = 0,
        this.MoveProcessDelay = 0,
        this.MoveDisplayDelay = 0,
        this.moveStartPts = -1,
        this.moveResponseCircular.clear(),
        this.moveProcessCircular.clear(),
        this.moveDisplayCircular.clear(),
        this.moveEvent = ""
    }
    getIsMoving(e) {
        let t;
        if (typeof e.newUserStates != "undefined")
            for (let r = 0; r < e.newUserStates.length; r++) {
                const n = e.newUserStates[r];
                if (n.userId == this.rtcp.network.room.userId) {
                    t = n.renderInfo.isMoving;
                    break
                }
            }
        return t
    }
    isHeartBeatPacket(e, t) {
        return new DataView(e).getUint32(0) == 2009889916
    }
    resetSendTimeDiff() {
        this.prevSenderTs = 0,
        this.serverSendTimeArray.clear()
    }
    calcSendTimeDiff(e) {
        if (this.prevSenderTs == -1) {
            this.prevSenderTs = e;
            return
        }
        const t = e - this.prevSenderTs;
        this.serverSendTimeArray.add(t),
        this.prevSenderTs = e
    }
    unmarshalStream(e) {
        var T, C, A, S, P, R, M, x, I, w;
        const t = new DataView(e);
        if (t.getUint32(0) != 1437227610)
        {
            return !1;
        }
        t.getUint16(4);
        const n = t.getUint16(6)
          , o = t.getUint16(8)
          , a = o
          , s = t.getUint16(10);
        let l = !1;
        s == 1 && (l = !0);
        const u = t.getUint32(12)
          , c = t.getUint32(16)
          , h = t.getUint32(20)
          , f = t.getUint16(24)
          , d = t.getUint16(26)
          , _ = t.getUint32(28)
          , g = t.getUint32(n - 4)
          , m = u + c
          , v = e.byteLength - n
          , y = new Uint8Array(e,n,v);
        this.calcSendTimeDiff(h);
        let b;
        if (this.inPanoMode && (c > 0 || f))
        {
            defaultLogger.error("Stream Protocal Violation: receive illegal stream in Pano mode")
            return !0;
        }
        if (v === m) {
            this.receivedMedia++;
            const O = new Uint8Array(e).subarray(n);
            h - this.lastServerTS > 60 ? this.serverFrameSlow++ : h - this.lastServerTS < 16 && this.serverFrameFast++;
            const D = Date.now();
            D - this.lastClientTS > 60 ? this.clientFrameSlow++ : D - this.lastClientTS < 16 && this.clientFrameFast++;
            const F = c === 0
              , V = h - this.lastServerTS;
            if(this.lastServerTS != 0)
            {
                if((o + 65536 - this.lastSeq) % 65536 === 1 && this.lastIsPureMeta == F){
                    F ? this.srvMetaIntervalCircular.add(V) : this.srvMediaIntervalCircular.add(V)
                }

                this.frameServerCircular.add(V);
                this.frameClientCircular.add(D - this.lastClientTS);
            }
            this.lastSeq = o;
            this.lastIsPureMeta = F;
            this.lastServerTS = h;
            this.lastClientTS = D;
            const N = O.subarray(0, u)
              , L = Date.now()
              , k = JSON.parse(this.Stringify(N))
              , U = Date.now();
            this.showAllReceivedMetadata && console.log(h, D, k);
            this.metaParseAraay.push(U - L);
            (T = k.traceIds) != null && T.length && this.processMetaWithTraceId(k);
            c != 0 && this.moveStartPts == -1 && this.inMovingMode && (this.moveStartPts = o);
            if(this.moveStartPts == o){
                this.MoveResponseDelay = Date.now() - this.StartMovingTs;
                console.log("move response delay: ", o, this.moveStartPts, this.MoveResponseDelay)
            }
            const z = this.getIsMoving(k);
            this.inMovingMode && z == 0 && this.lastIsMoving == 1 && this.clearMoveArray();
            typeof z != "undefined" && (this.lastIsMoving = z);
            if (this.inMovingMode) {
                const G = Date.now()
                  , W = G - this.lastMoveResponseTime;
                this.moveResponseCircular.add(W);
                this.lastMoveResponseTime = G;
            }
            if(f || d){
                b = (P = (S = (A = (C = k.newUserStates) == null ? void 0 : C.find(G=>G.userId === this._rtcp.network.room.userId)) == null ? void 0 : A.playerState) == null ? void 0 : S.player) == null ? void 0 : P.position
            }
            const H = {
                t: 0,
                data: O,
                mediaLen: c,
                metaLen: u,
                metadata: k,
                frameCnt: a,
                server_ts: h,
                isIDR: l,
                cacheRequest: d,
                cached: f,
                cachedKey: _,
                position: b
            };
            if (this.inPanoMode)
            {
                this.executeFunction("signal", {
                    signal: k,
                    pts: -1,
                    alreadyUpdateYUV: !0
                });
                return !0;
            }
            this.decoderWorker.postMessage(H, [O.buffer]);
            if (!this.firstMediaReceived) {
                this.firstMediaArraval = Date.now();
                const G = this.firstMediaArraval - this.rtcp.network.room._startTime;
                defaultLogger.infoAndReportMeasurement({
                    metric: "firstMediaArravalAt",
                    value: G,
                    group: "joinRoom"
                });
                this.firstMediaReceived = !0;
            }
        } 
        else {
            const O = this.hasFrmCntInCache(a);
            if (O != -1)
            {
                this.cacheFrameComposes[O].buffer.set(y, g);
                this.cacheFrameComposes[O].size += v;
                if (this.cacheFrameComposes[O].size === m) {
                    const D = new Uint8Array(this.cacheFrameComposes[O].buffer).slice(0, m);
                    this.cacheFrameComposes[O].frameCnt = -1;
                    this.cacheFrameComposes[O].size = 0;
                    this.cacheFrameComposes[O].startReceiveTime = 0;
                    this.cacheFrameComposes[O].serverTime = 0;
                    this.receivedMedia++;
                    h - this.lastServerTS > 60 ? this.serverFrameSlow++ : h - this.lastServerTS < 16 && this.serverFrameFast++;
                    const F = Date.now();
                    F - this.lastClientTS > 60 ? this.clientFrameSlow++ : F - this.lastClientTS < 16 && this.clientFrameFast++;
                    if(this.lastServerTS != 0)
                    {
                        this.frameServerCircular.add(h - this.lastServerTS);
                        this.frameClientCircular.add(F - this.lastClientTS);
                    }
                    this.lastServerTS = h;
                    this.lastClientTS = F;
                    const V = D.subarray(0, u)
                      , N = Date.now()
                      , L = JSON.parse(this.Stringify(V))
                      , k = Date.now();
                    this.showAllReceivedMetadata && console.log(h, F, L);
                    this.metaParseAraay.push(k - N);
                    (R = L.traceIds) != null && R.length && this.processMetaWithTraceId(L);
                    c != 0 && this.moveStartPts == -1 && this.inMovingMode && (this.moveStartPts = o);
                    this.moveStartPts == o && (this.MoveResponseDelay = Date.now() - this.StartMovingTs);
                    const U = this.getIsMoving(L);
                    this.inMovingMode && U == 0 && this.lastIsMoving == 1 && this.clearMoveArray();
                    typeof U != "undefined" && (this.lastIsMoving = U);
                    if (this.inMovingMode) {
                        const H = Date.now()
                          , G = H - this.lastMoveResponseTime;
                        this.moveResponseCircular.add(G);
                        this.lastMoveResponseTime = H;
                    }
                    (f || d) && (b = (w = (I = (x = (M = L.newUserStates) == null ? void 0 : M.find(H=>H.userId === this._rtcp.network.room.userId)) == null ? void 0 : x.playerState) == null ? void 0 : I.player) == null ? void 0 : w.position);
                    const z = {
                        t: 0,
                        data: D,
                        mediaLen: c,
                        metaLen: u,
                        metadata: L,
                        frameCnt: a,
                        server_ts: h,
                        isIDR: l,
                        cacheRequest: d,
                        cached: f,
                        cachedKey: _,
                        position: b
                    };
                    if (this.inPanoMode)
                    {
                        this.executeFunction("signal", {
                            signal: L,
                            pts: -1,
                            alreadyUpdateYUV: !0
                        });
                        return !0;
                    }
                    this.decoderWorker.postMessage(z, [D.buffer]);
                    if (!this.firstMediaReceived) {
                        this.firstMediaArraval = Date.now();
                        const H = this.firstMediaArraval - this.rtcp.network.room._startTime;
                        defaultLogger.infoAndReportMeasurement({
                            metric: "firstMediaArravalAt",
                            value: H,
                            group: "joinRoom"
                        }),
                        this.firstMediaReceived = !0
                    }
                } 
                else
                {
                    this.cacheFrameComposes[O].size > m && defaultLogger.debug("I frame exceed, cache size is ", this.cacheSize, ", total size is ", m);
                }
            }
            else if (O == -1) {
                let D = this.hasFrmCntInCache(-1);
                if (D == -1) {
                    let F = Date.now() + 1e18
                      , V = -1;
                    for (let N = 0; N < this.cacheFrameComposes.length; N++)
                        this.cacheFrameComposes[N].serverTime < F && (F = this.cacheFrameComposes[N].serverTime,
                        V = N);
                    D = V
                }
                this.cacheFrameComposes[D].buffer.set(y, g);
                this.cacheFrameComposes[D].size = v;
                this.cacheFrameComposes[D].frameCnt = a;
                this.cacheFrameComposes[D].startReceiveTime = Date.now();
                this.cacheFrameComposes[D].serverTime = h;
            }
        }
        return !0
    }
    reset() {
        defaultLogger.debug("Worker reset is called"),
        this.cacheFrameCnt = 0,
        this.receivedMedia = 0,
        this.reconnectSignal = !0,
        this.decoderWorker.postMessage({
            t: 4
        })
    }
    dataHandleOff(e) {
        defaultLogger.debug("hhh")
    }
    dataHandle(e) {
        if(this.saveframe){
            this.decoderWorker.postMessage({
                t: 6
            }),
            this.saveframe = !1
        }

        if(this.SaveMediaStream){
            this.decoderWorker.postMessage({
                t: 7
            }),
            this.SaveMediaStream = !1
        }

        const t = new Uint8Array(e);
        if (t.length >= 4 && this.isHeartBeatPacket(t.buffer, t.length) == !0)
        {
            return;
        }
        if (t.length > 36 && this.unmarshalStream(t.buffer) == !0) {
            if(this.reconnectSignal){
                this.executeFunction("reconnectedFrame", {});
                this.reconnectSignal = !1
            }
            return
        }
        if (t.length > 20 && this.unmarshalPano(t.buffer) == !0)
        {
            return;
        }
        this.noWasmBytesReceived += e.byteLength;
        const r = JSON.parse(this.Stringify(t));
        this.executeFunction("signal", {
            signal: r,
            pts: -1,
            alreadyUpdateYUV: !0
        })
    }
    changePanoMode(e) {
        this.inPanoMode = e
    }
    uploadDataToServer() {
        this.DynamicPanoTest == !0 && (this.onRotateInPanoMode({
            traceId: "b2e1a296-6438-4371-8a31-687beb724ebe"
        }),
        this.DynamicPanoTest = !1);
        function e(ie, ee) {
            return ee == -1 && (ee = 0),
            ie + ee
        }
        function t(ie, ee) {
            return Math.max(ie, ee)
        }
        const r = this.responseTimeArray.reduce(e, 0) / this.responseTimeArray.length || 0
          , n = this.processTimeArray.reduce(e, 0) / this.processTimeArray.length || 0
          , o = this.displayTimeArray.reduce(e, 0) / this.displayTimeArray.length || 0
          , a = this.overallTimeArray.reduce(e, 0) / this.overallTimeArray.length || 0
          , s = this.overallTimeArray.length;
        this.responseTimeArray = [],
        this.processTimeArray = [],
        this.displayTimeArray = [],
        this.overallTimeArray = [];
        const l = this.moveResponseCircular.getThreshPercent()
          , u = l[0]
          , c = l[1]
          , h = l[2]
          , f = l[3]
          , d = l[4]
          , _ = d - f
          , g = 1 - c / d || 0
          , m = [u, c - u, h - c, f - h, _]
          , v = this.moveProcessCircular.getThreshPercent()
          , y = v[0]
          , b = v[1]
          , T = v[2]
          , C = v[3]
          , A = v[4]
          , S = A - C
          , P = 1 - b / A || 0
          , R = [y, b - y, T - b, C - T, S]
          , M = this.moveDisplayCircular.getThreshPercent()
          , x = M[0]
          , I = M[1]
          , w = M[2]
          , O = M[3]
          , D = M[4]
          , F = D - O
          , V = 1 - I / D || 0
          , N = [x, I - x, w - I, O - w, F]
          , L = x
          , k = I - x
          , U = w - I
          , z = O - w
          , H = F
          , G = this.moveResponseCircular.getAvg()
          , W = this.moveProcessCircular.getAvg()
          , j = this.moveDisplayCircular.getAvg()
          , B = this.moveResponseCircular.getMax()
          , X = this.moveProcessCircular.getMax()
          , $ = this.moveDisplayCircular.getMax()
          , Y = this.moveResponseCircular.getStandardDeviation()
          , K = this.moveProcessCircular.getStandardDeviation()
          , Z = this.moveDisplayCircular.getStandardDeviation();
        this.moveResponseCircular.getIncomingAvg(),
        this.moveProcessCircular.getIncomingAvg(),
        this.moveDisplayCircular.getIncomingAvg(),
        this.moveResponseCircular.getIncomingMax(),
        this.moveProcessCircular.getIncomingMax(),
        this.moveDisplayCircular.getIncomingMax(),
        this.moveResponseCircular.clearIncoming(),
        this.moveProcessCircular.clearIncoming(),
        this.moveDisplayCircular.clearIncoming();
        const q = this.frameServerCircular.getAvg()
          , J = this.frameServerCircular.getMax();
        this.frameClientCircular.getAvg(),
        this.frameClientCircular.getMax();
        const Q = this.metaParseAraay.reduce(e, 0) / this.metaParseAraay.length || 0
          , te = this.metaParseAraay.reduce(t, 0);
        this.metaParseAraay = [];
        const re = {
            mediaBytesReceived: this.mediaBytesReceived,
            metaBytesReceived: this.metaBytesReceived,
            packetsLost: this.packetsLost,
            timestamp: Date.now(),
            frameHeight: 1280,
            frameWidth: 720,
            framesReceived: this.receivedMedia,
            framesReceivedWorker: this.receivedMedia_worker,
            framesDecoded: this.receivedYUV,
            framesEmited: this.receivedEmit,
            decodeTimePerFrame: this.decodeTimePerFrame,
            decodeTimeMaxFrame: this.decodeTimeMaxFrame,
            packetsDrop: this.packetsDrop,
            framesAwait: this.framesAwait,
            firstMediaArraval: this.firstMediaArraval,
            firstYUVDecoded: this.firstYUVDecoded,
            firstRender: this.firstRender,
            returnFrames: this.returnFrames,
            sendOutBuffer: this.sendOutBuffer,
            maxGraphicTime: this.updateYUVCircular.getMax(),
            averageGraphicTime: this.updateYUVCircular.getAvg(),
            jankTimes: this.JankTimes,
            bigJankTimes: this.bigJankTimes,
            decodeJankTimes: this.DecodeJankTimes,
            bigDecodeJankTimes: this.bigDecodeJankTimes,
            serverFrameSlow: this.serverFrameSlow,
            serverFrameFast: this.serverFrameFast,
            clientFrameSlow: this.clientFrameSlow,
            clientFrameFast: this.clientFrameFast,
            rtcMessageReceived: this.rtcMessageReceived,
            rtcBytesReceived: this.rtcBytesReceived - this.noWasmBytesReceived,
            receiveIframes: this.receiveIframes,
            decodeIframes: this.decodeIframes,
            avgResponseTime: r,
            avgProcessTime: n,
            avgDisplayTime: o,
            avgOverallTime: a,
            overallTimeCount: s,
            responseMiss: this.responseMiss,
            processMiss: this.processMiss,
            displayMiss: this.displayMiss,
            updateDropFrame: this.updateDropFrame,
            moveEvent: this.moveEvent,
            avgResponseMoveDiff: this.moveEvent == "MoveTo" ? G : 0,
            avgProcessMoveDiff: this.moveEvent == "MoveTo" ? W : 0,
            avgDisplayMoveDiff: this.moveEvent == "MoveTo" ? j : 0,
            maxResponseMoveDiff: this.moveEvent == "MoveTo" ? B : 0,
            maxProcessMoveDiff: this.moveEvent == "MoveTo" ? X : 0,
            maxDisplayMoveDiff: this.moveEvent == "MoveTo" ? $ : 0,
            moveResponseJank: this.moveEvent == "MoveTo" ? g : 0,
            moveProcessJank: this.moveEvent == "MoveTo" ? P : 0,
            moveDisplayJank: this.moveEvent == "MoveTo" ? V : 0,
            moveResponseCounts: this.moveEvent == "MoveTo" ? m.toString() : "0,0,0,0,0",
            moveProcessCounts: this.moveEvent == "MoveTo" ? R.toString() : "0,0,0,0,0",
            moveDisplayCounts: this.moveEvent == "MoveTo" ? N.toString() : "0,0,0,0,0",
            MoveDisplayCountGood: this.moveEvent == "MoveTo" ? L.toString() : "0",
            MoveDisplayCountWell: this.moveEvent == "MoveTo" ? k.toString() : "0",
            MoveDisplayCountFair: this.moveEvent == "MoveTo" ? U.toString() : "0",
            MoveDisplayCountBad: this.moveEvent == "MoveTo" ? z.toString() : "0",
            MoveDisplayCountRest: this.moveEvent == "MoveTo" ? H.toString() : "0",
            moveResponseDelay: this.moveEvent == "MoveTo" ? this.MoveResponseDelay : 0,
            moveProcessDelay: this.moveEvent == "MoveTo" ? this.MoveProcessDelay : 0,
            moveDisplayDelay: this.moveEvent == "MoveTo" ? this.MoveDisplayDelay : 0,
            sdMoveResponseLongTime: Y,
            sdMoveProcessLongTime: K,
            sdMoveDisplayLongTime: Z,
            avgResponseFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? G : 0,
            avgProcessFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? W : 0,
            avgDisplayFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? j : 0,
            maxResponseFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? B : 0,
            maxProcessFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? X : 0,
            maxDisplayFlyDiff: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? $ : 0,
            flyResponseJank: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? g : 0,
            flyProcessJank: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? P : 0,
            flyDisplayJank: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? V : 0,
            flyResponseCounts: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? m.toString() : "0,0,0,0,0",
            flyProcessCounts: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? R.toString() : "0,0,0,0,0",
            flyDisplayCounts: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? N.toString() : "0,0,0,0,0",
            flyResponseDelay: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? this.MoveResponseDelay : 0,
            flyProcessDelay: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? this.MoveProcessDelay : 0,
            flyDisplayDelay: this.moveEvent == "GetOnVehicle" || this.moveEvent == "GetOnAirship" ? this.MoveDisplayDelay : 0,
            avgMetaParseTime: Q,
            maxMetaParseTime: te,
            avgServerDiff: q,
            maxServerDiff: J,
            streamType: WASM_Version
        };
        return this.lastReturnFrames = this.returnFrames,
        this.lastReceivedEmit = this.receivedEmit,
        re
    }
}