# ----------------------------------------------------------------------
# Accela Selenium Keywords
#
# This file contains the Accela selenium keywords for robot framework
# ----------------------------------------------------------------------

"""
This library contains Selenium Robot Framework keywords for Web automation testing.

This library requires:
- ROBOTOUT environment variable to be set. This is where output files and screenshots will be saved to

For locating elements the following element locators are supported:

| =Locator Type= | =Description= | =Example= |
| id | Locates an element using its id attribute | id:username |
| xpath | Locates an element using xpath query on the html dom | xpath://input[@name='uid'] |
| link-text | Locates a hyper link element using its text | link-text:Click Here |
| partial-link-text | Same as link-text but locates the hyper link on partial text match | partial-link-text:username |
| name | Locates an element using the name attribute | name:zipcode |
| tag-name | Locates an element using its html tag name | tag-name:input |
| class-name | Locates an element using its class attribute | class-name:lastname |
| css-selector | Recommended, locates an element using a css query | css-selector:#nameid |

"""

from selenium.webdriver.support.wait import WebDriverWait
from robot.api import logger as robotlogger

from accelarobotkeywords.framework.selenium.conditions.alertconditions import *
from accelarobotkeywords.framework.selenium.conditions.checkboxconditions import *
from accelarobotkeywords.framework.selenium.conditions.pageconditions import *
from accelarobotkeywords.framework.selenium.locator import StringLocator
from accelarobotkeywords.framework.selenium.conditions.elementconditions import *
from accelarobotkeywords.framework.selenium.conditions.iframeconditions import *
from accelarobotkeywords.framework.selenium.conditions.windowconditions import *
from accelarobotkeywords.framework.selenium.conditions.listconditions import *
from accelarobotkeywords.framework.selenium.conditions.dropdownconditions import *
from accelarobotkeywords.framework.selenium.conditions.radioboxconditions import *
from accelarobotkeywords.framework.selenium.driverfactory import DriverFactory
from accelarobotkeywords.framework.selenium.screenshot import ScreenShot
from accelarobotkeywords.framework.selenium.conditions.tableconditions import *
from accelarobotkeywords.framework.utils.specialkeys import *


_driver = None
_default_window = None


# -----------------------------------------------------------
# Driver Keywords
# These are keywords controlling the browser itself
# -----------------------------------------------------------


def driver_open_browser():
    """Opens a web browser"""
    global _driver, _default_window
    _driver = DriverFactory.create_browser()
    _default_window = _driver.current_window_handle
    robotlogger.info('Browser opened with window handle {}'.format(_default_window))


def driver_close_browser():
    """Closes the web browser"""
    global _driver
    if _driver is not None:
        _driver.quit()
        robotlogger.info('Browser closed')
    else:
        robotlogger.info('Browser cannot be closed as it was not opened')


def driver_open_url(url):
    """Opens a specified URL"""
    global _driver
    _driver.get(url)
    robotlogger.info('URL opened {}'.format(url))


def driver_sleep_for_smaller_time():
    """Sleeps for the smaller timeout period"""
    seconds = SeleniumSettings.get_smaller_wait()
    time.sleep(seconds)


def driver_sleep_for_small_time():
    """Sleeps for the small timeout period"""
    seconds = SeleniumSettings.get_small_wait()
    time.sleep(seconds)


def driver_sleep_for_medium_time():
    """Sleeps for the medium timeout period"""
    seconds = SeleniumSettings.get_medium_wait()
    time.sleep(seconds)


def driver_sleep_for_long_time():
    """Sleeps for the long timeout period"""
    seconds = SeleniumSettings.get_long_wait()
    time.sleep(seconds)


def driver_save_screen_shot(filename):
    """Saves a screen shot out of the browser to the screenshots directory with the specified name"""
    ScreenShot.capture_screenshot(_driver, filename)
    
