"""Python libknot interface."""

import ctypes
import sys


class KnotLookup(ctypes.Structure):
    """Libknot lookup return structure."""

    _fields_ = [('id', ctypes.c_int), ('name', ctypes.c_char_p)]


class KnotRdataDescriptor(ctypes.Structure):
    """Rdata descriptor structure."""

    _fields_ = [('block_types', ctypes.c_int * 8), ('name', ctypes.c_char_p)]


class Knot(object):
    """Basic libknot interface."""

    LIBKNOT = None
    LIBKNOT_VERSION = "14"

    RCODE_NAMES = None

    STRERROR = None
    RDATA_DESC = None

    @classmethod
    def __init__(cls, path: str = None) -> None:
        """Loads shared libknot library.
           An explicit library path can be specified.
        """

        if cls.LIBKNOT:
            return

        if path is None:
            version = ""
            try:
                version = ".%u" % int(cls.LIBKNOT_VERSION)
            except Exception:
                pass

            if sys.platform == "darwin":
                path = "libknot%s.dylib" % version
            else:
                path = "libknot.so"

        cls.LIBKNOT = ctypes.cdll.LoadLibrary(path)

        cls.RCODE_NAMES = (KnotLookup * 32).in_dll(cls.LIBKNOT, "knot_rcode_names")

        cls.STRERROR = cls.LIBKNOT.knot_strerror
        cls.STRERROR.restype = ctypes.c_char_p
        cls.STRERROR.argtypes = [ctypes.c_int]

        cls.RDATA_DESC = cls.LIBKNOT.knot_get_rdata_descriptor
        cls.RDATA_DESC.restype = ctypes.POINTER(KnotRdataDescriptor)
        cls.RDATA_DESC.argtypes = [ctypes.c_ushort]

    @classmethod
    def rclass_str(cls, rclass: int) -> str:
        """Returns RRCLASS in text form."""

        if (rclass == 1):
            return "IN"
        elif (rclass == 3):
            return "CH"
        elif (rclass == 254):
            return "NONE"
        elif (rclass == 255):
            return "ANY"
        else:
            return "CLASS%i" % rclass

    @classmethod
    def rtype_str(cls, rtype: int) -> str:
        """Returns RRTYPE in text form."""

        descr = cls.RDATA_DESC(rtype).contents.name
        if descr:
            return descr.decode()
        else:
            return "TYPE%i" % rtype

    @classmethod
    def rcode_str(cls, rcode: int) -> str:
        """Returns RCODE in text form."""

        for item in cls.RCODE_NAMES:
            if item.name and item.id == rcode:
                return item.name.decode()
        return "RCODE%i" % rcode
