# coding=utf-8
'''
unsigned char* -> POINTER(c_ubyte)
data: bytes
ubuffer = (c.c_ubyte * len(data))(*data)

from ctypes.wintypes import BOOL
'''
import ctypes as c
import sys
charset = "utf-8"
# charset = "gbk"

py_str = lambda x: x.decode(charset) if x is not None else None
str2bytes = lambda x: x.encode(charset) if x is not None else None
# str->const char*
py_str_c_c_char_p = lambda x: c.c_char_p(str2bytes(x))
# str->const wchar*
py_str_c_c_wchar_p = lambda x: c.c_wchar_p(x)
# str->char*
py_str_c_char_p = lambda x, size=None: c.cast(c.create_string_buffer(str2bytes(x), size), c.c_char_p)
# char*->str
c_char_p_py_str = lambda x, size=-1: c.string_at(x, size)


def lib_loader(dll_fps: dict, exported_functions: list):
    sp = str(sys.platform)
    dll_fp = dll_fps.get(sp)
    # create the library...
    if sp == "win32":
        lib = c.windll.LoadLibrary(dll_fp)
    else:
        lib = c.cdll.LoadLibrary(dll_fp)

    # register the functions...
    for item in exported_functions:
        func = getattr(lib, item[0])

        try:
            if item[1]:
                func.argtypes = item[1]

            func.restype = item[2]
        except KeyError:
            pass

        try:
            if item[3]:
                func.errcheck = item[3]
        except KeyError:
            print("Error assigning check function to %s", func)

    return lib


def lib_load_default(dll_fps: dict, exported_functions: list):
    try:
        _lib = lib_loader(dll_fps, exported_functions)
    except Exception as e:

        # logger.error(e)
        _lib = None
    return _lib


class BaseStructure(c.Structure):

    def __init__(self, **kwargs):
        """
        Ctypes.Structure with integrated default values.

        :param kwargs: values different to defaults
        :type kwargs: dict
        """

        values = type(self)._defaults_.copy()
        for (key, val) in kwargs.items():
            values[key] = val

        super().__init__(**values)  # Python 3 syntax