def driver_get_cookie(name):
    """Get a specified cookie"""
    global _driver
    val = _driver.get_cookie(name)
    robotlogger.info('%s cookie value is %s' % (name, val))
       

# ------------------------------------------------------------
# Element Keywords
# These are keywords applicable to many element types
# ------------------------------------------------------------


def element_left_click(locator_string):
    """Left clicks on an element"""
    locator = StringLocator(locator_string)
    robotlogger.info("Left clicking on element: %s" % locator.locator_value)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementLeftClick(locator))
    robotlogger.info("Element %s was left clicked" % locator_string)


def element_clear_text(locator_string):
    """Clears text from an element"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementClearText(locator))
    robotlogger.info("Text was cleared from element %s" % locator_string)


def element_enter_text(locator_string, element_text):
    """Enters text on an element, clears any existing text first"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterText(locator, element_text))
    robotlogger.info("Text: %s, was entered on element %s" % (element_text, locator_string))


def element_enter_text_and_check_value_attribute(locator_string, element_text):
    """Enters text on an element, clears any existing text first and checks value attribute"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterTextAndCheckValueAttribute(locator, element_text))
    robotlogger.info("Text: %s, was entered on element %s" % (element_text, locator_string))


def element_type_text_individually(locator_string, element_text):
    """Enters text on an element after clearing by typing each character individually"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementTypeTextIndividually(locator, element_text))
    robotlogger.info(
        "Text: %s, was entered on element %s with each character individually typed" % (element_text, locator_string))


def element_enter_text_via_javascript(locator_string, element_text):
    """Enters text on an element via javascript"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterTextViaJavascript(locator, element_text))
    robotlogger.info("Text: %s, was entered on element %s via javascript" % (element_text, locator_string))


def element_enter_text_to_all_matching(locator_string, element_text):
    """Enters text on all matching elements"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterTextToAllMatching(locator, element_text))
    robotlogger.info("Text: %s, was entered on multiple element %s" % (element_text, locator_string))


def element_clear_text_from_all_matching(locator_string):
    """Clears text on all matching elements"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementClearTextToAllMatching(locator))
    robotlogger.info("Text was cleared from multiple element %s" % locator_string)


def element_enter_text_with_no_clear(locator_string, element_text):
    """Enters text on an element but does not clear any existing text first"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterTextWithNoClear(locator, element_text))
    robotlogger.info(
        "Text: %s, was entered on element %s with no clear of exiting text" % (element_text, locator_string))


def element_enter_text_via_actions(locator_string, element_text):
    """Enters text on an element via actions, clears any existing text first"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementEnterTextViaActions(locator, element_text))
    robotlogger.info("Text: %s, was entered on element %s via actions" % (element_text, locator_string))


def element_doubleclick(locator_string):
    """Double clicks on an element"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementDoubleClick(locator))
    robotlogger.info("Double clicked on element: %s" % locator_string)


def element_send_any_key(locator_string, keycode):
    """Send any special key to an element"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementSendAnyKey(locator, SpecialKeys.get_special_key_value(keyname=keycode)))
    robotlogger.info("Sent special key to element: %s" % locator_string)


def element_send_esc_key_to_active_element():
    """Sends ESCAPE key to currently active element"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementSendEscapeKey())
    robotlogger.info("Sent Escape key to currently active element" )


def element_hover_and_left_click(locator_string):
    """Hovers over and element and left clicks on it"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementHoverAndLeftClick(locator))
    robotlogger.info("Hovered and left clicked on element: %s" % locator_string)


def element_get_text(locator_string):
    """Gets the text of an element - returns text in a string"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    text = wait.until(ElementGetText(locator))
    robotlogger.info("Element text is: %s" % text)
    return text


