import warnings
from ctypes import *
import os
import platform
import glob

LIBS_PATH = os.path.dirname(os.path.dirname(__file__))


def lib_method_wrapper(named_func_pointer, argtypes, restype):
    wrapper = named_func_pointer
    wrapper.argtypes = argtypes
    wrapper.restype = restype

    return wrapper


class OS_Requirements():

    def __init__(self, lib_type: str, lib_path=""):
        self.__os_name = platform.system()
        self.__lib_type = lib_type
        self.__lib_specific_path = os.path.join(LIBS_PATH, lib_path if lib_path != "" else f"lib_{self.__lib_type.lower()}")

    def __gen_dll_path_for_win(self):
        dll_path = os.path.join(self.__lib_specific_path, f'{self.__lib_type}.dll')
        if not os.path.isfile(dll_path):
            dll_path = f'C:\\Program Files\\Unigraf\\Unigraf UCD Tools\\{self.__lib_type}.dll'

        return dll_path

    def __gen_lib_path_for_osx(self):
        lib_path = os.path.join(self.__lib_specific_path, f'lib{self.__lib_type}.dylib')
        return lib_path

    def __get_exe_path_for_win(self):
        dll_path = os.path.join(self.__lib_specific_path, f'{self.__lib_type}.exe')
        if not os.path.isfile(dll_path):
            dll_path = f'C:\\Program Files\\Unigraf\\Unigraf UCD Tools\\{self.__lib_type}.exe'

        return dll_path

    def __gen_lib_path_for_lin(self):
        full_dll_name = f'lib{self.__lib_type}.so'

        dll_path = os.path.join(self.__lib_specific_path, full_dll_name)
        if not os.path.isfile(dll_path):
            dll_path = glob.glob(f'/home/user/Downloads/*/sdk/python/common/tsi/tsi_devices/libs/lib_{self.__lib_type.lower()}/{full_dll_name}')
            if len(dll_path) > 0:
                dll_path = dll_path[0]
            else:
                dll_path = ""

        return dll_path

    def __gen_exe_path_for_lin_and_mac(self, is_linux):
        full_dll_name = f'lib{self.__lib_type}.so' if is_linux else f'lib{self.__lib_type}.'

        dll_path = os.path.join(self.__lib_specific_path, full_dll_name)
        if not os.path.isfile(dll_path):
            dll_path = glob.glob(f'/home/user/Downloads/*/sdk/python/common/tsi/tsi_devices/libs/lib_{self.__lib_type.lower()}/{full_dll_name}')
            if len(dll_path) > 0:
                dll_path = dll_path[0]
            else:
                dll_path = ""

        return dll_path

    def __get_lib_for_win(self):
        if os.path.exists(self.__gen_dll_path_for_win()):
            return windll.LoadLibrary(self.__gen_dll_path_for_win())
        else:
            warnings.warn(f"Failed to find library at {self.__gen_dll_path_for_win()}")

    def __get_lib_for_lin(self):
        if os.path.exists(self.__gen_lib_path_for_lin()):
            return cdll.LoadLibrary(self.__gen_lib_path_for_lin())
        else:
            warnings.warn(f"Failed to find library at {self.__gen_lib_path_for_lin()}")
            return None

    def __get_lib_for_osx(self):
        if os.path.exists(self.__gen_lib_path_for_osx()):
            return cdll.LoadLibrary(self.__gen_lib_path_for_osx())
        else:
            warnings.warn(f"Failed to find library at {self.__gen_lib_path_for_osx()}")
            return None

    def get_lib(self):
        if self.__os_name == 'Windows':
            return self.__get_lib_for_win()
        elif self.__os_name == 'Linux':
            return self.__get_lib_for_lin()
        elif self.__os_name == 'Darwin':
            return self.__get_lib_for_osx()
        else:
            raise Exception('Un-supported OS!')

    def get_additional_file(self):
        try:
            if self.__os_name == 'Windows':
                return self.__get_exe_path_for_win()
            elif self.__os_name == 'Linux':
                return self.__gen_exe_path_for_lin_and_mac(True)
            elif self.__os_name == 'Darwin':
                return self.__gen_exe_path_for_lin_and_mac(False)
            else:
                raise Exception('Un-supported OS!')
        except OSError:
            error = get_errno()
            print(f'Get error = {error} while loading {self.__lib_type} lib for {self.__os_name}!')
            if error == 193:
                print('Perhaps you are using a 64-bit python interpreter along with a 32-bit library, or vice versa.'
                      ' Need the same.')

    def get_path_to_lib(self):
        try:
            if self.__os_name == 'Windows':
                return self.__gen_dll_path_for_win()
            elif self.__os_name == 'Linux':
                return self.__gen_lib_path_for_lin()
            elif self.__os_name == 'Darwin':
                return self.__gen_lib_path_for_osx()
            else:
                raise Exception('Un-supported OS!')
        except OSError:
            error = GetLastError()
            print(f'Get error = {error} while loading {self.__lib_type} lib for {self.__os_name}!')
            if error == 193:
                print('Perhaps you are using a 64-bit python interpreter along with a 32-bit library, or vice versa.'
                      ' Need the same.')
