# This file was generated by the "yardl" tool. DO NOT EDIT.

# pyright: reportUnusedClass=false
# pyright: reportUnusedImport=false
# pyright: reportUnknownArgumentType=false
# pyright: reportUnknownMemberType=false
# pyright: reportUnknownVariableType=false

import collections.abc
import io
import typing

import numpy as np
import numpy.typing as npt

from .types import *
from .protocols import *
from . import _binary
from . import yardl_types as yardl

class BinaryPrdExperimentWriter(_binary.BinaryProtocolWriter, PrdExperimentWriterBase):
    """Binary writer for the PrdExperiment protocol."""


    def __init__(self, stream: typing.Union[typing.BinaryIO, str]) -> None:
        PrdExperimentWriterBase.__init__(self)
        _binary.BinaryProtocolWriter.__init__(self, stream, PrdExperimentWriterBase.schema)

    def _write_header(self, value: Header) -> None:
        _HeaderSerializer().write(self._stream, value)

    def _write_time_blocks(self, value: collections.abc.Iterable[TimeBlock]) -> None:
        _binary.StreamSerializer(_TimeBlockSerializer()).write(self._stream, value)


class BinaryPrdExperimentReader(_binary.BinaryProtocolReader, PrdExperimentReaderBase):
    """Binary writer for the PrdExperiment protocol."""


    def __init__(self, stream: typing.Union[io.BufferedReader, io.BytesIO, typing.BinaryIO, str]) -> None:
        PrdExperimentReaderBase.__init__(self)
        _binary.BinaryProtocolReader.__init__(self, stream, PrdExperimentReaderBase.schema)

    def _read_header(self) -> Header:
        return _HeaderSerializer().read(self._stream)

    def _read_time_blocks(self) -> collections.abc.Iterable[TimeBlock]:
        return _binary.StreamSerializer(_TimeBlockSerializer()).read(self._stream)

class _CoincidenceEventSerializer(_binary.RecordSerializer[CoincidenceEvent]):
    def __init__(self) -> None:
        super().__init__([("detector_1_id", _binary.uint32_serializer), ("detector_2_id", _binary.uint32_serializer), ("tof_idx", _binary.uint32_serializer), ("energy_1_idx", _binary.uint32_serializer), ("energy_2_idx", _binary.uint32_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: CoincidenceEvent) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.detector_1_id, value.detector_2_id, value.tof_idx, value.energy_1_idx, value.energy_2_idx)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['detector_1_id'], value['detector_2_id'], value['tof_idx'], value['energy_1_idx'], value['energy_2_idx'])

    def read(self, stream: _binary.CodedInputStream) -> CoincidenceEvent:
        field_values = self._read(stream)
        return CoincidenceEvent(detector_1_id=field_values[0], detector_2_id=field_values[1], tof_idx=field_values[2], energy_1_idx=field_values[3], energy_2_idx=field_values[4])


class _SubjectSerializer(_binary.RecordSerializer[Subject]):
    def __init__(self) -> None:
        super().__init__([("name", _binary.OptionalSerializer(_binary.string_serializer)), ("id", _binary.string_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: Subject) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.name, value.id)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['name'], value['id'])

    def read(self, stream: _binary.CodedInputStream) -> Subject:
        field_values = self._read(stream)
        return Subject(name=field_values[0], id=field_values[1])


class _InstitutionSerializer(_binary.RecordSerializer[Institution]):
    def __init__(self) -> None:
        super().__init__([("name", _binary.string_serializer), ("address", _binary.string_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: Institution) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.name, value.address)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['name'], value['address'])

    def read(self, stream: _binary.CodedInputStream) -> Institution:
        field_values = self._read(stream)
        return Institution(name=field_values[0], address=field_values[1])


class _ExamInformationSerializer(_binary.RecordSerializer[ExamInformation]):
    def __init__(self) -> None:
        super().__init__([("subject", _SubjectSerializer()), ("institution", _InstitutionSerializer()), ("protocol", _binary.OptionalSerializer(_binary.string_serializer)), ("start_of_acquisition", _binary.OptionalSerializer(_binary.datetime_serializer))])

    def write(self, stream: _binary.CodedOutputStream, value: ExamInformation) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.subject, value.institution, value.protocol, value.start_of_acquisition)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['subject'], value['institution'], value['protocol'], value['start_of_acquisition'])

    def read(self, stream: _binary.CodedInputStream) -> ExamInformation:
        field_values = self._read(stream)
        return ExamInformation(subject=field_values[0], institution=field_values[1], protocol=field_values[2], start_of_acquisition=field_values[3])