def element_get_text_from_all_matching_elements(locator_string):
    """Gets the text from all matching elements - returns the texts in a list object"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    matching_texts = wait.until(ElementGetTextFromAllMatchingElements(locator))
    robotlogger.info("Matching Element texts are: %s" % matching_texts)
    return matching_texts


def element_get_attribute_from_all_matching_elements(locator_string, attribute_name):
    """Gets the attribute from all matching elements - returns the attribute value in a list object"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    matching_attribute_values = wait.until(ElementGetAttributeFromAllMatchingElements(locator, attribute_name))
    robotlogger.info("Matching Element attribute values are: %s" % matching_attribute_values)
    return matching_attribute_values


def element_get_text_from_child_elements(locator_string, child_locator_string):
    """Gets the text of element(s) from a specific child of the parent - returns the text(s) in a list object"""
    locator = StringLocator(locator_string)
    child_locator = StringLocator(child_locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    child_texts = wait.until(ElementGetTextFromChildElements(locator, child_locator))
    robotlogger.info("This Child Element texts are: %s" % child_texts)
    return child_texts


def element_get_text_from_all_child_elements(locator_string):
    """Gets the text of element(s) from all the children of the parent - returns the text(s) in a list object"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    child_texts = wait.until(ElementGetTextFromAllChildElements(locator))
    robotlogger.info("All Child Element texts are: %s" % child_texts)
    return child_texts


def element_get_attribute(locator_string, attribute_name):
    """Gets the attribute of an element - returns the attribute value in a string or 'Empty' if no value"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    attribute_value = wait.until(ElementGetAttribute(locator, attribute_name))
    robotlogger.info("Element attribute's value is: %s" % attribute_value)
    return attribute_value


def element_get_css_value(locator_string, css_name):
    """Gets the css value of an element - returns the css value in a string or 'Empty' if no value"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    attribute_value = wait.until(ElementGetCssValue(locator, css_name))
    robotlogger.info("Element attribute's value is: %s" % attribute_value)
    return attribute_value


def element_make_visible(locator_string):
    """Makes an element visible in the browser"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementMakeVisible(locator))
    robotlogger.info("Element %s is now visible" % locator_string)


def element_make_hidden(locator_string):
    """Makes an element invisible or hidden in the browser"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementMakeHidden(locator))
    robotlogger.info("Element %s is now invisible or hidden" % locator_string)


def element_click_on_nth_element(locator_string, nth_position):
    """Clicks on Nth position link of the elements that are found on the locator string"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementClickNthElement(locator, nth_position))
    robotlogger.info("Clicked on position: %s of element:  %s" % (nth_position, locator_string))


def element_control_click(locator_string):
    """Control + Click on an element  """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementControlAndLeftClick(locator))
    robotlogger.info("Control + click done on element: %s" % locator_string)


def element_control_right_click(locator_string):
    """Control + Right Click on an element  """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementControlAndRightClick(locator))
    robotlogger.info("Control + Right click done on element: %s" % locator_string)


def element_control_and_press_key(key):
    """Control + press key on the element in focus  """
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementControlAndPressKey(key))
    robotlogger.info("Control + press %s done on element in focus" % key)


def element_alt_and_press_key(key):
    """Alt + press key on the element in focus  """
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementAltAndPressKey(key))
    robotlogger.info("Alt + press %s done on element in focus" % key)


def element_js_click(locator_string):
    """JS Click on an element, this is javascript click, sometimes the element is not clickable  by normal click
     and to overcome those cases we use js click """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementJsClick(locator))
    robotlogger.info("JS click done on element: %s" % locator_string)


def element_get_total_number_of_elements(locator_string):
    """Gets the total number of elements in the locator"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    number_of_elements = wait.until(ElementGetTotalNumberOfElements(locator))
    robotlogger.info("Total Number of Element is: %s on locator: %s" % (number_of_elements, locator_string))
    return number_of_elements


def element_set_focus(locator_string):
    """Sets Focus on the element passed in"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementSetFocus(locator))
    robotlogger.info("Element focus is set to : %s" % locator_string)


