package play.utils

import android.os.Environment
import com.blankj.utilcode.util.Utils
import java.io.*
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipFile

/**
 * <p> 解压字体包的任务 </p>
 * @author 段自航 2021/9/22 20:20
 * @version V1.0
 */
class UnzipWorker {

    companion object {
        /**
         * 字体zip包解压路径
         */
        private val fontFilePath by lazy {
            getExternalAppFilesPath() + "/font"
        }

        fun shouldDoUnzip(): Boolean {
            val file = File("$fontFilePath/songti.ttf")
            if (file.exists()) {
                return false
            }
            return true
        }

        fun doWork() {
            val file = File("$fontFilePath/songti.ttf")
            if (file.exists()) {
                return
            }
            createOrExistsDir(fontFilePath)
            val zipUrl = "$fontFilePath/songti.zip"
            var outputStream: FileOutputStream? = null
            var inputStream: InputStream? = null
            try {
                inputStream = Utils.getApp().assets.open("songti.zip")
                outputStream = FileOutputStream(zipUrl)
                val buffer = ByteArray(1024)
                var byteCount = 0
                while (inputStream.read(buffer).also { byteCount = it } != -1) { //循环从输入流读取 buffer字节
                    outputStream.write(buffer, 0, byteCount) //将读取的输入流写入到输出流
                }
                outputStream.flush() //刷新缓冲区
                inputStream.close()
                outputStream.close()
            } catch (e: Exception) {
                e.printStackTrace()
                return
            }
            unzipFile(zipUrl, fontFilePath)
        }

        @Throws(IOException::class)
        fun unzipFile(zipFilePath: String?, destDirPath: String?): List<File?>? {
            return unzipFileByKeyword(
                getFileByPath(zipFilePath),
                getFileByPath(destDirPath),
                null as String?
            )
        }

        @Throws(IOException::class)
        fun unzipFileByKeyword(zipFile: File?, destDir: File?, keyword: String?): List<File?>? {
            return if (zipFile != null && destDir != null) {
                val files: MutableList<File> = mutableListOf()
                val zip = ZipFile(zipFile)
                val entries: Enumeration<*> = zip.entries()
                try {
                    var entry: ZipEntry
                    var entryName: String
                    val var8: List<File?>
                    if (isSpace(keyword)) {
                        while (entries.hasMoreElements()) {
                            entry = entries.nextElement() as ZipEntry
                            entryName = entry.name
                            if (!entryName.contains("../") && !unzipChildFile(
                                    destDir,
                                    files,
                                    zip,
                                    entry,
                                    entryName
                                )
                            ) {
                                var8 = files
                                return var8
                            }
                        }
                    } else {
                        while (entries.hasMoreElements()) {
                            entry = entries.nextElement() as ZipEntry
                            entryName = entry.name
                            if (!entryName.contains("../") && entryName.contains(keyword!!) && !unzipChildFile(
                                    destDir,
                                    files,
                                    zip,
                                    entry,
                                    entryName
                                )
                            ) {
                                var8 = files
                                return var8
                            }
                        }
                    }
                } finally {
                    zip.close()
                }
                files
            } else {
                null
            }
        }

        @Throws(IOException::class)
        private fun unzipChildFile(
            destDir: File,
            files: MutableList<File>,
            zip: ZipFile,
            entry: ZipEntry,
            name: String
        ): Boolean {
            val file = File(destDir, name)
            files.add(file)
            return if (entry.isDirectory) {
                createOrExistsDir(file)
            } else if (!createOrExistsFile(file)) {
                false
            } else {
                var `in`: InputStream? = null
                var out: BufferedOutputStream? = null
                try {
                    `in` = BufferedInputStream(zip.getInputStream(entry))
                    out = BufferedOutputStream(FileOutputStream(file))
                    val buffer = ByteArray(8192)
                    var len: Int
                    while (`in`.read(buffer).also { len = it } != -1) {
                        out.write(buffer, 0, len)
                    }
                } finally {
                    `in`?.close()
                    out?.close()
                }
                true
            }
        }


        private fun getExternalAppFilesPath(): String? {
            return if ("mounted" != Environment.getExternalStorageState()) "" else getAbsolutePath(
                Utils.getApp().getExternalFilesDir(null as String?)
            )
        }

        private fun getAbsolutePath(file: File?): String? {
            return if (file == null) "" else file.absolutePath
        }

        private fun getFileByPath(filePath: String?): File? {
            return if (isSpace(filePath)) null else File(filePath)
        }

        private fun isSpace(s: String?): Boolean {
            return if (s == null) {
                true
            } else {
                var i = 0
                val len = s.length
                while (i < len) {
                    if (!Character.isWhitespace(s[i])) {
                        return false
                    }
                    ++i
                }
                true
            }
        }

        private fun createOrExistsFile(file: File?): Boolean {
            if (file == null) return false
            if (file.exists()) return file.isFile
            return if (!createOrExistsDir(file.parentFile)) false else try {
                file.createNewFile()
            } catch (e: IOException) {
                e.printStackTrace()
                false
            }
        }

        private fun createOrExistsDir(dirPath: String?): Boolean {
            return createOrExistsDir(getFileByPath(dirPath))
        }

        private fun createOrExistsDir(file: File?): Boolean {
            return file != null && if (file.exists()) file.isDirectory else file.mkdirs()
        }
    }


}