package net.northking.cctp.upperComputer.driver.agent.command;


import net.northking.cctp.upperComputer.driver.agent.command.data.ScreenVideoFrame;
import net.northking.cctp.upperComputer.driver.agent.command.protocol.AbstractProtocolCommand;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;

public class StartScreenVideoCommand extends AbstractProtocolCommand<StartScreenVideoCommand.Result> {

    /**
     * Constant quality mode
     */
    public static final int BITRATE_MODE_CQ = 0;
    /**
     * Variable bitrate mode
     */
    public static final int BITRATE_MODE_VBR = 1;
    /**
     * Constant bitrate mode
     */
    public static final int BITRATE_MODE_CBR = 2;
    /**
     * Constant bitrate mode with frame drops
     */
    public static final int BITRATE_MODE_CBR_FD = 3;

    private static StartScreenVideoCommand instance = null;

    public static StartScreenVideoCommand getInstance() {
        if (instance == null) {
            instance = new StartScreenVideoCommand();
        }
        return instance;
    }

    private int display = 0;
    private String mimeType = "video/avc";
    private String encoderName = "OMX.google.h264.encoder";
    private int width = 1080;
    private int height = 1920;
    private int frameRate = 60;
    private int bitRate = 8 * 1024 * 1024;
    private int bitRateMode = BITRATE_MODE_VBR;
    private int iFrameInterval = 10;
    private int profile = 8;
    private float maxFps = 0f;
    private long encoderTimeout = -1L;

    @Override
    public int getCommandId() {
        return 45;
    }

    public int getDisplay() {
        return display;
    }

    public void setDisplay(int display) {
        this.display = display;
    }

    public String getMimeType() {
        return mimeType;
    }

    public void setMimeType(String mimeType) {
        this.mimeType = mimeType;
    }

    public String getEncoderName() {
        return encoderName;
    }

    public void setEncoderName(String encoderName) {
        this.encoderName = encoderName;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getFrameRate() {
        return frameRate;
    }

    public void setFrameRate(int frameRate) {
        this.frameRate = frameRate;
    }

    public int getBitRate() {
        return bitRate;
    }

    public void setBitRate(int bitRate) {
        this.bitRate = bitRate;
    }

    public int getBitRateMode() {
        return bitRateMode;
    }

    public void setBitRateMode(int bitRateMode) {
        this.bitRateMode = bitRateMode;
    }

    public int getiFrameInterval() {
        return iFrameInterval;
    }

    public void setiFrameInterval(int iFrameInterval) {
        this.iFrameInterval = iFrameInterval;
    }

    public int getProfile() {
        return profile;
    }

    public void setProfile(int profile) {
        this.profile = profile;
    }

    public float getMaxFps() {
        return maxFps;
    }

    public void setMaxFps(float maxFps) {
        this.maxFps = maxFps;
    }

    public long getEncoderTimeout() {
        return encoderTimeout;
    }

    public void setEncoderTimeout(long encoderTimeout) {
        this.encoderTimeout = encoderTimeout;
    }

    @Override
    public void doSend(DataOutput output) throws IOException {
        output.writeInt(display);
        sendText(output, mimeType);
        sendText(output, encoderName);
        output.writeInt(width);
        output.writeInt(height);
        output.writeInt(frameRate);
        output.writeInt(bitRate);
        output.writeInt(bitRateMode);
        output.writeInt(iFrameInterval);
        output.writeInt(profile);
        output.writeFloat(maxFps);
        output.writeLong(encoderTimeout);
    }

    @Override
    public Result buildReceive(DataInput input) throws IOException {
        Result result = new Result();
        result.configCode = input.readInt();
        int cacheFrameCount = input.readInt();
        if (cacheFrameCount > 0) {
            for (int i = 0; i < cacheFrameCount; i++) {
                ScreenVideoFrame frame = new ScreenVideoFrame();
                frame.presentationTimeUs = input.readLong();
                frame.flags = input.readInt();
                int dataSize = input.readInt();
                byte[] data = new byte[dataSize];
                input.readFully(data);
                frame.data = data;
                result.cacheFrames.add(frame);
            }
        }

        return result;
    }

    @Override
    public String toString() {
        return "StartScreenVideoCommand{" +
                "display=" + display +
                ", mimeType='" + mimeType + '\'' +
                ", encoderName='" + encoderName + '\'' +
                ", width=" + width +
                ", height=" + height +
                ", frameRate=" + frameRate +
                ", bitRate=" + bitRate +
                ", bitRateMode=" + bitRateMode +
                ", iFrameInterval=" + iFrameInterval +
                ", profile=" + profile +
                ", maxFps=" + maxFps +
                ", encoderTimeout=" + encoderTimeout +
                '}';
    }

    public static class Result {
        /**
         * 配置有效状态码，0为成功有效
         */
        public int configCode = 0;

        /**
         * 执行启动时设备上存在的缓存帧<br>
         * 出现于执行本次启动屏幕视频流时已经有另一方已经提前启动了，且
         */
        public ArrayList<ScreenVideoFrame> cacheFrames = new ArrayList<>();

    }

}