def scroll_to_element_via_javascript(locator_string):
    """Scrolls to an element via javascript"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ScrollToElementViaJavascript(locator))
    robotlogger.info("Scrolled to element %s via javascript" % locator_string)


def element_get_active_element_text():
    """Returns the text of currently active/focused element"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    element = wait.until(ElementGetActiveElement())
    robotlogger.info("Currently Active element is : %s" % element.text)
    return element.text.strip()


def element_set_attribute_value_by_js(locator_string, attribute, value):
    """Sets value of the attribute that is  passed in, attribute name and value both are passed in"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementSetAttributeValueByJS(locator, attribute, value))
    robotlogger.info("Element attribute: %s value is set to : %s by javascript" % (attribute, value))


def element_mouse_over(locator_string):
    """Moves mouse over to the element"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementMouseOver(locator))
    robotlogger.info("Element Mouse Moved to : %s" % locator_string)


def element_get_css_property_value(locator_string, css_property):
    """Returns the value of the css property that is passed in"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    css_property_value = wait.until(ElementGetCSSPropertyValue(locator, css_property))
    robotlogger.info("Value of css property: %s is: %s " % (css_property, css_property_value))
    return css_property_value


def element_drag_and_drop_to_element(locator_from, locator_to):
    """Drags and drop element to another element"""
    from_locator = StringLocator(locator_from)
    to_locator = StringLocator(locator_to)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementDragAndDrop(from_locator, to_locator))
    robotlogger.info("Dragged element %s to element : %s" % (locator_from, locator_to))


def element_drag_and_drop_to_x_y_position(locator_from, x_offset, y_offset):
    """Drags and drop element to x and y position """
    from_locator = StringLocator(locator_from)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementDragAndDropXYPosition(from_locator, x_offset, y_offset))
    robotlogger.info("Dragged element %s to X: %s and Y: %s" % (locator_from, x_offset, y_offset))

# ----------------------------------------------------------------
# Conditions Keywords
# These are keywords waiting for a specific state
# ----------------------------------------------------------------


def element_wait_to_be_displayed(locator_string):
    """Waits for the element to be displayed"""
    robotlogger.info('Waiting for element to be displayed: %s' % locator_string)
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementWaitForDisplayed(locator))
    robotlogger.info("Element %s was found and is visible" % locator_string)

def element_wait_to_be_displayed_extended(locator_string):
    """Waits for the element to be displayed with extra longer timeout"""
    robotlogger.info('Waiting for element to be displayed: %s' % locator_string)
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_extra_long_wait())
    wait.until(ElementWaitForDisplayed(locator))
    robotlogger.info("Element %s was found and is visible" % locator_string)


def element_wait_to_be_not_displayed(locator_string):
    """Waits for the element to be not displayed"""
    robotlogger.info('Waiting for element to be not displayed: %s' % locator_string)
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementWaitForNotDisplayed(locator))
    robotlogger.info("Element %s was not found or is not visible" % locator_string)


def element_wait_to_be_enabled(locator_string):
    """Waits for an element to be enabled"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementWaitForEnabled(locator))
    robotlogger.info("Element %s was found and is enabled" % locator_string)


def element_wait_to_be_not_enabled(locator_string):
    """Waits for an element to be not enabled"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementWaitForNotEnabled(locator))
    robotlogger.info("Element %s was found and is not enabled" % locator_string)


def element_should_be_enabled(locator_string):
    """Verifies that an element is enabled"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementShouldBeEnabled(locator))
    robotlogger.info("Element %s was found and is enabled" % locator_string)


def element_should_not_be_enabled(locator_string):
    """Verifies that an element is not enabled"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementShouldNotBeEnabled(locator))
    robotlogger.info("Element %s was found and is not enabled" % locator_string)


def element_should_be_displayed(locator_string):
    """Verifies that an element is displayed"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementShouldBeDisplayed(locator))
    robotlogger.info("Element %s was found and is displayed" % locator_string)


