#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.


from selenium.webdriver.common import by

from openstack_dashboard.test.integration_tests.regions import baseregion
from openstack_dashboard.test.integration_tests.regions import menus


class RowRegion(baseregion.BaseRegion):
    """Classic table row."""

    _cell_locator = (by.By.CSS_SELECTOR, 'td.normal_column')

    @property
    def cells(self):
        return self._get_elements(*self._cell_locator)


class BaseActionRowRegion(RowRegion):
    """Base class for creating ActionRow class derivative."""

    _row_checkbox_locator = (by.By.CSS_SELECTOR, 'td > input')

    def mark(self):
        chck_box = self._get_element(*self._row_checkbox_locator)
        chck_box.click()


class BtnActionRowRegion(BaseActionRowRegion):
    """Row with buttons in action column."""

    _action_locator = (by.By.CSS_SELECTOR, 'td.actions_column > button')

    def __init__(self, driver, conf, src_elem, action_name):
        super(BtnActionRowRegion, self).__init__(driver, conf, src_elem)
        self.action_name = action_name
        self._action_id_pattern = ("%s__action_%%s" %
                                   src_elem.get_attribute('id'))
        self._init_action()

    def _init_action(self):
        self._init_dynamic_property(self.action_name, self._get_action,
                                    self._action_id_pattern)

    def _get_action(self):
        return self._get_element(*self._action_locator)

    @property
    def action(self):
        return self._get_action()


class ComplexActionRowRegion(BaseActionRowRegion):
    """Row with button and select box in action column."""

    _primary_action_locator = (by.By.CSS_SELECTOR,
                               'td.actions_column > div.btn-group > *.btn')
    _secondary_actions_dropdown_locator = (by.By.CSS_SELECTOR,
                                           'div.btn-group')

    PRIMARY_ACTION = "primary_action"
    SECONDARY_ACTIONS = "secondary_actions"

    ACTIONS_ERROR_MSG = ("Actions must be supplied in dictionary:"
                         " {%s: 'action_name', '%s': ('action_name',...)}"
                         % (PRIMARY_ACTION, SECONDARY_ACTIONS))

    def __init__(self, driver, conf, src_elem, action_names):
        super(ComplexActionRowRegion, self).__init__(driver, conf, src_elem)
        try:
            self.primary_action_name = action_names[self.PRIMARY_ACTION]
            self.secondary_action_names = action_names[self.SECONDARY_ACTIONS]
            self._action_id_pattern = ("%s__action_%%s" %
                                       src_elem.get_attribute('id'))
            self._init_actions()
        except (TypeError, KeyError):
            raise AttributeError(self.ACTIONS_ERROR_MSG)

    def _init_actions(self):
        self._init_dynamic_property(self.primary_action_name,
                                    self._get_primary_action,
                                    self._action_id_pattern)
        self._init_dynamic_properties(self.secondary_action_names,
                                      self._get_secondary_actions,
                                      self._action_id_pattern)

    def _get_primary_action(self):
        return self._get_element(*self._primary_action_locator)

    def _get_secondary_actions(self):
        src_elem = self._get_element(*self._secondary_actions_dropdown_locator)
        dropdown = menus.DropDownMenuRegion(self.driver, self.conf, src_elem)
        return dropdown.menu_items

    @property
    def primary_action(self):
        return self._get_primary_action()

    @property
    def secondary_actions(self):
        return self._get_secondary_actions()


class BasicTableRegion(baseregion.BaseRegion):
    """Basic class representing table object."""

    _heading_locator = (by.By.CSS_SELECTOR, 'h3.table_title')
    _columns_names_locator = (by.By.CSS_SELECTOR, 'thead > tr > th')
    _footer_locator = (by.By.CSS_SELECTOR, 'tfoot > tr > td > span')
    _rows_locator = (by.By.CSS_SELECTOR, 'tbody > tr')
    _empty_table_locator = (by.By.CSS_SELECTOR, 'tbody > tr.empty')
    _search_field_locator = (by.By.CSS_SELECTOR,
                             'div.table_search.client > input')
    _search_button_locator = (by.By.CSS_SELECTOR,
                              'div.table_search.client > button')

    @property
    def heading(self):
        return self._get_element(*self._heading_locator)

    @property
    def rows(self):
        if self._is_element_present(*self._empty_table_locator):
            return []
        else:
            return self._get_rows()

    @property
    def column_names(self):
        return self._get_elements(*self._columns_names_locator)

    @property
    def footer(self):
        return self._get_element(*self._footer_locator)

    def filter(self, value):
        self._set_search_field(value)
        self._click_search_btn()

    def get_row(self, column_index, text, exact_match=True):
        """Get row that contains specified text in specified column.

        In case exact_match is set to True, text contained in row must equal
        searched text, otherwise occurrence of searched text in the column
        text will result in row match.
        """
        def get_text(element):
            text = element.get_attribute('data-selenium')
            return text or element.text

        for row in self.rows:
            if exact_match and text == get_text(row.cells[column_index]):
                return row
            if not exact_match and text in get_text(row.cells[column_index]):
                return row
        return None

    def _set_search_field(self, value):
        srch_field = self._get_element(*self._search_field_locator)
        srch_field.send_keys(value)

    def _click_search_btn(self):
        btn = self._get_element(*self._search_button_locator)
        btn.click()

    def _get_rows(self):
        rows = []
        for elem in self._get_elements(*self._rows_locator):
            rows.append(RowRegion(self.driver, self.conf, elem))


class ActionsTableRegion(BasicTableRegion):
    """Base class for creating derivative of BasicTableRegion that
    has some actions.
    """

    _actions_locator = (by.By.CSS_SELECTOR, 'div.table_actions > button,'
                                            ' div.table_actions > a')

    # private methods
    def __init__(self, driver, conf, src_elm, table_name, action_names):
        super(ActionsTableRegion, self).__init__(driver, conf, src_elm)
        self._action_id_pattern = "%s__action_%%s" % table_name
        self.action_names = action_names
        self._init_actions()

    # protected methods
    def _init_actions(self):
        """Create new methods that corresponds to picking table's
        action buttons.
        """
        self._init_dynamic_properties(self.action_names, self._get_actions,
                                      self._action_id_pattern)

    def _get_actions(self):
        return self._get_elements(*self._actions_locator)

    # properties
    @property
    def actions(self):
        return self._get_actions()


class SimpleActionsTableRegion(ActionsTableRegion):
    """Table which rows has buttons in action column."""

    def __init__(self, driver, conf, src_elm, table_name, action_names,
                 row_action_name):
        super(SimpleActionsTableRegion, self).__init__(
            driver, conf, src_elm, table_name, action_names)
        self.row_action_name = row_action_name

    def _get_rows(self):
        rows = []
        for elem in self._get_elements(*self._rows_locator):
            rows.append(BtnActionRowRegion(self.driver, self.conf, elem,
                                           self.row_action_name))
        return rows


class ComplexActionTableRegion(ActionsTableRegion):
    """Table which has button and selectbox in the action column."""

    def __init__(self, driver, conf, src_elm, table_name,
                 action_names, row_action_names):
        super(ComplexActionTableRegion, self).__init__(
            driver, conf, src_elm, table_name, action_names)
        self.row_action_names = row_action_names

    def _get_rows(self):
        rows = []
        for elem in self._get_elements(*self._rows_locator):
            rows.append(ComplexActionRowRegion(self.driver, self.conf, elem,
                                               self.row_action_names))
        return rows
