"""KeypadLink toggle button property."""
from . import calc_toggle_mode, get_usable_value
from ..constants import ToggleMode
from ..utils import bit_is_set, set_bit
from .derived_property import DerivedProperty


class ToggleButtonProperty(DerivedProperty):
    """KeypadLink toggle button property."""

    def __init__(
        self, address, name, button, non_toggle_mask_prop, non_toggle_on_off_mask_prop
    ):
        """Init the ToggleButtonProperty class."""
        super().__init__(address, name, ToggleMode, False, False)
        self._button_bit = button - 1
        self._non_toggle_mask_prop = non_toggle_mask_prop
        self._non_toggle_on_off_mask_prop = non_toggle_on_off_mask_prop

    @property
    def value(self):
        """Return the toggle mode of the undlying properties."""
        if not self.is_loaded:
            return None
        toggle_value = bit_is_set(self._non_toggle_mask_prop.value, self._button_bit)
        toggle_on_value = bit_is_set(
            self._non_toggle_on_off_mask_prop.value, self._button_bit
        )
        return calc_toggle_mode(toggle_value, toggle_on_value)

    @property
    def new_value(self):
        """Return the modified toggle mode of the button."""
        if not self.is_dirty:
            return None

        toggle_prop_value = get_usable_value(self._non_toggle_mask_prop)
        toggle_on_off_value = get_usable_value(self._non_toggle_on_off_mask_prop)
        toggle = bit_is_set(toggle_prop_value, self._button_bit)
        toggle_on = bit_is_set(toggle_on_off_value, self._button_bit)
        return calc_toggle_mode(toggle, toggle_on)

    @new_value.setter
    def new_value(self, value):
        """Set the new toggle mode value of the button."""
        if not self.is_loaded:
            return

        if value is None:
            self._non_toggle_mask_prop.new_value = None
            self._non_toggle_on_off_mask_prop.new_value = None
            return

        toggle_mode = ToggleMode(value)
        if toggle_mode == self.value:
            self._non_toggle_mask_prop.new_value = None
            self._non_toggle_on_off_mask_prop.new_value = None
            return

        non_toggle_mask = self._non_toggle_mask_prop
        on_only_mask = self._non_toggle_on_off_mask_prop
        non_toggle_val = get_usable_value(non_toggle_mask)
        on_only_val = get_usable_value(on_only_mask)
        if toggle_mode == ToggleMode.TOGGLE:
            non_toggle_mask.new_value = set_bit(non_toggle_val, self._button_bit, False)
            on_only_mask.new_value = set_bit(on_only_val, self._button_bit, False)
        elif toggle_mode == ToggleMode.ON_ONLY:
            non_toggle_mask.new_value = set_bit(non_toggle_val, self._button_bit, True)
            on_only_mask.new_value = set_bit(on_only_val, self._button_bit, True)
        else:
            non_toggle_mask.new_value = set_bit(non_toggle_val, self._button_bit, True)
            on_only_mask.new_value = set_bit(on_only_val, self._button_bit, False)

    @property
    def is_dirty(self):
        """Return the change state of the underlying properties."""
        return (
            self._non_toggle_mask_prop.is_dirty
            or self._non_toggle_on_off_mask_prop.is_dirty
        )

    @property
    def is_loaded(self):
        """Return the load status of the underlying properties."""
        return (
            self._non_toggle_mask_prop.is_loaded
            and self._non_toggle_on_off_mask_prop.is_loaded
        )