def element_should_not_be_displayed(locator_string):
    """Verifies that an element is not displayed"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementShouldNotBeDisplayed(locator))
    robotlogger.info("Element %s was found and is not displayed" % locator_string)


def element_should_be_empty(locator_string):
    """Verifies that an element is empty"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementShouldBeEmpty(locator))
    robotlogger.info("Element %s was found and is empty" % locator_string)


def list_wait_to_have_item_count(locator_string, count):
    """Waits for specified list to have specified item count"""
    locator = StringLocator(locator_string)
    item_count = int(count)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ListWaitForItemCount(locator, item_count))
    robotlogger.info("List was found to have %s items" % str(count))


# ------------------------------------------------------------------------
# Page Keywords
# These are keywords relating to pages
# ------------------------------------------------------------------------

def page_wait_for_ready_state():
    """Waits for the page dom to report a ready state"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(DocumentReadyState())
    robotlogger.info("Page is now in a ready state")


def page_refresh():
    """Refreshes the page dom"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(PageRefresh())
    robotlogger.info("Page is now Refreshed")


def page_navigate_back():
    """Navigates one step backward in the browser history"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(PageNavigateBack())
    robotlogger.info("Navigated one step backwards in the browser history")


def page_navigate_forward():
    """Navigates one step forward in the browser history"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(PageNavigateForward())
    robotlogger.info("Navigated one step forwards in the browser history")


def page_get_current_url():
    """Gets the URL of the current page"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    url = wait.until(PageGetCurrentUrl())
    robotlogger.info("Got the Url of the current page")
    return url

# ------------------------------------------------------------------------
# IFrame Keywords
# These are keywords relating to iframes
# ------------------------------------------------------------------------


def iframe_switch_to_default_content():
    """Switches the browser context back to the document root"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(IFrameSwitchDefaultContent())
    robotlogger.info("Switched to default content")


def iframe_switch_to_parent_frame():
    """Switches the browser context back to the parent frame"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(IFrameSwitchToParentFrame())
    robotlogger.info("Switched to parentFrame")


def iframe_switch_to_by_name(name):
    """
    Switches to the iframe specified by its name attribute
    """
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(IFrameSwitchToByName(name))
    robotlogger.info("Switched to iframe with name: %s" % name)


def iframe_switch_to_by_locator(locator_string):
    """Switches to the iframe specified by the locator"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(IFrameSwitchToByLocator(locator))
    robotlogger.info("Switched to iframe with locator: %s" % locator_string)


# -----------------------------------------------------------------------
# Window keywords
# These are keywords for window/tabs
# -----------------------------------------------------------------------

def window_switch_to_window_by_title(title_string):
    """Switches to the window with the matching title"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToWindowWithTitle(title_string))
    robotlogger.info("Switched to window with title: %s" % title_string)


def window_switch_to_first_found_window():
    """Switches to the first found non default window"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToFirstFoundWindow(_default_window))
    robotlogger.info("Non default window found and switched to")


def window_switch_to_main_window():
    """Switches to the base/default window"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToMainWindow(_default_window))
    robotlogger.info("default window found and switched to it")

def window_switch_to_new_window(window_type):
    """Switches to a new window or a new tab"""
    if window_type not in ['tab', 'window']:
        error_message = f"Invalid option: '{window_type}'. Please choose 'tab' or 'window'."
        robotlogger.error(error_message)
        raise ValueError(error_message) 
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToNewWindow(window_type))
    robotlogger.info(f"Successfully switched to a new {window_type}")

def window_maximize_window():
    """Maximizes the current window"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowMaximizeWindow())
    robotlogger.info("Maximized the window")


def window_switch_to_window_with_url(url_string):
    """Switches to window with specified url, this can be a partially matching url"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToWindowWithUrl(url_string))
    robotlogger.info("Switched to window based on following url %s" % url_string)


def window_switch_to_window_with_window_index(window_index):
    """Switches to window from an index, the first window is 0 index"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowSwitchToWindowWithHandleIndex(window_index))
    robotlogger.info("Switched to window based on following index %s" % window_index)


