# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .issue import Issue
from ...utils.threading import LockedList
from ...utils.collections import FrozenList
from ...utils.exceptions import print_exception
from ...utils.console import puts, Colored, indent
from ...utils.formatting import as_raw


class ValidationContext(object):
    """
    Validation context.

    :ivar allow_unknown_fields: when ``False`` (the default) will report an issue if an unknown
     field is used
    :vartype allow_unknown_fields: bool
    :ivar allow_primitive_coersion`: when ``False`` (the default) will not attempt to coerce
     primitive field types
    :vartype allow_primitive_coersion: bool
    :ivar max_level: maximum validation level to report (default is all)
    :vartype max_level: int
    """

    def __init__(self):
        self.allow_unknown_fields = False
        self.allow_primitive_coersion = False
        self.max_level = Issue.ALL

        self._issues = LockedList()

    def report(self, message=None, exception=None, location=None, line=None,
               column=None, locator=None, snippet=None, level=Issue.PLATFORM, issue=None):
        if issue is None:
            issue = Issue(message, exception, location, line, column, locator, snippet, level)

        # Avoid duplicate issues
        with self._issues:
            for i in self._issues:
                if str(i) == str(issue):
                    return

            self._issues.append(issue)

    @property
    def has_issues(self):
        return len(self._issues) > 0

    @property
    def issues(self):
        issues = [i for i in self._issues if i.level <= self.max_level]
        issues.sort(key=lambda i: (i.level, i.location, i.line, i.column, i.message))
        return FrozenList(issues)

    @property
    def issues_as_raw(self):
        return [as_raw(i) for i in self.issues]

    def dump_issues(self):
        issues = self.issues
        if issues:
            puts(Colored.blue('Validation issues:', bold=True))
            with indent(2):
                for issue in issues:
                    puts(Colored.blue(issue.heading_as_str))
                    details = issue.details_as_str
                    if details:
                        with indent(3):
                            puts(details)
                    if issue.exception is not None:
                        with indent(3):
                            print_exception(issue.exception)
            return True
        return False
