from selenium.webdriver.remote.webdriver import WebDriver

from selen_kaa.utils.custom_types import TimeoutType
from selen_kaa.waits import Wait


class ElementWaits:
    """True if condition is fulfilled else throws exception."""

    def __init__(self, se_web_element, webdriver: WebDriver, timeout: TimeoutType):
        self.__web_element = se_web_element
        self._timeout = timeout
        self._wait = Wait(webdriver)

    def be_visible(self, timeout: TimeoutType = None):
        """True when an element is visible on the html page.
        :param timeout: time to wait element visibility.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_be_visible(self.__web_element, timeout=timeout_)

    def be_invisible(self, timeout: TimeoutType = None):
        """True if an element is not visible on the html page.
        :param timeout: time to wait element visibility.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_be_invisible(self.__web_element, timeout_)

    def have_class(self, expected_class: str, timeout: TimeoutType = None):
        """True when an element has a specific class.
        :param expected_class: class_name for expected class (not css_selector).
        :param timeout: time to wait for an element to have a class name.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_get_class(self.__web_element, expected_class, timeout_)

    def include_element(self, child_selector: str, timeout: TimeoutType = None):
        """True when an element gets a desired child element.
        :param child_selector: a css or xpath selector for a child element.
        :param timeout: time to wait for the condition.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_include_child_element(
            self.__web_element,
            child_selector,
            timeout_
        )

    def contain_text(self, text: str, timeout: TimeoutType = None):
        """True if an element contains a provided text in its text attribute.
        Not precise comparision, e.g. returns True for:
        "some" in "this is some text"
        :param text: expected text.
        :param timeout: time to wait for the condition.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_contain_text(self.__web_element, text, timeout_)

    def have_similar_text(self, text: str, timeout: TimeoutType = None):
        """True if an element has a similar text in texts attribute.
        Not precise comparision, e.g. returns True for:
        "some" in "this is some text", " test\n" and "test", "TEST" and "test".
        Ignores whitespaces and is case insensitive.
        :param text: a text to compare for similarity.
        :param timeout: time to wait for the condition.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_have_similar_text(self.__web_element, text, timeout_)

    def have_exact_text(self, text: str, timeout: TimeoutType = None):
        """True if an element has exactly provided text, and no other text.
        Precise comparision, e.g. returns False if "some" == "this is some text"
        :param text: exact text to search inside an element
        :param timeout: time to wait for the condition.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_have_exact_text(self.__web_element, text, timeout_)

    def not_present_in_dom(self, timeout: TimeoutType = None):
        """True for an element to be stale or absent in DOM.
        :param timeout: equal to the self.timeout if other not passed.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_not_present(self.__web_element, timeout_)

    def be_on_the_screen(self, timeout: TimeoutType = None):
        """True for an element is present on the screen (inside the viewport).
        Checks if element's coordinates match viewport height and width.
        Different from `to_be_visible` as `to_be_visible` checks element has size > 1px
        and display is not `:none`.
        :param timeout: equal to the self.timeout if other not passed.

        """
        timeout_ = timeout if timeout is not None else self._timeout
        return self._wait.element_to_be_in_viewport(self.__web_element, timeout_)
