# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import unicode_literals

import os
import re

RE_COMMENT = re.compile(r'\s+#')
RE_HTTP = re.compile(r'HTTP\((\.\.(\/\.\.)*)\)')
RE_PROTOCOL = re.compile(r'^\w+:')
FAILURE_TYPES = (
    'fails',
    'fails-if',
    'needs-focus',
    'random',
    'random-if',
    'silentfail',
    'silentfail-if',
    'skip',
    'skip-if',
    'slow',
    'slow-if',
    'fuzzy',
    'fuzzy-if',
    'require-or',
    'asserts',
    'asserts-if',
)
PREF_ITEMS = (
    'pref',
    'test-pref',
    'ref-pref',
)


class ReftestManifest(object):
    """Represents a parsed reftest manifest.

    We currently only capture file information because that is the only thing
    tools require.
    """
    def __init__(self, finder=None):
        self.path = None
        self.dirs = set()
        self.files = set()
        self.manifests = set()
        self.tests = set()
        self.finder = finder

    def load(self, path):
        """Parse a reftest manifest file."""
        normalized_path = os.path.normpath(os.path.abspath(path))
        self.manifests.add(normalized_path)
        if not self.path:
            self.path = normalized_path

        mdir = os.path.dirname(normalized_path)
        self.dirs.add(mdir)

        if self.finder:
            lines = self.finder.get(path).read().splitlines()
        else:
            with open(path, 'r') as fh:
                lines = fh.read().splitlines()

        urlprefix = ''
        for line in lines:
            line = line.decode('utf-8')

            # Entire line is a comment.
            if line.startswith('#'):
                continue

            # Comments can begin mid line. Strip them.
            m = RE_COMMENT.search(line)
            if m:
                line = line[:m.start()]
            line = line.strip()
            if not line:
                continue

            items = line.split()
            tests = []

            for i in range(len(items)):
                item = items[i]

                if item.startswith(FAILURE_TYPES):
                    continue
                if item.startswith(PREF_ITEMS):
                    continue
                if item == 'HTTP':
                    continue

                m = RE_HTTP.match(item)
                if m:
                    # Need to package the referenced directory.
                    self.dirs.add(os.path.normpath(os.path.join(
                        mdir, m.group(1))))
                    continue

                if item == 'url-prefix':
                    urlprefix = items[i+1]
                    break

                if item == 'default-preferences':
                    break

                if item == 'include':
                    self.load(os.path.join(mdir, items[i+1]))
                    break

                if item == 'load' or item == 'script':
                    tests.append(items[i+1])
                    break

                if item == '==' or item == '!=' or item == 'print':
                    tests.extend(items[i+1:i+3])
                    break

            for f in tests:
                # We can't package about: or data: URIs.
                # Discarding data isn't correct for a parser. But retaining
                # all data isn't currently a requirement.
                if RE_PROTOCOL.match(f):
                    continue

                test = os.path.normpath(os.path.join(mdir, urlprefix + f))
                self.files.add(test)
                self.dirs.add(os.path.dirname(test))
                self.tests.add((test, normalized_path))
