import {BufferNode, BufferQueue, ImagePool} from './BufferNode.js';
import YUVWebGLCanvas from './WebGLCanvas.js';

let Uniformity = true;
let channelId = 0;
let canvas = null;
let drawer = null;
let preWidth = null;
let preHeight = null;
let drawingStrategy = null;
let frameInterval = null;
let prevCodecType = null;
let resizeCallback = null;
let startTimestamp = 0;
let frameTimestamp = null;
let preTimestamp = 0;
let progressTime = 0;
let curTime = 0;
let imagePool = new ImagePool;
let bufferNode = null;
let fileName = "";
let captureFlag = false;
let isRendering = false;
let defaultInterval = 16.7;
let defaultMaxDelay = 20;
let milisecond = 1e3;
let maxDelay = null;

let videoBufferQueue = null;

let canvasElem = null;

class VideoBufferNode extends BufferNode{
    constructor(data, width, height, codecType, frameType, timeStamp){
        super();
        //console.log(data)
        this.buffer = data;
        this.width = width;
        this.height = height;
        this.codecType = codecType;
        this.frameType = frameType;
        this.timeStamp = timeStamp
    }
}

class VideoBufferQueue extends BufferQueue{

    constructor() {
        super();
        this.MAX_LENGTH = 30;
    }

    enqueue(data, width, height, codecType, frameType, timeStamp) {
        //console.log(arguments)
        if(this.size >= this.MAX_LENGTH) {
            this.clear();
        }
        let node = new VideoBufferNode(data, width, height, codecType, frameType, timeStamp);
        if (this.first === null) {
            this.first = node
        } else {
            let tempNode = this.first;
            while (tempNode.next !== null) {
                tempNode = tempNode.next
            }
            tempNode.next = node
        }
        this.size += 1;
        return node
    }
}

class Size {
    constructor(width, height) {
        this.w = width;
        this.h = height;
    }

    toString() {
        return "(" + this.w + ", " + this.h + ")"
    }

    getHalfSize() {
        return new Size(this.w >>> 1, this.h >>> 1)
    }

    length() {
        return this.w * this.h
    }
}

class YUVPlayer {
    constructor(canvas){
        drawingStrategy = "YUVWebGL";
        prevCodecType = null;
        videoBufferQueue = new VideoBufferQueue;
        frameInterval = defaultInterval;
        isRendering = false
        canvasElem = canvas;
    }

    draw(data, width, height, codecType, frameType, timeStamp) {
        if (videoBufferQueue !== null) {
            videoBufferQueue.enqueue(data, width, height, codecType, frameType, timeStamp)
        }
    }

    startRendering() {
        if (startTimestamp === 0 && Uniformity !== false) {
            isRendering = true;
            window.requestAnimationFrame(drawingInTime)
        }
    }

    stopRendering() {
        isRendering = false;
        startTimestamp = 0
    }

    setFPS(fps) {
        if (typeof fps === "undefined") {
            frameInterval = defaultInterval;
            maxDelay = defaultMaxDelay
        } else if (fps === 0) {
            frameInterval = defaultInterval;
            maxDelay = defaultMaxDelay
        } else {
            frameInterval = milisecond / fps;
            maxDelay = fps * 1
        }
    }

    terminate() {
        startTimestamp = 0;
        frameTimestamp = null;
        if (videoBufferQueue !== null) {
            videoBufferQueue.clear();
            videoBufferQueue = null
        }
        drawer = null
    }
}

function resize(width, height) {
    let size = new Size(width, height);
    canvas = canvasElem;
    switch (drawingStrategy) {
        case"YUVWebGL":
            drawer = new YUVWebGLCanvas(canvas, size);
            break;
        default:
            break
    }
}

function drawFrame(stepValue) {

    bufferNode = videoBufferQueue.dequeue();
    if (bufferNode !== null && bufferNode.buffer !== null && (bufferNode.codecType === "mjpeg" || bufferNode.buffer.length > 0)) {
        if (typeof preWidth === "undefined" || typeof preHeight === "undefined" || preWidth !== bufferNode.width || preHeight !== bufferNode.height || prevCodecType !== bufferNode.codecType) {
            drawingStrategy = bufferNode.codecType === "h264" || bufferNode.codecType === "h265" ? "YUVWebGL" : "ImageWebGL";
            resize(bufferNode.width, bufferNode.height);
            preWidth = bufferNode.width;
            preHeight = bufferNode.height;
            prevCodecType = bufferNode.codecType;
            if (typeof resizeCallback !== "undefined" && resizeCallback !== null) {
                resizeCallback("resize")
            }
        }
        frameTimestamp = bufferNode.timeStamp;
        //workerManager.timeStamp(frameTimestamp);
        if (typeof drawer !== "undefined") {
            drawer.drawCanvas(bufferNode.buffer);
            canvas.updatedCanvas = true;
            // if (captureFlag) {
            //     captureFlag = false;
            //     doCapture(canvas.toDataURL(), fileName)
            // }
            if (bufferNode.codecType === "mjpeg") {
                imagePool.free(bufferNode.buffer)
            } else {
                delete bufferNode.buffer;
                bufferNode.buffer = null
            }
            bufferNode.previous = null;
            bufferNode.next = null;
            bufferNode = null;
            return true
        } else {
            console.log("drawer is undefined in StreamDrawer!")
        }
    } else {
    }
    return false
}

function drawingInTime(timestamp) {
    let stampCheckTime = 200;
    if (isRendering === true) {
        if (startTimestamp === 0 || timestamp - startTimestamp < stampCheckTime) {
            if (startTimestamp === 0) {
                startTimestamp = timestamp
            }
            if (videoBufferQueue !== null) {
                window.requestAnimationFrame(drawingInTime)
            }
            return
        }
        curTime += timestamp - preTimestamp;
        if (curTime > progressTime) {
            if(drawFrame()) {
                progressTime += frameInterval
            }
        }
        if (curTime > milisecond) {
            progressTime = 0;
            curTime = 0
        }
        preTimestamp = timestamp;
        window.requestAnimationFrame(drawingInTime)
    }
}

function drawImage(data) {
    if (typeof preWidth === "undefined" || typeof preHeight === "undefined" || preWidth !== data.width || preHeight !== data.height) {
        drawingStrategy = "ImageWebGL";
        resize(data.width, data.height);
        preWidth = data.width;
        preHeight = data.height;
        resizeCallback("resize")
    }
    frameTimestamp = data.time;
    if (frameTimestamp !== null) {
        //workerManager.timeStamp(frameTimestamp)
    }
    if (typeof drawer !== "undefined") {
        drawer.drawCanvas(data);
        if (captureFlag) {
            captureFlag = false;
            //doCapture(canvas.toDataURL(), fileName)
        }
        imagePool.free(data);
        return true
    } else {
        console.log("drawer is undefined in StreamDrawer!")
    }
    return false
}

export default YUVPlayer;
