from __future__ import absolute_import
from __future__ import print_function

from typing import Set, Tuple

import os
import re

GENERIC_KEYWORDS = [
    'active',
    'alert',
    'danger',
    'condensed',
    'disabled',
    'error',
    'expanded',
    'hide',
    'show',
    'notdisplayed',
    'popover',
    'success',
    'text-error',
    'warning',
    'zoom-in',  # TODO: clean these up, they are confusing
    'zoom-out',
    'first',
    'second',
]

def raise_error(fn, i, line):
    # type: (str, int, str) -> None
    error = '''
        In %s line %d there is the following line of code:

        %s

        Our tools want to be able to identify which modules
        add which HTML/CSS classes, and we need two things to
        happen:

            - The code must explicitly name the class.
            - Only one module can refer to that class (unless
              it is something generic like an alert class).

        If you get this error, you can usually address it by
        refactoring your code to be more explicit, or you can
        move the common code that sets the class to a library
        module.  If neither of those applies, you need to
        modify %s
        ''' % (fn, i, line, __file__)
    raise Exception(error)

def generic(html_class):
    # type: (str) -> bool
    for kw in GENERIC_KEYWORDS:
        if kw in html_class:
            return True

def display(fns):
    # type: (List[str]) -> None
    for tup in find(fns):
        # this format is for code generation purposes
        print(' ' * 8 + repr(tup) + ',')

def find(fns):
    # type: (List[str]) -> List[Tuple[str, str]]
    encountered = set() # type: Set[str]
    tups = [] # type: List[Tuple[str, str]]
    for fn in fns:
        lines = list(open(fn))
        fn = os.path.basename(fn)
        module_classes = set() # type: Set[str]
        for i, line in enumerate(lines):
            if 'addClass' in line:
                html_classes = [] # type: List[str]
                m = re.search('addClass\([\'"](.*?)[\'"]', line)
                if m:
                    html_classes = [m.group(1)]
                if not html_classes:
                    if 'bar-success' in line:
                        html_classes = ['bar-success', 'bar-danger']
                    elif 'color_class' in line:
                        continue
                    elif 'stream_dark' in line:
                        continue
                    elif fn == 'signup.js' and 'class_to_add' in line:
                        html_classes = ['error', 'success']
                    elif fn == 'ui.js' and 'status_classes' in line:
                        html_classes = ['alert']

                if not html_classes:
                    raise_error(fn, i, line)
                for html_class in html_classes:
                    if generic(html_class):
                        continue
                    if html_class in module_classes:
                        continue
                    if html_class in encountered:
                        raise_error(fn, i, line)
                    tups.append((fn, html_class))
                    module_classes.add(html_class)
                    encountered.add(html_class)
    return tups
