"""Module contains functionality that parser main page for Cisco vulnerabilities."""

import time
import lxml
import lxml.etree
import selenium.common.exceptions
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
from cve_connector.vendor_cve.implementation.parsers.general_and_format_parsers\
    .html_parser import HtmlParser
from cve_connector.vendor_cve.implementation.utilities.utility_functions \
    import string_to_date, get_current_date


class CiscoMainPageParser(HtmlParser):
    """
    Class providing functionality for parsing Cisco main page.
    """
    def __init__(self, url, logger, from_date=None, to_date=None):
        super().__init__(url, from_date, to_date)
        self.date_format = '%Y %b %d'  # 2018 Apr 25
        self.driver = None
        self.last_parsed_date = get_current_date()
        self.entries_per_page = 100
        self.load_content()
        self.first_element_at_page = ''
        self.logger = logger

    def load_content(self):
        """
        Loads content from URL.

        :return: None
        """
        content = self.get_content_from_ulr()
        content_without_br = lxml.etree.HTML(content.replace('<br>', ''))
        self.data = content_without_br

    def get_content_from_ulr(self):
        """
        Gets and returns content from URL.

        :return: content
        """
        if not self.url:
            raise ValueError('Url must not be empty.')
        options = Options()
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')

        driver = webdriver.Chrome(chrome_options=options)
        driver.get(self.url)
        wait = WebDriverWait(driver, 10)
        wait.until(ec.presence_of_element_located((
            By.XPATH,
            './/table[contains(@class, "advisoryAlertTable")]'
            '/tbody[2]//tr[{}]'.format(self.entries_per_page))))
        self.driver = driver
        content = driver.page_source
        return content

    def parse(self):
        """
        Provides parsing functionality.

        :return: None
        """
        try:
            load_next_page = True
            while load_next_page:
                load_next_page = self.parse_content()
                if load_next_page:
                    next_page_loaded = False
                    while not next_page_loaded:
                        next_page_loaded = self.load_next_page()
        except ValueError as val_err:
            self.logger.error('Error while parsing RH.')
            self.logger.error(val_err.args)
        finally:
            self.driver.close()

    def parse_content(self):
        """
        Helper function which parses downloaded content.

        :return: True if parsing was successful
        """
        rows = self.data.xpath('.//table[@class="advisoryAlertTable"]/tbody[2]/tr')
        if not rows or len(rows) < self.entries_per_page:
            raise ValueError('Format of parsed website has changed.')

        i = 0
        was_correct_date = False
        for row in rows:
            i += 1
            items = row.xpath('.//table/tbody//td')
            if 'Informational' in items[2].xpath('.//text()'):
                continue

            date_string = items[3].xpath('.//text()')
            url_list = items[0].xpath('.//span/a/@href')
            if not url_list:
                raise ValueError('Format of parsed website has changed (url parsing).')
            url = url_list[0] if url_list else ''
            if not date_string:
                raise ValueError('Format of parsed website has changed (date parsing).')

            date = string_to_date(date_string[0], self.date_format)
            if date < self.from_date:
                return False
            if self.from_date <= date <= self.to_date:
                was_correct_date = True
                self.entities.append(url)
            elif was_correct_date:
                return False
            if i is self.entries_per_page:
                return True

    def try_to_load_next_page(self):
        """
        Tries to load next page in a loop.

        :return: None
        """
        correct_loaded = False
        while not correct_loaded:
            correct_loaded = self.load_next_page()

    def load_next_page(self):
        """
        Loads next page.

        :return: True if succesful
        """
        driver = self.driver
        try:
            elm = driver.find_element_by_xpath(
                '//*[@id="tab-1"]/div[2]/table/tfoot/tr[2]/td/div[2]/button[2]')
            elm.click()
        except (ValueError, selenium.common.exceptions.ElementNotVisibleException):
            return False
        time.sleep(3)
        content = driver.page_source
        data = lxml.etree.HTML(content.replace('<br>', ''))
        self.driver = driver
        self.data = data
        return True
