package com.grkj.iscs_mc.extentions

import android.util.Base64
import com.grkj.iscs_mc.util.CRC16
import java.io.ByteArrayOutputStream
import kotlin.experimental.xor

fun ByteArray.startsWith(prefix: ByteArray): Boolean {
    require(this.size >= prefix.size) { "ByteArray is smaller than the prefix." }

    for (i in prefix.indices) {
        if (this[i] != prefix[i]) {
            return false
        }
    }
    return true
}

fun ByteArray.base64() : String {
    return Base64.encodeToString(this, Base64.NO_WRAP)
}

private val hexEncodingTable = byteArrayOf(
    '0'.toByte(), '1'.toByte(), '2'.toByte(), '3'.toByte(), '4'.toByte(), '5'.toByte(), '6'.toByte(), '7'.toByte(),
    '8'.toByte(), '9'.toByte(), 'A'.toByte(), 'B'.toByte(), 'C'.toByte(), 'D'.toByte(), 'E'.toByte(), 'F'.toByte()
)

fun ByteArray.toHexStrings(space: Boolean = true) : String {
    val out = ByteArrayOutputStream()
    try {
        for (i in 0 until size) {
            val v: Int = this[i].toInt() and 0xff
            out.write(hexEncodingTable[v ushr 4].toInt())
            out.write(hexEncodingTable[v and 0xf].toInt())
            if (space) {
                out.write(' '.toInt())
            }
        }
    } catch (e: java.lang.Exception) {
        throw IllegalStateException("exception encoding Hex string: " + e.message, e)
    }
    val bytes = out.toByteArray()
    return String(bytes)
}

const val RADIX_62 = 62

/**
 * 把[from, to) 部分的子数组，转换为以 0-9 a-z A-Z 共 62个字符组成的数字
 *
 * @param from 起始
 * @param to 结束（不包含）
 */
fun ByteArray.to62Num(from: Int, to: Int) : Int {
    var sum = 0
    var scale = 1
    for (i in to - 1 downTo from) {
        sum += from62(this[i]) * scale
        scale *= RADIX_62
    }
    return sum
}

/**
 * 把[from, to) 部分的字节做异或
 */
fun ByteArray.xor(from: Int, to: Int) : Byte {
    var res = this[from]
    for (i in (from + 1) until to) {
        res = res xor this[i]
    }
    return res
}

private fun from62(b: Byte): Int {
    if (b in 0x30..0x39) {
        return b - 0x30
    }
    if (b in 0x61..0x7a) {
        return b - 0x57
    }
    if (b in 0x41..0x5a) {
        return b - 0x1d
    }
    throw IllegalArgumentException("$b is not a num char")
}

/**
 * 计算 [from, to) 部分的字节做 的 CRC16 校验值
 * @return 两字节的校验值
 */
fun ByteArray.crc16(from: Int = 0, to: Int = size) : ByteArray {
    val value = CRC16.crc16(this, from.coerceAtLeast(0), to.coerceAtMost(size))
    val c1 = (0xff00 and value shr 8).toByte()
    val c2 = (0xff and value).toByte()
    return byteArrayOf(c1, c2)
}