from abc import ABC, abstractmethod


class Device:

    def __init__(self, device_id: int, gateway: int, name: str):
        self.id = device_id
        self.gateway = gateway
        self.name = name

    def __str__(self) -> str:
        return 'Name: {}, Id: {}, Gateway {}'.format(self.name, self.id, self.gateway)


class Parameter(ABC):

    @property
    @abstractmethod
    def value_id(self):
        ...

    @value_id.setter
    @abstractmethod
    def value_id(self, value_id: int):
        ...

    @property
    @abstractmethod
    def name(self):
        ...

    @property
    @abstractmethod
    def parameter_id(self):
        ...

    @property
    @abstractmethod
    def bundle_id(self):
        ...

    @property
    @abstractmethod
    def read_only(self):
        ...

    @property
    @abstractmethod
    def parent(self):
        ...

    def __str__(self) -> str:
        return "%s -> %s[%d][%d][%s][%d] of %s" % (self.__class__.__name__, self.name, self.parameter_id, self.bundle_id, self.read_only, self.value_id, self.parent)


class SimpleParameter(Parameter):
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def parent(self):
        return self._parent

    @property
    def parameter_id(self):
        return self._parameter_id
    
    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only


class UnitParameter(Parameter, ABC):
    @property
    @abstractmethod
    def unit(self):
        ...

    def __str__(self) -> str:
        return super().__str__() + " unit: [%s]" % self.unit


class Temperature(UnitParameter):
    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "°C"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id
    
    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class Pressure(UnitParameter):
    @property
    def unit(self):
        return 'bar'

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class HoursParameter(UnitParameter):
    @property
    def unit(self):
        return 'H'

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class PercentageParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "%"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only
    
    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class PowerParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "kW"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only
    
    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class EnergyParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "kWh"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only
    
    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class RPMParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "U/min"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class FlowParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "l/min"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class FrequencyParameter(UnitParameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def unit(self):
        return "Hz"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

class ListItem:
    name: str
    value: int

    def __init__(self, value: int, name: str):
        self.value = int(value)
        self.name = name

    def __str__(self) -> str:
        return '%d -> %s' % (self.value, self.name)


class ListItemParameter(Parameter):

    @property
    def parameter_id(self):
        return self._parameter_id

    @property
    def value_id(self):
        return self._value_id

    @value_id.setter
    def value_id(self, value_id: int):
        self._value_id = value_id

    @property
    def bundle_id(self):
        return self._bundle_id
    
    @property
    def read_only(self):
        return self._read_only

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name

    @property
    def parent(self):
        return self._parent

    def __init__(self, value_id: int, name: str, parent: str, items: list[ListItem], parameter_id: int, bundle_id: int, read_only: bool):
        self._value_id = value_id
        self._name = name
        self._parent = parent
        self.items = items
        self._parameter_id = parameter_id
        self._bundle_id = bundle_id
        self._read_only = read_only

    def __str__(self) -> str:
        return super().__str__() + " items: " + ", ".join([item.__str__() for item in self.items])


class Value:

    def __init__(self, value_id: int, value: str, state: str):
        self.value_id = value_id
        self.value = value
        self.state = state

    def __str__(self) -> str:
        return 'Value id: {}, value: {}, state {}'.format(self.value_id, self.value, self.state)

