# Copyright (C) 2018 Igalia S.L.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import json
import os


def check_repeated_keys(args):
    seen = {}
    for key, val in args:
        if key in seen:
            raise ValueError("Key %s appears more than once" % key)
        else:
            seen[key] = val

    return seen


class TestExpectations(object):

    def __init__(self, port_name, expectations_file, build_type='Release'):
        self._port_name = port_name
        self._build_type = build_type
        if os.path.isfile(expectations_file):
            with open(expectations_file, 'r') as fd:
                self._expectations = self._load_expectation_string(fd.read())
        else:
            self._expectations = {}

    def _load_expectation_string(self, expectations):
        return json.loads(expectations, object_pairs_hook=check_repeated_keys)

    def _port_name_for_expected(self, expected):
        if self._port_name in expected:
            return self._port_name

        name_with_build = self._port_name + '@' + self._build_type
        if name_with_build in expected:
            return name_with_build

        if 'all' in expected:
            return 'all'

        name_with_build = 'all@' + self._build_type
        if name_with_build in expected:
            return name_with_build

        return None

    def _expected_value(self, expected, value, default):
        port_name = self._port_name_for_expected(expected)
        if port_name is None:
            return default

        port_expected = expected[port_name]
        if value in port_expected:
            return port_expected[value]

        return default

    def skipped_tests(self):
        skipped = []
        for test in self._expectations:
            if 'expected' not in self._expectations[test]:
                continue

            expected = self._expectations[test]['expected']
            if 'SKIP' in self._expected_value(expected, 'status', []):
                skipped.append(test)
        return skipped

    def skipped_subtests(self, test):
        skipped = []
        if test not in self._expectations:
            return skipped

        test_expectation = self._expectations[test]
        if 'subtests' not in test_expectation:
            return skipped

        subtests = test_expectation['subtests']
        for subtest in subtests:
            if 'SKIP' in self._expected_value(subtests[subtest]['expected'], 'status', []):
                skipped.append(subtest)
        return skipped

    def _expectation_value(self, test, subtest, value, default):
        retval = default
        if test not in self._expectations:
            return retval

        test_expectation = self._expectations[test]
        if 'expected' in test_expectation:
            retval = self._expected_value(test_expectation['expected'], value, retval)

        if subtest is None or 'subtests' not in test_expectation:
            return retval

        subtests = test_expectation['subtests']
        if subtest not in subtests:
            return retval

        return self._expected_value(subtests[subtest]['expected'], value, retval)

    def is_slow(self, test, subtest=None):
        return self._expectation_value(test, subtest, 'slow', False)

    def get_expectation(self, test, subtest=None):
        return self._expectation_value(test, subtest, 'status', ['PASS'])
