# This file is autogenerated
import threading
import ctypes
import os
from pyautd3.native_methods.structs import Vector3, Quaternion, FfiFuture, LocalFfiFuture
from pyautd3.native_methods.autd3_driver import SamplingConfig, LoopBehavior, SyncMode, GainSTMMode, GPIOOut, GPIOIn, Segment, SilencerTarget, Drive
from pyautd3.native_methods.autd3capi_driver import ControllerBuilderPtr, GeometryPtr, HandlePtr, LinkPtr, ResultStatus


class EmulatorControllerPtr(ctypes.Structure):
    _fields_ = [("_0", ctypes.c_void_p)]


class EmulatorPtr(ctypes.Structure):
    _fields_ = [("_0", ctypes.c_void_p)]


class RecordPtr(ctypes.Structure):
    _fields_ = [("_0", ctypes.c_void_p)]


class SoundFieldPtr(ctypes.Structure):
    _fields_ = [("_0", ctypes.c_void_p)]


class RecordOption(ctypes.Structure):
    _fields_ = [("sound_speed", ctypes.c_float), ("time_step_ns", ctypes.c_uint64), ("print_progress", ctypes.c_bool), ("memory_limits_hint_mb", ctypes.c_uint64), ("gpu", ctypes.c_bool)]

    def __eq__(self, other: object) -> bool:
        return isinstance(other, RecordOption) and self._fields_ == other._fields_  # pragma: no cover


class Range(ctypes.Structure):
    _fields_ = [("x_start", ctypes.c_float), ("x_end", ctypes.c_float), ("y_start", ctypes.c_float), ("y_end", ctypes.c_float), ("z_start", ctypes.c_float), ("z_end", ctypes.c_float), ("resolution", ctypes.c_float)]

    def __eq__(self, other: object) -> bool:
        return isinstance(other, Range) and self._fields_ == other._fields_  # pragma: no cover


class ResultRecord(ctypes.Structure):
    _fields_ = [("result", RecordPtr), ("err_len", ctypes.c_uint32), ("err", ctypes.c_void_p)]

    def __eq__(self, other: object) -> bool:
        return isinstance(other, ResultRecord) and self._fields_ == other._fields_  # pragma: no cover


class ResultSoundField(ctypes.Structure):
    _fields_ = [("result", SoundFieldPtr), ("err_len", ctypes.c_uint32), ("err", ctypes.c_void_p)]

    def __eq__(self, other: object) -> bool:
        return isinstance(other, ResultSoundField) and self._fields_ == other._fields_  # pragma: no cover



