import time

from selenium import webdriver
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.common.exceptions import TimeoutException, StaleElementReferenceException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class Browser:
  DRIVER_PATH = r'./geckodriver'
  TIMEOUT = 5

  def __init__(self, headless=True):
    self.uri = None
    self.headless = headless
    self.options = FirefoxOptions()
    self.options.headless = headless
    self.driver = webdriver.Firefox(executable_path=self.DRIVER_PATH, options=self.options)
  
  def open_uri(self, uri, allow_refresh=False):
    if self.driver.current_url != uri or allow_refresh:
      self.driver.get(uri)
      self.find('/html', None, self.TIMEOUT)
      return True
    return False

  def find(self, xpath, element=None, timeout=TIMEOUT):
    while True:
      try:
        if element is None:
          return WebDriverWait(self.driver, timeout).until(EC.presence_of_element_located((By.XPATH, xpath)))
        return element.find_element_by_xpath(xpath)
      except TimeoutException:
        return None
      except StaleElementReferenceException:
        continue

  def click(self, xpath, element=None, timeout=TIMEOUT):
    try:
      WebDriverWait(self.driver, timeout).until(EC.element_to_be_clickable((By.XPATH, xpath))).click() if element is None else element.click()
      return True
    except TimeoutException:
      return False

  def get_attribute(self, xpath, name, element=None, timeout=TIMEOUT):
    try:
      if element is None:
        return WebDriverWait(self.driver, timeout).until(EC.visibility_of_element_located((By.XPATH, xpath))).get_attribute(name)
      return element.get_attribute(name)
    except TimeoutException:
      return None

  def get_css_value(self, xpath, name, element=None, timeout=TIMEOUT):
    try:
      if element is None:
        return WebDriverWait(self.driver, timeout).until(EC.presence_of_element_located((By.XPATH, xpath))).value_of_css_property(name)
      return element.value_of_css_property(name)
    except TimeoutException:
      return None