def window_window_title_should_match(window_title):
    """Verifies the current window title contains the specified title text"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowTitleShouldMatch(window_title))
    robotlogger.info("Window title matched with  %s" % window_title)


def window_window_title_should_be_equal(window_title):
    """Verifies the current window title has exactly matching title"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowTitleShouldBeEqual(window_title))
    robotlogger.info("Window title is equal to %s" % window_title)


def window_close_window_based_on_title(window_title):
    """Closes the window based on its title, title can be partially matched"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowCloseWindowBasedOnTitle(window_title))
    robotlogger.info("Window found and closed")


def window_close_window_based_on_title_equal(window_title):
    """Closes the window based on title, title has to be exact match"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowCloseWindowBasedOnTitleEqual(window_title))
    robotlogger.info("Window found and closed")


def window_close_window_based_on_url(window_url):
    """Closes window based on its url, url can be partially matched"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(WindowCloseWindowBasedOnUrl(window_url))
    robotlogger.info("Window found and closed")


def window_scroll_to(x_value, y_value):
    """Scroll to a specified x and y values """
    a_script = 'window.scroll(%d,%d);' % (x_value, y_value)
    _driver.execute_script(a_script)
    robotlogger.info("Window scroll to position %d %d" % (x_value, y_value))

    
def window_get_window_title():
        """Gets the Title of the current page"""
        wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
        title = wait.until(WindowGetWindowTitle())
        robotlogger.info("Got the Title of the current page")
        return title


def window_get_count_of_windows_opened():
    """Returns the number of currently opened windows"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    number_of_windows_opened = wait.until(WindowGetWindowHandles())
    robotlogger.info("Returning the count of windows opened")
    return int(number_of_windows_opened)

# -------------------------------------------------------------------
# DropDown Keywords
# These are keywords relating to drop down lists
# -------------------------------------------------------------------

def drop_down_select_item_by_text_value(locator_string, text_value):
    """Selects an item in a drop down list by its text value"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(DropDownSelectItemByTextValue(locator, text_value))
    robotlogger.info("Selected item %s in drop down element %s" % (text_value, locator_string))


def drop_down_select_item_by_value(locator_string, value_of_attribute_value):
    """Selects an item in a drop down list by its value attribute value eg. value="Individual" """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(DropDownSelectItemByValue(locator, value_of_attribute_value))
    robotlogger.info("Selected item %s in drop down element %s" % (value_of_attribute_value, locator_string))


def drop_down_select_item_by_index(locator_string, index_to_select):
    """Selects an item in a drop down list by its indexed position in the drop down list, first item is position 0"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(DropDownSelectItemByIndex(locator, index_to_select))
    robotlogger.info("Selected item %s in drop down element %s" % (index_to_select, locator_string))


def drop_down_get_currently_selected_option_text(locator_string):
    """Gets currently selected option in drop down list, Returns the selected option text"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    text = wait.until(DropDownGetCurrentlySelectedOptionText(locator))
    robotlogger.info("Selected item in drop down element %s" % locator_string)
    return text


def drop_down_get_currently_selected_option_value(locator_string):
    """Gets the value of currently selected option, gets from value attribute"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    value = wait.until(DropDownGetCurrentlySelectedOptionValue(locator))
    robotlogger.info("currently selected option value is returned from locator:  %s" % locator_string)
    return str(value)


def drop_down_get_currently_selected_option_index(locator_string):
    """Gets the index of the currently selected option, first items index position will be 0  """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    index = wait.until(DropDownGetCurrentlySelectedOptionIndex(locator))
    robotlogger.info("index value of currently selected option is returned:  %s" % locator_string)
    return index


