package com.jihe.punchnet.sdlan.network

import com.jihe.punchnet.sdlan.logs.TerminalLogger
import org.bouncycastle.util.Strings
import java.util.LinkedList
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.ReentrantReadWriteLock

data class RouteDetail(
    // Int representation of 255.255.255.0
    val mask: Int,
    val gw: Int,
    val maskedAddr: Int,
)

fun cidrToRouteDetail(cidr: String, gw: String): RouteDetail? {
    val ipAndMaskDigit = Strings.split(cidr, '/')
    if (ipAndMaskDigit.size != 2) {
        TerminalLogger.debugf { "cidr format error: ${cidr}" }
        return null
    }
    val ip = ipStringToInt(ipAndMaskDigit[0])
    val mask = maskDigitToInt(ipAndMaskDigit[1].toInt())

    if (ip == null || mask == null) {
        TerminalLogger.debugf { "cidr format error2: ${cidr}" }
        return null
    }

    val gateway = ipStringToInt(gw)
    if (gateway == null) {
        TerminalLogger.debugf { "gateway format error: ${gateway}" }
        return null
    }

    if ((ip and mask) != ip) {
        TerminalLogger.debugf { "net not masked" }
        return null
    }

    return RouteDetail(
        mask = mask,
        gw = gateway,
        maskedAddr = ip,
    )
}

fun maskIPToDigit(mask: Int): Int {
    var count = 0
    var temp = mask
    while (temp != 0) {
        temp = temp shl 1
        count += 1
    }
    return count
}

fun maskDigitToInt(digit: Int): Int? {
    if (digit <= 0 || digit >= 32) {
        return null
    }
    return ((1 shl (32-digit)) - 1).inv()
}

fun ipStringToInt(ip: String): Int? {
    val ipFiltered = ip.trim { it.isWhitespace() }
    val ipSeg = Strings.split(ipFiltered, '.')
    if (ipSeg.size != 4) {
        return null
    }
    return ((ipSeg[0].toInt() and 0xff) shl 24) +
            ((ipSeg[1].toInt() and 0xff) shl 16) +
            ((ipSeg[2].toInt() and 0xff) shl 8) +
            (ipSeg[3].toInt() and 0xff)

}

class RouteTable() {
    val lock = ReentrantReadWriteLock()

    val routeInfo: MutableList<RouteDetail> = mutableListOf()

    fun addRoute(vararg routes: RouteDetail) {
        try {
            lock.writeLock().lock()
            for (route in routes) {
                routeInfo.add(route)
            }
        } finally {
            lock.writeLock().unlock()
        }
    }

    fun clearRoute() {
        try {
            lock.writeLock().lock()
            routeInfo.clear()
        } finally {
            lock.writeLock().unlock()
        }
    }

    fun getGateway(ip: Int): Int? {
        try {
            lock.readLock().lock()
            for (item in routeInfo) {
                if ((ip and item.mask) == item.maskedAddr) {
                    return item.gw
                }
            }
            return null
        } finally {
            lock.readLock().unlock()
        }
    }

}

class RouteTable2(
    val initRouteInfo: List<RouteDetail>
) {
    val routeInfo: Array<RouteDetail> = initRouteInfo.toTypedArray()

    fun getGeteway(ip: Int): Int? {
        for (item in routeInfo) {
            if ((ip and item.mask) == item.maskedAddr) {
                return item.gw
            }
        }
        return null
    }
}