import os
import re
import sys
from ctypes import *

if sys.version_info >= (3,0):
    import urllib.parse

try: 
    from libximc import *
except ImportError as err:
    cur_dir = os.path.abspath(os.path.dirname(__file__))
    ximc_dir = os.path.join(cur_dir, "..", "..", "..", "ximc")
    ximc_package_dir = os.path.join(ximc_dir, "crossplatform", "wrappers", "python")
    sys.path.append(ximc_package_dir)
    from libximc import *


def choose_device() -> bytes:
    devenum, device_count = search_devices()
    if device_count < 1:
        print("The real controller is not found or busy with another app.\nThe virtual controller is opening to check "
              "the operation of the library...")
        device_name = create_virtual_device_name()
    else:
        device_name = get_device_name_from_list(devenum, device_count)
    lib.free_enumerate_devices(devenum)
    return device_name


def create_virtual_device_name() -> bytes:
    path = os.path.expanduser("~") + "/virt_controller.bin"
    if os.altsep:
        path = path.replace(os.sep, os.altsep)
    # urlparse build wrong path if scheme is not file
    uri = urllib.parse.urlunparse(urllib.parse.ParseResult(scheme="file", netloc=None, path=path, params=None,
                                                           query=None, fragment=None))
    device_name = re.sub(r"^file", "xi-emu", uri).encode()
    print("Virtual controller file path: '{}'".format(path))
    return device_name


def get_device_name_from_list(devenum, device_count) -> bytes:
    while True:
        print_device_list(devenum, device_count)
        print("When using an Ethernet (TCP protocol) connection, multi-user interaction with the device is possible. "
              "In this case, the same device may be controlled simultaneously from multiple sources, which can "
              "potentially lead to control conflicts.\nEnter device number from the list:")
        try:
            number = int(input())
        except Exception:
            continue

        if 1 <= number <= device_count:
            device_name = lib.get_device_name(devenum, number - 1)
            print("Selected device: '{}'".format(device_name.decode("utf-8")))
            return device_name

        if number == device_count + 1:
            return create_virtual_device_name()


def print_device_list(devenum, device_count) -> None:
    print("\nFound devices list:")
    for i in range(device_count):
        raw_name = lib.get_device_name(devenum, i)
        device_name = raw_name.decode("utf-8")
        print(" #{}. {}".format(i + 1, device_name))
    print(" #{}. virtual".format(max(device_count, 0) + 1))


def search_devices():
    print("\nSearching for devices...")
    probe_flags = EnumerateFlags.ENUMERATE_PROBE | EnumerateFlags.ENUMERATE_NETWORK
    enumerate_hints = b"addr="
    devenum = lib.enumerate_devices(probe_flags, enumerate_hints)
    if not devenum:
        print("Error searching for devices")
        return devenum, 0

    device_count = lib.get_device_count(devenum)
    if device_count < 1:
        print("No devices found")
        return devenum, device_count

    print("Found {} devices".format(device_count + 1))
    return devenum, device_count


def warn_user_about_modifications() -> bool:
    while True:
        answer = input("\nThe script will modify all controller settings. Continue? [y/n]:\n")
        if answer.lower() == "y":
            return False

        if answer.lower() == "n":
            return True


def main() -> None:
    # A compilation of the profile file
    exec(compile(open("8MT173-25-MEn1.py").read(), "8MT173-25-MEn1", "exec"), globals())

    # variable 'lib' points to a loaded library
    # note that ximc uses stdcall on win
    sbuf = create_string_buffer(64)
    lib.ximc_version(sbuf)
    print("This is a ximc test program\nlibximc version " + sbuf.raw.decode().rstrip("\0"))

    if warn_user_about_modifications():
        return

    device_name = choose_device()
    print("\nOpening device...", end="")
    device = lib.open_device(device_name)
    if device == Result.NoDevice:
        print("\nError opening device\nPress Enter to exit...")
        return
    print(" Done")

    print("Setting profile for 8MT173-25...", end="")
    result = set_profile_8MT173_25_MEn1(lib, device)
    print(" Done. Result: {}".format(result))

    print("Closing device...", end="")
    # The device_t device parameter in this function is a C pointer, unlike most library functions that use this parameter
    lib.close_device(byref(cast(device, POINTER(c_int))))
    print(" Done")
    input("Press Enter to exit...")


if __name__ == "__main__":
    main()
