package com.mogo.cloud.live.manager;


import com.mogo.cloud.live.listener.IYUVDataListener;
import com.zhidao.libyuv.Key;
import com.zhidao.libyuv.YuvUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * 视频帧管理
 */
public class CameraFrameManager {
    private static final int DST_WIDTH = 1280;
    private static final int DST_HEIGHT = 720;

    byte[] dst = null;
    byte[] tmp = null;

    private final Set<IYUVDataListener> globalDataListener = new HashSet<>();

    public static CameraFrameManager getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static final class SingletonHolder {
        private static final CameraFrameManager INSTANCE = new CameraFrameManager();
    }

    public void notifyYUVData(byte[] data, int width, int height, int type) {
        dispatchData(handleData(data, width, height, type));
    }

    /**
     * @param data   origin yuv data
     * @param width  data width
     * @param height data height
     * @param type   1:YV12 2:NV21 3:I420 4 nv12
     */
    private byte[] handleData(byte[] data, int width, int height, int type) {
        if (dst == null) {
            dst = new byte[DST_WIDTH * DST_HEIGHT * 3 / 2];
        }

        if (tmp == null) {
            tmp = new byte[848 * 480 * 3 / 2];
        }

        if (type == 4) {
            if (DST_WIDTH == width && DST_HEIGHT == height) {
                YuvUtils.NV12ToI420(data, dst, width, height);
                return dst;
            } else {
                YuvUtils.NV12ToI420(data, tmp, width, height);
                YuvUtils.I420Scale(tmp, width, height, dst, DST_WIDTH, DST_HEIGHT, Key.SCALE_MODE_NONE, false);
                return dst;
            }
        } else if (type == 3) {
            if (DST_WIDTH == width && DST_HEIGHT == height) {
                return data;
            } else {
                YuvUtils.I420Scale(data, width, height, dst, DST_WIDTH, DST_HEIGHT, Key.SCALE_MODE_NONE, false);
                return dst;
            }
        } else if (type == 2) {
            if (DST_WIDTH == width && DST_HEIGHT == height) {
                YuvUtils.NV21ToI420(data, dst, width, height, false);
                return dst;
            } else {
                YuvUtils.NV21ToI420(data, tmp, width, height, false);
                YuvUtils.I420Scale(tmp, width, height, dst, DST_WIDTH, DST_HEIGHT, Key.SCALE_MODE_NONE, false);
                return dst;
            }
        } else if (type == 1) {
            if (DST_WIDTH == width && DST_HEIGHT == height) {
                swapYV12toI420(data, dst, width, height);
                return dst;
            } else {
                swapYV12toI420(data, tmp, width, height);
                YuvUtils.I420Scale(tmp, width, height, dst, DST_WIDTH, DST_HEIGHT, Key.SCALE_MODE_NONE, false);
                return dst;
            }
        }
        return new byte[0];
    }

    public synchronized void addYuvDataCallback(IYUVDataListener callback) {
        if (callback != null) {
            globalDataListener.add(callback);
        }
    }

    public synchronized void rmYuvDataCallback(IYUVDataListener callback) {
        if (callback != null) {
            globalDataListener.remove(callback);
        }
    }

    public synchronized void release() {
        dst = null;
        tmp = null;
    }

    private void dispatchData(byte[] data) {
        if (globalDataListener.size() > 0) {
            for (IYUVDataListener callback : globalDataListener) {
                if (callback != null) {
                    callback.onFrame(data);
                }
            }
        }
    }

    private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height) {
        System.arraycopy(yv12bytes, 0, i420bytes, 0, width * height);
        System.arraycopy(yv12bytes, width * height + width * height / 4, i420bytes, width * height, width * height / 4);
        System.arraycopy(yv12bytes, width * height, i420bytes, width * height + width * height / 4, width * height / 4);
    }
}
