
from os.path import isfile, isdir, join, abspath, splitext, basename, exists, dirname

from cloakx import Extension
from cloakx.CloakBase import CloakBase
from cloakx.CloakHTML import CloakHTML
import cssutils
import re
from bs4 import BeautifulSoup
from logging import CRITICAL as CRITICAL_LOG_LEVEL
from cloakx.utils import multi_open

class CloakCSS(CloakBase):
    @staticmethod
    def fn_filter(fn):
        return fn.endswith('.css') and isfile(fn)

    def __init__(self, extension):
        super().__init__()
        self.ext = extension  # type: Extension

        self.variable_regex = re.compile(self.ident_pattern, re.IGNORECASE)
        cssutils.log.setLevel(CRITICAL_LOG_LEVEL)


    def cloak(self, token_map):
        e = self.ext # type: Extension
        #print(token_map)
        css_fns = e.get_filtered_filenames(CloakCSS.fn_filter)
        change_made = False

        for fn in css_fns:
            self.fn = fn
            parser = cssutils.parseFile(fn)
            change_made = self.replace_in_rules(parser.cssRules, token_map, fn, 'external') or change_made

            # todo: replace with write out to file
            # write new css out to file
            # with open('style_new.css', 'wb') as f:
            #     f.write(parser.cssText)
            pass

        html_fns = e.get_filtered_filenames(CloakHTML.fn_filter)
        #print(html_fns)

        for fn in html_fns:
            self.fn = fn
            with multi_open(fn) as fp:
                soup = BeautifulSoup(fp, 'html.parser')

            found_style = False
            for tag in soup.find_all('style'):
                temp = tag.string
                style_contents = tag.renderContents().decode('utf-8')
                parser = cssutils.parseString(style_contents, validate=False)
                #print(parser.cssRules)
                change_made = self.replace_in_rules(parser.cssRules, token_map, fn, 'inline') or change_made
                tag.string = parser.cssText.decode("utf-8")
                #self.change_tracker[self.fn].append({'type': 'html-inline', 'orig': temp, 'new': tag.string})

                # could add a validation checker to see if same errors occur.

                found_style = True

            if found_style:
                pass
                # todo: write soup out to file before moving on
        if change_made:
            print(self.get_change_results())

    def replace_in_rules(self, cssRules, token_map, fn, filetype):
        """
        This parses all the cssRules and replaces the variables with their counterpart located in the token_map
        :param cssRules: 
        :type cssRules: 
        :param token_map: 
        :type token_map: 
        :return: 
        :rtype: 
        """
        change_made = False
        for rule in cssRules:
            if hasattr(rule, 'selectorText'):
                temp = rule.selectorText
                rule.selectorText = self.token_replace_by_map(rule.selectorText, token_map)
                if temp != rule.selectorText:
                    ext = basename(filetype).split(".")[-1]
                    self.change_tracker[fn].append({'type':ext, 'orig': temp, 'new': rule.selectorText})
                change_made = True

            if hasattr(rule, 'cssRules'):
                change_made = self.replace_in_rules(rule.cssRules, token_map, fn, filetype)

        return change_made
