package com.mogo.cloud.util;

import android.util.Log;

import com.zhidao.libyuv.Key;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * YUV与RGB转换工具类
 */
public class YuvToolUtils {
    private static final String TAG = "YuvToolUtils";

    private static final int DST_WIDTH = 1280;
    private static final int DST_HEIGHT = 720;

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

    /**
     * @param data   origin yuv data
     * @param width  data width
     * @param height data height
     * @param type   1:YV12 2:NV21 3:I420 4 nv12
     */
    public static byte[] convertData(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) {
                com.zhidao.libyuv.YuvUtils.NV12ToI420(data, dst, width, height);
                return dst;
            } else {
                com.zhidao.libyuv.YuvUtils.NV12ToI420(data, tmp, width, height);
                com.zhidao.libyuv.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 {
                com.zhidao.libyuv.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) {
                com.zhidao.libyuv.YuvUtils.NV21ToI420(data, dst, width, height, false);
                return dst;
            } else {
                com.zhidao.libyuv.YuvUtils.NV21ToI420(data, tmp, width, height, false);
                com.zhidao.libyuv.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);
                com.zhidao.libyuv.YuvUtils.I420Scale(tmp, width, height, dst, DST_WIDTH, DST_HEIGHT, Key.SCALE_MODE_NONE, false);
                return dst;
            }
        }
        return new byte[0];
    }

    public static synchronized void release() {
        dst = null;
        tmp = null;
        Log.d(TAG, "release 释放临时帧");
    }

    /**
     * 将 YV12 格式转换为 I420
     *
     * @param yv12bytes 原始格式数据
     * @param i420bytes 转出格式数据
     * @param width     宽度
     * @param height    高度
     */
    public static void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height) {
        System.arraycopy(yv12bytes, 0, i420bytes, 0, width * height);
        int srcPos = width * height + width * height / 4;
        // 这里利用的是 YV12 和 I420 存储特性 ，将 U 和 V 数据进行调换
        System.arraycopy(yv12bytes, srcPos, i420bytes, width * height, width * height / 4);
        System.arraycopy(yv12bytes, width * height, i420bytes, srcPos, width * height / 4);
    }


    public static ArrayList<byte[]> splitYUVI420(byte[] i420bytes, int width, int height) {

        ArrayList<byte[]> yuvList = new ArrayList<>();

        byte[] yData = new byte[width * height];
        byte[] uData = new byte[width * height / 4];
        byte[] vData = new byte[width * height / 4];

        System.arraycopy(i420bytes, 0, yData, 0, width * height);
        System.arraycopy(i420bytes, width * height, uData, 0, width * height / 4);
        System.arraycopy(i420bytes, width * height + width * height / 4, vData, 0, width * height / 4);

        yuvList.add(yData);
        yuvList.add(uData);
        yuvList.add(vData);

        return yuvList;
    }


    public static LinkedBlockingQueue<byte[]> queueYUV = new LinkedBlockingQueue<>();
    public static boolean isSaveFile = true;

    public static void connectYUVFile(String filePath) {
        Thread writeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    File file = new File(filePath);
                    if (!file.exists()) {
                        boolean isOk = file.createNewFile();
                        if (isOk) {
                            Log.d(TAG, filePath + " 文件创建成功");
                        } else {
                            Log.w(TAG, filePath + " 文件已经存在");
                        }
                    }
                    FileOutputStream out = new FileOutputStream(filePath);
                    // 子线程中死循环
                    while (isSaveFile) {
                        // 拿数据
                        byte[] data = queueYUV.take();
                        // 往本地文件写入
                        out.write(data);
                        // 刷新
                        out.flush();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        writeThread.start();
    }


    /**
     * 写入文件
     *
     * @param path 文件路径
     * @param data YUV 数据
     * @return 是否写入成功
     */
    public static boolean writeFile(String path, byte[] data) {
        FileOutputStream out = null;
        try {
            File file = new File(path);
            File parent = file.getParentFile();
            if (parent != null && !parent.exists())
                parent.mkdirs();
            if (!file.exists()) {
                boolean isOk = file.createNewFile();
                if (isOk) {
                    out = new FileOutputStream(path);
                    out.write(data);
                    FileDescriptor fd = out.getFD();
                    fd.sync();
                }
                return true;
            } else {
                Log.d(TAG, path + " 文件已经存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }


}
