package bums.lunatic.launcher.utils

import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.util.zip.DeflaterOutputStream
import java.util.zip.InflaterInputStream
import kotlin.math.floor


object CompressStringUtil {
    val charsetName: String = "UTF-8"

    /**
     * String 객체를 압축하여 String 으로 리턴한다.
     * @param string
     * @return
     */
    @Synchronized
    fun compressString(string: String): String? {
        return byteToString(compress(string))
    }

    /**
     * 압축된 스트링을 복귀시켜서 String 으로 리턴한다.
     * @param compressed
     * @return
     */
    @Synchronized
    fun decompressString(compressed: String?): String {
        return decompress(hexToByteArray(compressed))
    }

    private fun byteToString(bytes: ByteArray?): String? {
        val sb = StringBuilder()
        try {
            for (b in bytes!!) {
                sb.append(String.format("%02X", b))
            }
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }

        return sb.toString()
    }

    private fun compress(text: String): ByteArray? {
        val baos = ByteArrayOutputStream()
        try {
            val out: OutputStream = DeflaterOutputStream(baos)
            out.write(text.toByteArray(charset(charsetName)))
            out.close()
        } catch (e: UnsupportedEncodingException) {
            e.printStackTrace()
            return null
        } catch (e: IOException) {
            e.printStackTrace()
            return null
        }
        return baos.toByteArray()
    }


    private fun decompress(bytes: ByteArray): String {
        val `in`: InputStream = InflaterInputStream(ByteArrayInputStream(bytes))
        val baos = ByteArrayOutputStream()
        try {
            val buffer = ByteArray(8192)
            var len: Int
            while ((`in`.read(buffer).also { len = it }) > 0) baos.write(buffer, 0, len)
            return String(baos.toByteArray(), charset(charsetName))
        } catch (e: IOException) {
            e.printStackTrace()
            throw AssertionError(e)
        }
    }

    /**
     * 16진 문자열을 byte 배열로 변환한다.
     */
    private fun hexToByteArray(hex: String?): ByteArray {
        if (hex == null || hex.length % 2 != 0) {
            return byteArrayOf()
        }

        val bytes = ByteArray(hex.length / 2)
        var i = 0
        while (i < hex.length) {
            val value = hex.substring(i, i + 2).toInt(16).toByte()
            bytes[floor((i / 2).toDouble()).toInt()] = value
            i += 2
        }
        return bytes
    }
}