class _DetectorSerializer(_binary.RecordSerializer[Detector]):
    def __init__(self) -> None:
        super().__init__([("id", _binary.uint32_serializer), ("x", _binary.float32_serializer), ("y", _binary.float32_serializer), ("z", _binary.float32_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: Detector) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.id, value.x, value.y, value.z)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['id'], value['x'], value['y'], value['z'])

    def read(self, stream: _binary.CodedInputStream) -> Detector:
        field_values = self._read(stream)
        return Detector(id=field_values[0], x=field_values[1], y=field_values[2], z=field_values[3])


class _ScannerInformationSerializer(_binary.RecordSerializer[ScannerInformation]):
    def __init__(self) -> None:
        super().__init__([("model_name", _binary.OptionalSerializer(_binary.string_serializer)), ("detectors", _binary.VectorSerializer(_DetectorSerializer())), ("tof_bin_edges", _binary.NDArraySerializer(_binary.float32_serializer, 1)), ("tof_resolution", _binary.float32_serializer), ("energy_bin_edges", _binary.NDArraySerializer(_binary.float32_serializer, 1)), ("energy_resolution_at_511", _binary.float32_serializer), ("listmode_time_block_duration", _binary.uint32_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: ScannerInformation) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.model_name, value.detectors, value.tof_bin_edges, value.tof_resolution, value.energy_bin_edges, value.energy_resolution_at_511, value.listmode_time_block_duration)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['model_name'], value['detectors'], value['tof_bin_edges'], value['tof_resolution'], value['energy_bin_edges'], value['energy_resolution_at_511'], value['listmode_time_block_duration'])

    def read(self, stream: _binary.CodedInputStream) -> ScannerInformation:
        field_values = self._read(stream)
        return ScannerInformation(model_name=field_values[0], detectors=field_values[1], tof_bin_edges=field_values[2], tof_resolution=field_values[3], energy_bin_edges=field_values[4], energy_resolution_at_511=field_values[5], listmode_time_block_duration=field_values[6])


class _HeaderSerializer(_binary.RecordSerializer[Header]):
    def __init__(self) -> None:
        super().__init__([("scanner", _ScannerInformationSerializer()), ("exam", _binary.OptionalSerializer(_ExamInformationSerializer()))])

    def write(self, stream: _binary.CodedOutputStream, value: Header) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.scanner, value.exam)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['scanner'], value['exam'])

    def read(self, stream: _binary.CodedInputStream) -> Header:
        field_values = self._read(stream)
        return Header(scanner=field_values[0], exam=field_values[1])


class _TimeBlockSerializer(_binary.RecordSerializer[TimeBlock]):
    def __init__(self) -> None:
        super().__init__([("id", _binary.uint32_serializer), ("prompt_events", _binary.VectorSerializer(_CoincidenceEventSerializer())), ("delayed_events", _binary.OptionalSerializer(_binary.VectorSerializer(_CoincidenceEventSerializer())))])

    def write(self, stream: _binary.CodedOutputStream, value: TimeBlock) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.id, value.prompt_events, value.delayed_events)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['id'], value['prompt_events'], value['delayed_events'])

    def read(self, stream: _binary.CodedInputStream) -> TimeBlock:
        field_values = self._read(stream)
        return TimeBlock(id=field_values[0], prompt_events=field_values[1], delayed_events=field_values[2])


class _TimeIntervalSerializer(_binary.RecordSerializer[TimeInterval]):
    def __init__(self) -> None:
        super().__init__([("start", _binary.uint32_serializer), ("stop", _binary.uint32_serializer)])

    def write(self, stream: _binary.CodedOutputStream, value: TimeInterval) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.start, value.stop)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['start'], value['stop'])

    def read(self, stream: _binary.CodedInputStream) -> TimeInterval:
        field_values = self._read(stream)
        return TimeInterval(start=field_values[0], stop=field_values[1])


class _TimeFrameInformationSerializer(_binary.RecordSerializer[TimeFrameInformation]):
    def __init__(self) -> None:
        super().__init__([("time_frames", _binary.VectorSerializer(_TimeIntervalSerializer()))])

    def write(self, stream: _binary.CodedOutputStream, value: TimeFrameInformation) -> None:
        if isinstance(value, np.void):
            self.write_numpy(stream, value)
            return
        self._write(stream, value.time_frames)

    def write_numpy(self, stream: _binary.CodedOutputStream, value: np.void) -> None:
        self._write(stream, value['time_frames'])

    def read(self, stream: _binary.CodedInputStream) -> TimeFrameInformation:
        field_values = self._read(stream)
        return TimeFrameInformation(time_frames=field_values[0])


