"""Module contains functionality for parsing HTML page of a particular vulnerability."""

import re
import urllib.request

from cve_connector.vendor_cve.implementation.parsers.general_and_format_parsers.html_parser \
    import HtmlParser
from cve_connector.vendor_cve.implementation.vendors_storage_structures.apple import Apple

from cve_connector.vendor_cve.implementation.utilities.utility_functions \
    import concat_strings, normalize_string, get_cves_from_text, string_to_date


def get_string_without_prefix(string, prefix):
    """
    Deletes prefix from the string.

    :param string: string to be modified
    :param prefix: prefix to be deleted
    :return:
    """
    return string.replace(prefix, '')


class AppleVulnerabilityParser(HtmlParser):
    """
    Contains functionality for parsing HTML of specific CVE.
    """
    def __init__(self, url):
        super().__init__(url)
        self.date_format = '%B %d, %Y'  # March 29, 2018
        self.load_content()

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

        :return: content
        """
        response = urllib.request.urlopen(self.url)
        if response.getcode() != 200:
            raise ConnectionError('Unable to load ', self.url)
        content = response.read()
        response.close()
        return content

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

        :return: True if parsing was successful
        """
        content_list = self.data.xpath('.//div[@id="sections"]/div[3]')
        if not content_list:
            return False
        parsed_released_date = content_list[0].xpath('.//p/span[@class="note"]//text()')
        released_date = None
        if parsed_released_date:
            date_to_convert = re.match(r'Released (\w+ \d+, \d+)', parsed_released_date[0])
            if date_to_convert:
                released_date = string_to_date(date_to_convert.group(1), self.date_format)

        p_list = content_list[0].xpath('.//p')
        if not p_list:
            raise ValueError('Different format of Apple advisory - {}.'.format(self.url))
        self.parse_p_list(p_list, released_date)
        return True

    def parse_p_list(self, p_list, published):
        """
        Parses list of rows from HTML page.

        :param p_list: list of CVEs
        :param published: published date
        :return: None
        """
        cves = []
        description_all = ''
        description = ''
        impact = ''
        available_for = ''
        for paragraph in p_list:
            if paragraph.xpath('.//strong') and cves:
                self.add_new_entities(cves=cves, description=description, impact=impact,
                                      available_for=available_for, release_date=published,
                                      description_all=description_all)
                cves = []
                description = ''
                impact = ''
                available_for = ''
                description_all = ''
                continue
            text = concat_strings(paragraph.xpath('./text()'), ' ')
            if text == '':
                continue
            if text.startswith('Available for'):
                description_all = description_all + ' ' + normalize_string(text) + '.'
                available_for_re = re.search(r'Available for:(.+)', text)
                if available_for_re:
                    available_for = normalize_string(available_for_re.group(1))
            elif text.startswith('Impact'):
                description_all = description_all + ' ' + normalize_string(text) + '.'
                impact_re = re.search(r'Impact:(.+)', text)
                if impact_re:
                    impact = normalize_string(impact_re.group(1))
            elif text.startswith('Description'):
                description_all = description_all + ' ' + normalize_string(text)
                description_re = re.search(r'Description:(.+)', text)
                if description_re:
                    description = normalize_string(description_re.group(1))
            elif text.startswith('CVE'):
                cves.extend(get_cves_from_text(text))

        self.add_new_entities(cves, description, impact, available_for, published, description_all)

    def add_new_entities(self, cves, description, impact, available_for, release_date,
                         description_all):
        """
        Adds new entity to the list of entities as property.

        :param cves: list of CVEs
        :param description: description of CVE
        :param impact: impact of CVE
        :param available_for: string for which is available
        :param release_date: release date
        :param description_all: common description of all CVEs
        :return: None
        """
        for cve in cves:
            new_entity = Apple(cve_id=cve, description=description, available_for=available_for,
                               impact=impact, published=release_date, descr_all=description_all)
            if new_entity.is_valid_entity():
                self.entities.append(new_entity)
