package com.platform.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

@Slf4j
public class FileUtils {

    //文件路径+名称
    private static String fileNameTemp;

    public static void uploadImg(String path, String base64Data)
            throws Exception {
        byte[] bt = null;
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            if (base64Data.startsWith("data:image/png;base64,")) {
                bt = decoder.decodeBuffer(base64Data.replace("data:image/png;base64,", ""));
            } else if (base64Data.startsWith("data:image/jpeg;base64,")) {
                bt = decoder.decodeBuffer(base64Data.replace("data:image/jpeg;base64,", ""));
            } else if (base64Data.startsWith("data:image/bmp;base64,")) {
                bt = decoder.decodeBuffer(base64Data.replace("data:image/bmp;base64,", ""));
            } else {
                return;
            }
            writeBinary(bt, path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void writeBinary(byte[] buf, String filePath) throws Exception {
        File fout = new File(filePath);
        if (!fout.getParentFile().exists()) {
            fout.getParentFile().mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(fout);
        ByteArrayInputStream stream = new ByteArrayInputStream(buf);
        BufferedOutputStream bos = new BufferedOutputStream(fos);//设置输出路径
        BufferedInputStream bis = new BufferedInputStream(stream);
        int b = -1;
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }
        bis.close();
        bos.close();
    }

    public static boolean createDir(String destDirName) {
        File dir = new File(destDirName);
        if (dir.exists()) {
            System.out.println("创建目录" + destDirName + "失败，目标目录已经存在");
            return false;
        }
        if (!destDirName.endsWith(File.separator)) {
            destDirName = destDirName + File.separator;
        }
        //创建目录  
        if (dir.mkdirs()) {
            System.out.println("创建目录" + destDirName + "成功！");
            return true;
        } else {
            System.out.println("创建目录" + destDirName + "失败！");
            return false;
        }
    }

    /**
     * 获取视频的第一帧
     * */
    public static boolean executeCodecs(String filePath, String targetFilePath, String targetFileName ,String imageMat){
        try {
            FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
            ff.start();
            /**
             * 如果拍摄的视频中带有旋转(rotate)信息，那么截取出来的图片就会被旋转
             * getVideoMetadata("rotate")方法可以获取到视频的旋转信息。
             * 根据获取到的rotate信息对ff.grabImage()得到的Frame进行旋转，
             * 但是Frame并没有提供旋转接口。但有一个IpImage对象提供了旋转方法
             */
            String rotate = ff.getVideoMetadata("rotate");
            Frame f;
            int i = 0;
            while (i < 1) {
                f = ff.grabImage();
                opencv_core.IplImage src = null;
                if (null != rotate && rotate.length() > 1) {
                    OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
                    src = converter.convert(f);
                    f = converter.convert(rotate(src, Integer.valueOf(rotate)));
                }
                doExecuteFrame(f, targetFilePath, targetFileName ,imageMat);
                i++;
            }
            ff.stop();
            return true;
        } catch (Exception e) {
            log.info("生成视频第一帧图片出错:{}" ,e);
        }
        return false;
    }

    /*
     * 旋转角度的
     */
    public static   opencv_core.IplImage rotate(opencv_core.IplImage src, int angle) {
        opencv_core.IplImage img = opencv_core.IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
        opencv_core.cvTranspose(src, img);
        opencv_core.cvFlip(img, img, angle);
        return img;
    }

    public static   void doExecuteFrame(Frame f, String targetFilePath, String targetFileName , String imageMat) {

        if (null == f || null == f.image) {
            return;
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        String fileName = targetFilePath + targetFileName + "." + imageMat;
        BufferedImage bi = converter.getBufferedImage(f);
        log.info("输出视频第一帧的图片的宽度:{},高度:{}" ,  bi.getWidth() , bi.getHeight());
        File output = new File(fileName);
        try {
            ImageIO.write(bi, imageMat, output);
        } catch (IOException e) {
            log.info("生成视频第一帧图片出错:{}" ,e);
        }
    }


    /**
     * 创建文件
     *
     * @param fileName    文件名称
     * @param fileContent 文件内容
     * @return 是否创建成功，成功则返回true
     */
    public static boolean createFile(String path, String fileName, String fileContent) {
        Boolean bool = false;
        fileNameTemp = path + fileName + ".json";//文件路径+名称+文件类型
        File file = new File(fileNameTemp);
        try {
            File folder = new File(path);
            if (!folder.exists()) {
                folder.mkdirs();
            }
            //如果文件不存在，则创建新的文件
            if (!file.exists()) {
                file.createNewFile();
                bool = true;
                System.out.println("success create file,the file is " + fileNameTemp);
                //创建文件成功后，写入内容到文件里
                writeFileContent(fileNameTemp, fileContent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bool;
    }

    /**
     * 向文件中写入内容
     *
     * @param filePath 文件路径与名称
     * @param newstr   写入的内容
     * @return
     * @throws IOException
     */
    public static boolean writeFileContent(String filePath, String newstr) throws IOException {
        Boolean bool = false;
        String filein = newstr + "\r\n";//新写入的行，换行
        String temp = "";

        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        FileOutputStream fos = null;
        PrintWriter pw = null;
        try {
            File file = new File(filePath);//文件路径(包括文件名称)
            //将文件读入输入流
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis);
            br = new BufferedReader(isr);
            StringBuffer buffer = new StringBuffer();

            //文件原有内容
            for (int i = 0; (temp = br.readLine()) != null; i++) {
                buffer.append(temp);
                // 行与行之间的分隔符 相当于“\n”
                buffer = buffer.append(System.getProperty("line.separator"));
            }
            buffer.append(filein);

            fos = new FileOutputStream(file);
            pw = new PrintWriter(fos);
            pw.write(buffer.toString().toCharArray());
            pw.flush();
            bool = true;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            //不要忘记关闭
            if (pw != null) {
                pw.close();
            }
            if (fos != null) {
                fos.close();
            }
            if (br != null) {
                br.close();
            }
            if (isr != null) {
                isr.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
        return bool;
    }
    public static String parseFile(MultipartFile multipartFile , String fileBackupPath , String newFileName) {
        File directory = new File(fileBackupPath);
        if (!directory.exists()) {
            directory.mkdirs();
        }
        String fileName = fileBackupPath.concat(newFileName);
        log.info("上传的文件名:{}", fileName);
        File file = new File(fileName);
        if(file.exists()){
            deleteFile(fileName);
            file = new File(fileName);
        }
        try {
            InputStream is = multipartFile.getInputStream();
            FileOutputStream os = new FileOutputStream(file);
            byte[] b = new byte[2048];
            int length;
            while ((length = is.read(b)) > 0) {
                os.write(b, 0, length);
            }
            is.close();
            os.close();
        } catch (IOException e) {
            log.info("文件存储本地出现异常:{}", e);
        }
        return fileName;
    }

    public static String parseFile(MultipartFile multipartFile , String fileBackupPath) {
        File directory = new File(fileBackupPath);
        if (!directory.exists()) {
            directory.mkdirs();
        }
        String fileName = fileBackupPath.concat(multipartFile.getOriginalFilename());
        log.info("上传的文件名:{}", fileName);
        File file = new File(fileName);
        if(file.exists()){
            deleteFile(fileName);
            file = new File(fileName);
        }
        try {
            InputStream is = multipartFile.getInputStream();
            FileOutputStream os = new FileOutputStream(file);
            byte[] b = new byte[2048];
            int length;
            while ((length = is.read(b)) > 0) {
                os.write(b, 0, length);
            }
            is.close();
            os.close();
        } catch (IOException e) {
            log.info("文件存储本地出现异常:{}", e);
        }
        return fileName;
    }





    /**
     * 删除单个文件
     *
     * @param fileName 要删除的文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 根据路径删除指定的目录，无论存在与否
     *
     * @param sPath 要删除的目录path
     * @return 删除成功返回 true，否则返回 false。
     */
    public static boolean deleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除目录以及目录下的文件
     *
     * @param sPath 被删除目录的路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            } //删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) {
                    break;
                }
            }
        }
        if (!flag) {
            return false;
        }
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    //按行读文件
    public static String readFile(String path) throws Exception {
        File f = new File(path);
        if (!f.exists()) {
            return null;
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(f));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toString();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            bos.close();
        }
    }

    public static boolean copyFile(String srcFileName, String destFileName, boolean overlay) {
        File srcFile = new File(srcFileName);
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            return false;
        } else if (!srcFile.isFile()) {
            return false;
        }
        // 判断目标文件是否存在
        File destFile = new File(destFileName);
        if (destFile.exists()) {
            // 如果目标文件存在并允许覆盖
            if (overlay) {
                // 删除已经存在的目标文件，无论目标文件是目录还是单个文件
                new File(destFileName).delete();
            }
        } else {
            // 如果目标文件所在目录不存在，则创建目录
            if (!destFile.getParentFile().exists()) {
                // 目标文件所在目录不存在
                if (!destFile.getParentFile().mkdirs()) {
                    // 复制文件失败：创建目标文件所在目录失败
                    return false;
                }
            }
        }
        // 复制文件
        int byteread = 0; // 读取的字节数
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            byte[] buffer = new byte[1024];

            while ((byteread = in.read(buffer)) != -1) {
                out.write(buffer, 0, byteread);
            }
            return true;
        } catch (IOException e) {
            return false;
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 从网络Url中下载文件
     *
     * @param urlStr
     * @param fileName
     * @param savePath
     * @return
     * @throws IOException
     */
    public static boolean downLoadFromUrl(String urlStr, String fileName, String savePath) {
        FileOutputStream fos = null;
        InputStream inputStream = null;
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置超时间为3秒
            conn.setConnectTimeout(3 * 1000);
            // 防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

            // 得到输入流
            inputStream = conn.getInputStream();
            // 获取自己数组
            byte[] getData = readInputStream(inputStream);

            // 文件保存位置
            File saveDir = new File(savePath);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            String filePath = saveDir + File.separator + fileName;
            String filePathFolder = filePath.substring(0, filePath.lastIndexOf("/") + 1);
            createDir(filePathFolder);

            File file = new File(filePath);
            fos = new FileOutputStream(file);
            fos.write(getData);
            if (fos != null) {
                fos.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            System.out.println("info:" + url + " download success");
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            return false;
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }


    public static void writeFile(String filePath, String str) throws IOException {
        File fout = new File(filePath);
        if (!fout.getParentFile().exists()) {
            fout.getParentFile().mkdirs();
        }
        if (!fout.exists()) {
            fout.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(fout);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
        bw.write(str);
        bw.close();
    }

    /**
     * 将byte数组写入文件
     *
     * @param path
     * @param fileName
     * @param content
     * @throws IOException
     */
    public static void writeFile(String path, String fileName, byte[] content)
            throws IOException {
        try {
            File f = new File(path);
            if (!f.exists()) {
                f.mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(path + fileName);
            fos.write(content);
            fos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 向json文件写入参数,重复的覆盖，多的新增
     *
     * @return
     */
    public static void writeJsonFile(String path, Map<String, Object> map) throws Exception {
        String str = readFile(path);
        JSONObject json = new JSONObject();
        if (str != null) {
            json = JSONObject.parseObject(str);
        } else {
            File file = new File(path);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if (!file.exists()) {
                file.createNewFile();
            }
        }
        Iterator entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry entry = (Map.Entry) entries.next();
            json.put(String.valueOf(entry.getKey()), entry.getValue());
        }

        writeFile(path, json.toString());
    }


    //删除文件夹
    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); //删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            myFilePath.delete(); //删除空文件夹
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //删除指定文件夹下的所有文件
    public static boolean delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        if (tempList != null) {
            for (int i = 0; i < tempList.length; i++) {
                if (path.endsWith(File.separator)) {
                    temp = new File(path + tempList[i]);
                } else {
                    temp = new File(path + File.separator + tempList[i]);
                }
                if (temp.isFile()) {
                    temp.delete();
                }
                if (temp.isDirectory()) {
                    delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
                    delFolder(path + "/" + tempList[i]);//再删除空文件夹
                    flag = true;
                }
            }
        }

        //再删除当前空文件夹
        file.delete();
        return flag;
    }

    public static List<String> readfileNamesForDirectory(String path, String except) {
        try {
            File file = new File(path);
            if (file.isDirectory()) {
                String[] fileNames = file.list();
                List<String> list = new ArrayList<String>();
                if (fileNames != null) {
                    for (int i = 0; i < fileNames.length; ++i) {
                        if (fileNames[i].toLowerCase().endsWith(except)) {
                            list.add(fileNames[i]);
                        }
                    }
                }

                return list;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //递归获取文件中所有文件的路径
    public static List<String> readfilePath(String path, List<String> urlList) {
        try {
            File file = new File(path);
            if (file != null && file.isDirectory()) {
                File[] files = file.listFiles();

                if (files != null) {
                    for (int i = 0; i < files.length; ++i) {
                        if (files[i].isDirectory()) {
                            readfilePath(files[i].getAbsolutePath(), urlList);
                        } else {
                            urlList.add(files[i].getAbsolutePath());
                        }
                    }
                }
                return urlList;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return urlList;
    }

    public static void saveImageToDisk(String accessToken, String mediaId, String picName, String picPath, InputStream inputStream)
            throws Exception {
        byte[] data = new byte[10240];
        int len = 0;
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(picPath + picName + ".amr");
            while ((len = inputStream.read(data)) != -1) {
                fileOutputStream.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param content base64内容
     * @param path    输出文件路径，需要后缀名
     * @return
     */
    public static boolean base64ToFileWriter(String content, String path) {
        if (content == null) {
            return false;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // decoder
            byte[] b = decoder.decodeBuffer(content);
            // processing data
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            OutputStream out = new FileOutputStream(path);
            out.write(b);
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取类路径（classes路径）
     */
    public static String getResource() {
        String path = "";
        try {
            path = ResourceUtils.getURL("classpath:").getPath();
            path = URLDecoder.decode(path, "utf-8");
        } catch (Exception e) {
        }
        return path;
    }

    /**
     * 判断文件大小处于限制内
     *
     * @param fileLen  文件长度
     * @param fileSize 限制大小
     * @param fileUnit 限制的单位（B,K,M,G）
     * @return
     */
    public static boolean checkFileSizeIsLimit(Long fileLen, double fileSize, String fileUnit) {
//        long len = file.length();
        double fileSizeCom = 0;
        if ("B".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen;
        } else if ("K".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / 1024;
        } else if ("M".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / (1024 * 1024);
        } else if ("G".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / (1024 * 1024 * 1024);
        }
        if (fileSizeCom > fileSize) {
            return false;
        }
        return true;

    }

}