def drop_down_get_number_of_options(locator_string):
    """Gets total number of options available in drop down list"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    number_of_options = wait.until(DropDownGetNumberOfOptions(locator))
    robotlogger.info("Returned total number of available options in drop down element %s" % locator_string)
    return int(number_of_options)


def drop_down_get_all_options(locator_string):
    """Gets all options available in drop down list(visible text),
    a list object is returned with all the available options"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    all_options = wait.until(DropDownGetAllOptions(locator))
    robotlogger.info("Returned all available options in drop down element %s" % locator_string)
    return all_options

# -----------------------------------------------------------------
# RadioBox Keywords
# Keywords relating to radio box controls
# -----------------------------------------------------------------


def radio_box_select(locator_string):
    """Selects the specified radio box"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(RadioBoxCheck(locator))
    robotlogger.info("Radio box was selected %s" % locator_string)


# -----------------------------------------------------------------
# Alert Keywords
# Keywords relating to Alerts
# -----------------------------------------------------------------


def alert_accept_if_present():
    """Accepts a javascript alert if present"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(AlertAcceptIfPresent())
    robotlogger.info("Alert was accepted")


def alert_should_have_text(alert_text):
    """Verifies the text on a javascript alert matches the specified text"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    text_from_alert = wait.until(AlertGetAlertText())
    robotlogger.info("Alert has text: %s" % text_from_alert)
    if alert_text == text_from_alert:
        robotlogger.info("Alert text is the same as expected text : %s" % text_from_alert)
    else:
        raise Exception("Alert text is not the same as expected")
    
def alert_get_text():
    """Get alert text"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    text_from_alert = wait.until(AlertGetAlertText())
    robotlogger.info("Alert has text: %s" % text_from_alert)
    return text_from_alert
    

def enter_text_to_alert(text):
    """Enters text to alert"""
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(AlertEnterTextAndAccept(text))
    robotlogger.info("Text: %s, was entered on alert" % text)


# -----------------------------------------------------------------
# Checkbox Keywords
# Keywords relating to Check box controls
# -----------------------------------------------------------------

def check_box_check(locator_string):
    """Selects the specified check box"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxCheck(locator))
    robotlogger.info("Check box was selected %s" % locator_string)


def check_box_uncheck(locator_string):
    """Un-selects the specified check box"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxUnCheck(locator))
    robotlogger.info("Check box was un-selected %s" % locator_string)


def check_box_should_be_checked(locator_string):
    """Verifies the specified checkbox is checked"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxShouldBeChecked(locator))
    robotlogger.info("Check box was was found to be selected %s" % locator_string)


def check_box_should_be_unchecked(locator_string):
    """Verifies the specified checkbox is unchecked"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxShouldBeUnChecked(locator))
    robotlogger.info("Check box was found to be un-selected %s" % locator_string)


# ----------------------------------------------------------------------------------
# Radio Button keywords
# ----------------------------------------------------------------------------------

def radio_button_select(locator_string):
    """Selects the specified radio button"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxCheck(locator))
    robotlogger.info("radio button was selected %s" % locator_string)


def radio_button_should_be_selected(locator_string):
    """Verifies the specified radio button is selected"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxShouldBeChecked(locator))
    robotlogger.info("radio button was found to be selected %s" % locator_string)


def radio_button_should_not_be_selected(locator_string):
    """Verifies the specified radio button is not selected"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(CheckBoxShouldBeUnChecked(locator))
    robotlogger.info("radio button was found to be Not selected %s" % locator_string)

# ----------------------------------------------------------------------------------
# Table keywords
# ----------------------------------------------------------------------------------


def table_get_column_number_from_name(locator_string, name):
    """Gets the column index position of a table from its name"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    table_info = wait.until(GetTableDetails(locator))
    index = table_info.get_column_index(name)
    robotlogger.info('Column name %s was found at index %s' % (name, str(index)))
    return index


