#!/usr/bin/env python
'''
@file augment_serial_io_module.py

@brief SerialIoModule: extends DeviceIoModule with Serial-specific functionality.
       Provides open/close operations and direct access to pyserial object.

Copyright (C) Atmosic 2025
'''
from __future__ import annotations

from typing import Optional
import serial
from deviceio.device_io_module import DeviceIoModule
from deviceio.serial_io_entry import SerialIoEntry


class SerialIoModule(DeviceIoModule):
    """Serial-specific I/O module that extends DeviceIoModule.
    
    - Provides open/close operations for serial port
    - Exposes pyserial object as property for advanced operations
    - Maintains all DeviceIoModule functionality (internal buffer, observers, etc.)
    - Supports context manager protocol for automatic open/close
    """

    def __init__(
        self,
        port: str,
        baudrate: int = 115200,
        rtscts: bool = False,
        stream_type: str = "ascii",
        timeout: Optional[float] = None,
        read_poll_interval: float = 0.001,
    ) -> None:
        """Initialize SerialIoModule with serial port parameters.
        
        Args:
            port: Serial port name (e.g., 'COM1', '/dev/ttyUSB0')
            baudrate: Baud rate for serial communication
            rtscts: Enable RTS/CTS flow control
            stream_type: Stream type ('ascii' or 'hex')
            timeout: Read timeout for serial operations
            read_poll_interval: Polling interval for read operations
        """
        # Create SerialIoEntry
        self._serial_entry = SerialIoEntry(
            port=port,
            baudrate=baudrate,
            rtscts=rtscts,
            stream_type=stream_type,
            timeout=timeout
        )
        
        # Initialize parent DeviceIoModule
        super().__init__(self._serial_entry, read_poll_interval)
        
        # Store serial parameters for reference
        self._port = port
        self._baudrate = baudrate
        self._rtscts = rtscts
        self._stream_type = stream_type
        self._timeout = timeout

    @property
    def pyserial(self) -> Optional[serial.Serial]:
        """Access to underlying pyserial Serial object.
        
        Returns:
            serial.Serial object if open, None if closed.
        """
        return self._serial_entry._ser

    @property
    def port(self) -> str:
        """Get the serial port name."""
        return self._port

    @property
    def baudrate(self) -> int:
        """Get the baud rate."""
        return self._baudrate

    @property
    def is_open(self) -> bool:
        """Check if serial port is open."""
        return self._serial_entry.is_open()

    def open(self) -> None:
        """Open the serial port and start receiver."""
        self._serial_entry.open()
        self._start_receiver()

    def close(self) -> None:
        """Close the serial port and stop receiver."""
        # Stop receiver before closing
        self._stop_receiver()
        self._serial_entry.close()

    def reopen_with_baudrate(self, new_baudrate: int) -> None:
        """Close and reopen with a new baudrate.

        Args:
            new_baudrate: New baudrate to use

        Returns:
            True if successful, False otherwise
        """
        self._stop_receiver()
        self._serial_entry.reopen_with_baudrate(new_baudrate)
        self._baudrate = new_baudrate
        self._start_receiver()

    # Context manager support
    def __enter__(self) -> 'SerialIoModule':
        """Enter context manager - open the serial port."""
        self.open()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        """Exit context manager - close the serial port."""
        self.close()



    def __repr__(self) -> str:
        """String representation of SerialIoModule."""
        status = "open" if self.is_open else "closed"
        return (f"SerialIoModule(port='{self._port}',"
               f" baudrate={self._baudrate}, status={status})")
