from .abstract_i2c_device import AbstractI2CDevice

class LM75(AbstractI2CDevice):
    """
    Dies ist die Implementierung des LM75 "Digitaler Temperatursensor".
    
    Diese Klasse unterstützt fast alle Funktionen des Geräts:
    * Auslesen der aktuellen Temperatur.
    * Einstellen der OS- und HYST-Temperaturen.
    * Konfiguration des Comparator/Interrupt-Modus für den O.S. Pin.
    * Einstellen der O.S. Polarität.

    Nicht unterstützte Funktionen:
    * Hard-Reset des Geräts.
    * Low-Power Shutdown-Modus.
    * Auslesen der Fault Queue.

    ### Pin-Konfiguration (SO8 Gehäuse):
    
    | Pin | Symbol     | Funktion                                  |
    |-----|------------|-------------------------------------------|
    | 1   | SDA        | Serielle Datenleitung                     |
    | 2   | SCL        | Serielle Taktleitung                      |
    | 3   | INT/CMPTR  | Interrupt- oder Komparator-Ausgang        |
    | 4   | Vss        | Masse (Ground)                            |
    | 5   | A2         | Adresseingang 2 (MSB)                     |
    | 6   | A1         | Adresseingang 1                           |
    | 7   | A0         | Adresseingang 0 (LSB)                     |
    | 8   | Vdd        | Versorgungsspannung (2,7 V bis 5,5 V)     |

    :author: Thomas Wagner
    """
    
    NAME = "LM75"
    CLASS = 0x09  # 1001 in binär
    
    # Register Pointer
    REG_TEMP = 0
    REG_CONFIG = 1
    REG_TEMP_HYST = 2
    REG_TEMP_OS = 3

    def __init__(self, device_address: int):
        if not (0 <= device_address <= 7):
            raise ValueError("Invalid device address 0-7")
        super().__init__(self.NAME, self.CLASS, device_address)
        
        self.last_register_pointer = -1
        self.t_current = 0.0
        self.t_os = 80.0
        self.t_hyst = 75.0

    def _init_device(self):
        try:
            self.get_t()
            self.get_t_os()
            self.get_t_hyst()
        except Exception as e:
            print(f"Error initializing LM75: {e}")

    def _convert_to_temp(self, msb: int, lsb: int) -> float:
        """Entspricht deiner Java Temperature Klasse"""
        # MSB ist das ganze Grad (Signed 8-bit)
        temp = msb
        if temp > 127:
            temp -= 256
        # LSB Bit 7 ist 0.5 Grad
        if lsb & 0x80:
            temp += 0.5
        return float(temp)

    def _set_register_pointer(self, pointer: int):
        if pointer == self.last_register_pointer:
            return
        # Java: int data[] = {devAddr.getWriteAddress(), pointer};
        self.i2c.write_i2c(self,[self.dev_addr.write_address, pointer])
        self.last_register_pointer = pointer

    def get_t(self) -> float:
        self._set_register_pointer(self.REG_TEMP)
        # Java: i2c.readI2C(this, data, 2)
        data = self.i2c.read_i2c(self,[self.dev_addr.read_address], 2)
        self.t_current = self._convert_to_temp(data[0], data[1])
        return self.t_current

    def get_t(self) -> float:
        self._set_register_pointer(self.REG_TEMP)
        # Früher: [self.read_address]
        # Jetzt: [self.dev_addr.read_address]
        data = self.i2c.read_i2c(self,[self.dev_addr.read_address], 2)
        return self._convert_to_temp(data[0], data[1])

    def get_t_os(self) -> float:
        self._set_register_pointer(self.REG_TEMP_OS)
        data = self.i2c.read_i2c(self,[self.dev_addr.read_address], 2)
        self.t_os = self._convert_to_temp(data[0], data[1])
        return self.t_os

    def get_t_hyst(self) -> float:
        self._set_register_pointer(self.REG_TEMP_HYST)
        data = self.i2c.read_i2c(self,[self.dev_addr.read_address], 2)
        self.t_hyst = self._convert_to_temp(data[0], data[1])
        return self.t_hyst

    def get_configuration(self):
        """Liest die aktuelle Konfiguration vom Sensor."""
        self._set_register_pointer(self.REG_CONFIG)
        # Wir lesen nur 1 Byte
        data = self.i2c.read_i2c(self,[self.dev_addr.read_address], 1)
        config_byte = data[0]

        # Bit 1 ist der Mode, Bit 2 ist die Polarity
        self.mode = (config_byte >> 1) & 0x01
        self.polarity = (config_byte >> 2) & 0x01
        
        # Nur für Debug-Zwecke (entspricht deinem System.out.println)
        # print(f"DEBUG: Mode={self.mode}, Polarity={self.polarity} (Raw: 0x{config_byte:02x})")
        
        return {"mode": self.mode, "polarity": self.polarity}

    def __str__(self):
        return f"{self.NAME}: Addr[0x{self.dev_addr}], T_curr[{self.t_current}°C]"