import os
import re

from ..check import Check
from ..frontmatter import parse

class CheckIncludes(Check):
    '''Ensure tests make use of the harness files that they require via the
    `includes` directive.'''
    ID = 'INCLUDES'
    _cache = dict()

    @staticmethod
    def _remove_frontmatter(source):
        return re.sub(
            r'/\*---.*---\*/', '', source, flags=re.DOTALL
        )

    @staticmethod
    def _load(include_name):
        if include_name not in CheckIncludes._cache:
            with open(os.path.join('harness', include_name), 'r') as f:
                source = f.read()

            CheckIncludes._cache[include_name] = {
                'name': include_name,
                'source': CheckIncludes._remove_frontmatter(source),
                'defines': parse(source)['defines']
            }

        return CheckIncludes._cache.get(include_name)

    @staticmethod
    def _has_reference(source, names):
        for name in names:
            if name in source:
                return True
        return False

    def run(self, name, meta, source):
        if not meta or 'includes' not in meta:
            return

        harness_files = [self._load(name) for name in meta['includes']]

        if len(harness_files) == 0:
            return 'If present, the `includes` tag must have at least one member'

        without_frontmatter = self._remove_frontmatter(source)

        for harness_file in harness_files:
            if self._has_reference(without_frontmatter, harness_file['defines']):
                continue

            # If the test file does not reference a value defined by a given
            # include file, inspect each of the other include files for such a
            # reference.
            for other_harness_file in harness_files:
                if other_harness_file == harness_file:
                    continue

                if self._has_reference(other_harness_file['source'], harness_file['defines']):
                    break
            else:
                return 'Unused include: "%s"' % harness_file['name']
