package com.jsc.dsp.utils;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.logging.Logger;

public class FileUtils {
    private final Logger logger = Logger.getLogger(this.getClass().getName());

    public FileUtils() {
    }

    public void UnzipTarGzip(String fileName, String fileUnzipPath) throws IOException {
        Path source = Paths.get(fileName);
        Path target = Paths.get(fileUnzipPath);

        if (Files.notExists(source)) {
            throw new IOException("Tar file not exist!");
        }

        //InputStream输入流，以下四个流将tar.gz读取到内存并操作
        //BufferedInputStream缓冲输入流
        //GzipCompressorInputStream解压输入流
        //TarArchiveInputStream解tar包输入流
        try (InputStream fi = Files.newInputStream(source);
             BufferedInputStream bi = new BufferedInputStream(fi);
             GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
             TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {

            ArchiveEntry entry;
            while ((entry = ti.getNextEntry()) != null) {
                Path newPath = zipSlipProtect(entry, target);
                if (entry.isDirectory()) {
                    Files.createDirectories(newPath);
                } else {
                    Path parent = newPath.getParent();
                    if (parent != null) {
                        if (Files.notExists(parent)) {
                            Files.createDirectories(parent);
                        }
                    }
                    Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING);

                }
            }
        }

    }

    //判断压缩文件是否被损坏，并返回该文件的解压目录
    private Path zipSlipProtect(ArchiveEntry entry, Path targetDir) throws IOException {
        Path targetDirResolved = targetDir.resolve(entry.getName());
        Path normalizePath = targetDirResolved.normalize();
        if (!normalizePath.startsWith(targetDir)) {
            throw new IOException("Tar file error: " + entry.getName());
        }
        return normalizePath;
    }

    private final HashSet<String> downloadedFileSet = new HashSet<>();

    /**
     * 从网络Url中下载文件
     *
     * @param urlStr url的路径
     */
    public int downloadFromUrl(String urlStr, String savePath) {
        try {
            if (downloadedFileSet.contains(urlStr)) {
                logger.warning("File exist from " + urlStr);
                return 2;
            }
            String[] urlCascade = urlStr.split("/");
            String fileName = urlCascade[urlCascade.length - 1];
            Long startTimestamp = System.currentTimeMillis();
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(60 * 1000);
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            InputStream inputStream = conn.getInputStream();
            byte[] getData = readInputStream(inputStream);
            //文件保存位置
            File saveDir = new File(savePath);
            if (!saveDir.exists()) { // 没有就创建该文件
                saveDir.mkdir();
            }
            File file = new File(saveDir + File.separator + fileName);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(getData);
            fos.close();
            inputStream.close();
            Long endTimestamp = System.currentTimeMillis();
            double durationSeconds = (endTimestamp - startTimestamp) / 1000.0;
            logger.info("File downloaded from " + urlStr + " (" + (file.length() / 1024 + 1) + " KB in " + durationSeconds + "s)");
            if (downloadedFileSet.size() > 1000) {
                logger.info("Reset downloaded file hash set...");
                downloadedFileSet.clear();
            }
            downloadedFileSet.add(urlStr);
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

    /**
     * 从输入流中获取字节数组
     */
    private byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[4 * 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 boolean saveStringToFile(String content, String fullPath) {
        try {
            FileOutputStream fos = new FileOutputStream(fullPath);
            fos.write(content.getBytes());
            fos.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static String readContentFromFile(String fullPath) {
        try {
            FileInputStream fi = new FileInputStream(fullPath);
            byte[] bytes = new byte[fi.available()];// 修改了这里
            int len;// 记录每次读取的字节的个数
            StringBuilder str = new StringBuilder();
            while ((len = fi.read(bytes)) != -1) {
                str.append(new String(bytes, 0, len));
            }
            return str.toString();
        } catch (Exception e) {
            return null;
        }
    }

    public void moveFileToBackupFolder(File transferFile, String keepBackupFile) {
        if (keepBackupFile.equals("del")) {
            transferFile.delete();
        } else {
            long transferFileModTimestamp = transferFile.lastModified();
            Calendar modTime = Calendar.getInstance();
            modTime.setTime(new Date(transferFileModTimestamp));
            String modYear = String.valueOf(modTime.get(Calendar.YEAR));
            String modMonth = String.valueOf(modTime.get(Calendar.MONTH) + 1);
            modMonth = modMonth.length() == 1 ? "0" + modMonth : modMonth;
            String modDay = String.valueOf(modTime.get(Calendar.DAY_OF_MONTH));
            modDay = modDay.length() == 1 ? "0" + modDay : modDay;
            String subDirByDate = String.format("%s/%s-%s/%s-%s-%s/",
                    modYear, modYear, modMonth, modYear, modMonth, modDay);
            File endDirection = new File(keepBackupFile + subDirByDate);
            if (!endDirection.exists()) {
                endDirection.mkdirs();
            }
            File backupFile = new File(keepBackupFile + subDirByDate + transferFile.getName());
            if (!transferFile.renameTo(backupFile)) {
                transferFile.delete();
            }
        }
    }

    public static void main(String[] args) {
        saveStringToFile("{\"aaa\":\"测试测试testtest\"}", "E:/yuxin/test.json");
    }
}