class Singleton(type):
    _instances = {}  # type: ignore
    _lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            with cls._lock:
                if cls not in cls._instances: # pragma: no cover
                    cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class NativeMethods(metaclass=Singleton):

    def init_dll(self, bin_location: str, bin_prefix: str, bin_ext: str):
        self.dll = ctypes.CDLL(os.path.join(bin_location, f'{bin_prefix}autd3capi_emulator{bin_ext}'))

        self.dll.AUTDEmulatorTracingInit.argtypes = [] 
        self.dll.AUTDEmulatorTracingInit.restype = None

        self.dll.AUTDEmulatorTracingInitWithFile.argtypes = [ctypes.c_char_p] 
        self.dll.AUTDEmulatorTracingInitWithFile.restype = ResultStatus

        self.dll.AUTDEmulator.argtypes = [ControllerBuilderPtr]  # type: ignore 
        self.dll.AUTDEmulator.restype = EmulatorPtr

        self.dll.AUTDEmulatorFree.argtypes = [EmulatorPtr]  # type: ignore 
        self.dll.AUTDEmulatorFree.restype = None

        self.dll.AUTDEmulatorGeometry.argtypes = [EmulatorPtr]  # type: ignore 
        self.dll.AUTDEmulatorGeometry.restype = GeometryPtr

        self.dll.AUTDEmulatorRecordFrom.argtypes = [EmulatorPtr, ctypes.c_uint64, ctypes.c_void_p]  # type: ignore 
        self.dll.AUTDEmulatorRecordFrom.restype = FfiFuture

        self.dll.AUTDEmulatorRecordFree.argtypes = [RecordPtr]  # type: ignore 
        self.dll.AUTDEmulatorRecordFree.restype = None

        self.dll.AUTDEmulatorWaitResultRecord.argtypes = [HandlePtr, FfiFuture]  # type: ignore 
        self.dll.AUTDEmulatorWaitResultRecord.restype = ResultRecord

        self.dll.AUTDEmulatorTickNs.argtypes = [LinkPtr, ctypes.c_uint64]  # type: ignore 
        self.dll.AUTDEmulatorTickNs.restype = ResultStatus

        self.dll.AUTDEmulatorRecordNumDevices.argtypes = [RecordPtr]  # type: ignore 
        self.dll.AUTDEmulatorRecordNumDevices.restype = ctypes.c_uint16

        self.dll.AUTDEmulatorRecordNumTransducers.argtypes = [RecordPtr, ctypes.c_uint16]  # type: ignore 
        self.dll.AUTDEmulatorRecordNumTransducers.restype = ctypes.c_uint8

        self.dll.AUTDEmulatorRecordDriveLen.argtypes = [RecordPtr]  # type: ignore 
        self.dll.AUTDEmulatorRecordDriveLen.restype = ctypes.c_uint64

        self.dll.AUTDEmulatorRecordDriveTime.argtypes = [RecordPtr, ctypes.POINTER(ctypes.c_uint64)]  # type: ignore 
        self.dll.AUTDEmulatorRecordDriveTime.restype = None

        self.dll.AUTDEmulatorRecordDrivePulseWidth.argtypes = [RecordPtr, ctypes.c_uint16, ctypes.c_uint8, ctypes.POINTER(ctypes.c_uint8)]  # type: ignore 
        self.dll.AUTDEmulatorRecordDrivePulseWidth.restype = None

        self.dll.AUTDEmulatorRecordDrivePhase.argtypes = [RecordPtr, ctypes.c_uint16, ctypes.c_uint8, ctypes.POINTER(ctypes.c_uint8)]  # type: ignore 
        self.dll.AUTDEmulatorRecordDrivePhase.restype = None

        self.dll.AUTDEmulatorRecordOutputLen.argtypes = [RecordPtr]  # type: ignore 
        self.dll.AUTDEmulatorRecordOutputLen.restype = ctypes.c_uint64

        self.dll.AUTDEmulatorRecordOutputTime.argtypes = [RecordPtr, ctypes.POINTER(ctypes.c_uint64)]  # type: ignore 
        self.dll.AUTDEmulatorRecordOutputTime.restype = None

        self.dll.AUTDEmulatorRecordOutputVoltage.argtypes = [RecordPtr, ctypes.c_uint16, ctypes.c_uint8, ctypes.POINTER(ctypes.c_float)]  # type: ignore 
        self.dll.AUTDEmulatorRecordOutputVoltage.restype = None

        self.dll.AUTDEmulatorRecordOutputUltrasound.argtypes = [RecordPtr, ctypes.c_uint16, ctypes.c_uint8, ctypes.POINTER(ctypes.c_float)]  # type: ignore 
        self.dll.AUTDEmulatorRecordOutputUltrasound.restype = None

        self.dll.AUTDEmulatorSoundField.argtypes = [RecordPtr, Range, RecordOption]  # type: ignore 
        self.dll.AUTDEmulatorSoundField.restype = LocalFfiFuture

        self.dll.AUTDEmulatorWaitSoundField.argtypes = [HandlePtr, LocalFfiFuture]  # type: ignore 
        self.dll.AUTDEmulatorWaitSoundField.restype = ResultSoundField

        self.dll.AUTDEmulatorSoundFieldTimeLen.argtypes = [SoundFieldPtr, ctypes.c_uint64]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldTimeLen.restype = ctypes.c_uint64

        self.dll.AUTDEmulatorSoundFieldPointsLen.argtypes = [SoundFieldPtr]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldPointsLen.restype = ctypes.c_uint64

        self.dll.AUTDEmulatorSoundFieldGetX.argtypes = [SoundFieldPtr, ctypes.POINTER(ctypes.c_float)]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldGetX.restype = None

        self.dll.AUTDEmulatorSoundFieldGetY.argtypes = [SoundFieldPtr, ctypes.POINTER(ctypes.c_float)]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldGetY.restype = None

        self.dll.AUTDEmulatorSoundFieldGetZ.argtypes = [SoundFieldPtr, ctypes.POINTER(ctypes.c_float)]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldGetZ.restype = None

        self.dll.AUTDEmulatorSoundFieldSkip.argtypes = [SoundFieldPtr, ctypes.c_uint64]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldSkip.restype = LocalFfiFuture

        self.dll.AUTDEmulatorSoundFieldNext.argtypes = [SoundFieldPtr, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.POINTER(ctypes.c_float))]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldNext.restype = LocalFfiFuture

        self.dll.AUTDEmulatorSoundFieldFree.argtypes = [SoundFieldPtr]  # type: ignore 
        self.dll.AUTDEmulatorSoundFieldFree.restype = None

    def emulator_tracing_init(self) -> None:
        return self.dll.AUTDEmulatorTracingInit()

    def emulator_tracing_init_with_file(self, path: bytes) -> ResultStatus:
        return self.dll.AUTDEmulatorTracingInitWithFile(path)

    def emulator(self, builder: ControllerBuilderPtr) -> EmulatorPtr:
        return self.dll.AUTDEmulator(builder)

    def emulator_free(self, emulator: EmulatorPtr) -> None:
        return self.dll.AUTDEmulatorFree(emulator)

    def emulator_geometry(self, emulator: EmulatorPtr) -> GeometryPtr:
        return self.dll.AUTDEmulatorGeometry(emulator)

    def emulator_record_from(self, emulator: EmulatorPtr, start_time: int, f: ctypes.c_void_p | None) -> FfiFuture:
        return self.dll.AUTDEmulatorRecordFrom(emulator, start_time, f)

    def emulator_record_free(self, record: RecordPtr) -> None:
        return self.dll.AUTDEmulatorRecordFree(record)

    def emulator_wait_result_record(self, handle: HandlePtr, future: FfiFuture) -> ResultRecord:
        return self.dll.AUTDEmulatorWaitResultRecord(handle, future)

    def emulator_tick_ns(self, record: LinkPtr, tick_ns: int) -> ResultStatus:
        return self.dll.AUTDEmulatorTickNs(record, tick_ns)

    def emulator_record_num_devices(self, record: RecordPtr) -> ctypes.c_uint16:
        return self.dll.AUTDEmulatorRecordNumDevices(record)

    def emulator_record_num_transducers(self, record: RecordPtr, dev_idx: int) -> ctypes.c_uint8:
        return self.dll.AUTDEmulatorRecordNumTransducers(record, dev_idx)

    def emulator_record_drive_len(self, record: RecordPtr) -> ctypes.c_uint64:
        return self.dll.AUTDEmulatorRecordDriveLen(record)

    def emulator_record_drive_time(self, record: RecordPtr, time: ctypes.Array[ctypes.c_uint64] | None) -> None:
        return self.dll.AUTDEmulatorRecordDriveTime(record, time)

    def emulator_record_drive_pulse_width(self, record: RecordPtr, dev_idx: int, tr_idx: int, pulsewidth: ctypes.Array[ctypes.c_uint8] | None) -> None:
        return self.dll.AUTDEmulatorRecordDrivePulseWidth(record, dev_idx, tr_idx, pulsewidth)

    def emulator_record_drive_phase(self, record: RecordPtr, dev_idx: int, tr_idx: int, pulsewidth: ctypes.Array[ctypes.c_uint8] | None) -> None:
        return self.dll.AUTDEmulatorRecordDrivePhase(record, dev_idx, tr_idx, pulsewidth)

    def emulator_record_output_len(self, record: RecordPtr) -> ctypes.c_uint64:
        return self.dll.AUTDEmulatorRecordOutputLen(record)

    def emulator_record_output_time(self, record: RecordPtr, time: ctypes.Array[ctypes.c_uint64] | None) -> None:
        return self.dll.AUTDEmulatorRecordOutputTime(record, time)

    def emulator_record_output_voltage(self, record: RecordPtr, dev_idx: int, tr_idx: int, v: ctypes.Array[ctypes.c_float] | None) -> None:
        return self.dll.AUTDEmulatorRecordOutputVoltage(record, dev_idx, tr_idx, v)

    def emulator_record_output_ultrasound(self, record: RecordPtr, dev_idx: int, tr_idx: int, v: ctypes.Array[ctypes.c_float] | None) -> None:
        return self.dll.AUTDEmulatorRecordOutputUltrasound(record, dev_idx, tr_idx, v)

    def emulator_sound_field(self, record: RecordPtr, range: Range, option: RecordOption) -> LocalFfiFuture:
        return self.dll.AUTDEmulatorSoundField(record, range, option)

    def emulator_wait_sound_field(self, handle: HandlePtr, future: LocalFfiFuture) -> ResultSoundField:
        return self.dll.AUTDEmulatorWaitSoundField(handle, future)

    def emulator_sound_field_time_len(self, sound_field: SoundFieldPtr, duration_ns: int) -> ctypes.c_uint64:
        return self.dll.AUTDEmulatorSoundFieldTimeLen(sound_field, duration_ns)

    def emulator_sound_field_points_len(self, sound_field: SoundFieldPtr) -> ctypes.c_uint64:
        return self.dll.AUTDEmulatorSoundFieldPointsLen(sound_field)

    def emulator_sound_field_get_x(self, sound_field: SoundFieldPtr, x: ctypes.Array[ctypes.c_float] | None) -> None:
        return self.dll.AUTDEmulatorSoundFieldGetX(sound_field, x)

    def emulator_sound_field_get_y(self, sound_field: SoundFieldPtr, y: ctypes.Array[ctypes.c_float] | None) -> None:
        return self.dll.AUTDEmulatorSoundFieldGetY(sound_field, y)

    def emulator_sound_field_get_z(self, sound_field: SoundFieldPtr, z: ctypes.Array[ctypes.c_float] | None) -> None:
        return self.dll.AUTDEmulatorSoundFieldGetZ(sound_field, z)

    def emulator_sound_field_skip(self, sound_field: SoundFieldPtr, duration_ns: int) -> LocalFfiFuture:
        return self.dll.AUTDEmulatorSoundFieldSkip(sound_field, duration_ns)

    def emulator_sound_field_next(self, sound_field: SoundFieldPtr, duration_ns: int, time: ctypes.Array[ctypes.c_uint64] | None, v: ctypes.Array[ctypes.Array[ctypes.c_float]]) -> LocalFfiFuture:
        return self.dll.AUTDEmulatorSoundFieldNext(sound_field, duration_ns, time, v)

    def emulator_sound_field_free(self, sound_field: SoundFieldPtr) -> None:
        return self.dll.AUTDEmulatorSoundFieldFree(sound_field)