def table_get_cell_text(locator_string, row_number, column_number):
    """Gets the text from the specified cell in the table"""
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    cell_text = wait.until(GetCellText(locator=locator, row_number=row_number, column_number=column_number))
    robotlogger.info('Cell text from position (%s, %s) = %s' % (row_number, column_number, cell_text))
    return cell_text


def table_get_row_number_by_value_and_column_index(locator_string, column_index, search_text, starting_row):
    """
    Searches the specified column index for the specified search text
    :param locator_string: Locator of the table element
    :param column_index: Index of the column to search
    :param search_text: Text to search for
    :param starting_row: Row number to start the search from
    :return: The matching row number
    """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    table_info = wait.until(GetTableDetails(locator))
    row_number = wait.until(SearchForCellValue(locator=locator, column_index=column_index, search_text=search_text,
                                               max_rows=table_info.get_row_count(),
                                               start_row=int(starting_row)))
    robotlogger.info("Search text found at row: %s" % row_number)
    return row_number


def table_get_row_number_by_value_and_column_name(locator_string, column_name, search_text, starting_row):
    """
    Searches the specified column name for the specified search text
    :param locator_string: Locator of the table element
    :param column_name: Name of the column to search in
    :param search_text: The search text to find
    :param starting_row: The starting row number
    :return: The matching row number
    """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    table_info = wait.until(GetTableDetails(locator))
    column_index = table_info.get_column_index(name=column_name)
    robotlogger.info("Column %s has index %s" % (column_name, column_index))
    row_number = wait.until(SearchForCellValue(locator=locator, column_index=column_index, search_text=search_text,
                                               max_rows=table_info.get_row_count(),
                                               start_row=int(starting_row)))
    robotlogger.info("Search text found at row: %s" % row_number)
    return row_number


def table_click_on_cell_by_value_and_column_index(locator_string, column_index, search_text, starting_row,
                                                  click_column_index):
    """
    Searches for the specified text in the specified column, and then click on the child element of that table cell
    :param locator_string: Locator of the table element
    :param column_index: Index position of the column to search on
    :param search_text: Text to search for in the column
    :param starting_row: Starting row number to search from
    :param click_column_index: Column index to click on
    :return: Nothing
    """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    table_info = wait.until(GetTableDetails(locator))
    wait.until(ClickOnCell(locator=locator, column_index=column_index, search_text=search_text,
                           start_row=int(starting_row), max_rows=table_info.get_row_count(),
                           click_column_index=click_column_index))
    robotlogger.info("Search text was found, and cell was clicked")


def table_click_on_cell_by_value_and_column_name(locator_string, column_name, search_text, starting_row,
                                                 click_column_name):
    """
    Searches for the specified text in the specified column, and then click on the child element of that table cell
    :param locator_string: Locator of the table element
    :param column_name: Name of the column to search on
    :param search_text: Text to search for in the column
    :param starting_row: Starting row number to search from
    :param click_column_name: Column name to click on
    :return: Nothing
    """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    table_info = wait.until(GetTableDetails(locator))
    column_index = table_info.get_column_index(column_name)
    click_column_index = table_info.get_column_index(click_column_name)
    wait.until(ClickOnCell(locator=locator, column_index=column_index, search_text=search_text,
                           start_row=int(starting_row), max_rows=table_info.get_row_count(),
                           click_column_index=click_column_index))
    robotlogger.info("Search text was found, and cell was clicked")


def element_choose_file(locator_string, file_path):
    """
    Inputs the ``file_path`` into the file input field ``locator``.
    This keyword is most often used to input files into upload forms.
    Example:
    | `Choose File` | my_upload_field | ${CURDIR}/trades.csv |
    """
    locator = StringLocator(locator_string)
    wait = WebDriverWait(_driver, SeleniumSettings.get_explicit_wait())
    wait.until(ElementChooseFile(locator, file_path))
    robotlogger.info("Text: %s, was entered on element %s" % (file_path, locator_string))
