# 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 ...utils.threading import FixedThreadPoolExecutor
from ...utils.formatting import json_dumps, yaml_dumps
from ..loading import UriLocation
from ..reading import AlreadyReadException
from ..presentation import PresenterNotFoundError
from .consumer import Consumer


class Read(Consumer):
    """
    Reads the presentation, handling imports recursively.

    It works by consuming a data source via appropriate :class:`~aria.parser.loading.Loader`,
    :class:`~aria.parser.reading.Reader`, and :class:`~aria.parser.presentation.Presenter`
    instances.

    It supports agnostic raw data composition for presenters that have
    ``_get_import_locations`` and ``_merge_import``.

    To improve performance, loaders are called asynchronously on separate threads.

    Note that parsing may internally trigger more than one loading/reading/presentation
    cycle, for example if the agnostic raw data has dependencies that must also be parsed.
    """

    def consume(self):
        if self.context.presentation.location is None:
            self.context.validation.report('Presentation consumer: missing location')
            return

        presenter = None
        imported_presentations = None

        executor = FixedThreadPoolExecutor(size=self.context.presentation.threads,
                                           timeout=self.context.presentation.timeout)
        executor.print_exceptions = self.context.presentation.print_exceptions
        try:
            presenter = self._present(self.context.presentation.location, None, None, executor)
            executor.drain()

            # Handle exceptions
            for e in executor.exceptions:
                self._handle_exception(e)

            imported_presentations = executor.returns
        finally:
            executor.close()

        # Merge imports
        if (imported_presentations is not None) and hasattr(presenter, '_merge_import'):
            for imported_presentation in imported_presentations:
                okay = True
                if hasattr(presenter, '_validate_import'):
                    okay = presenter._validate_import(self.context, imported_presentation)
                if okay:
                    presenter._merge_import(imported_presentation)

        self.context.presentation.presenter = presenter

    def dump(self):
        if self.context.has_arg_switch('yaml'):
            indent = self.context.get_arg_value_int('indent', 2)
            raw = self.context.presentation.presenter._raw
            self.context.write(yaml_dumps(raw, indent=indent))
        elif self.context.has_arg_switch('json'):
            indent = self.context.get_arg_value_int('indent', 2)
            raw = self.context.presentation.presenter._raw
            self.context.write(json_dumps(raw, indent=indent))
        else:
            self.context.presentation.presenter._dump(self.context)

    def _handle_exception(self, e):
        if isinstance(e, AlreadyReadException):
            return
        super(Read, self)._handle_exception(e)

    def _present(self, location, origin_location, presenter_class, executor):
        # Link the context to this thread
        self.context.set_thread_local()

        raw = self._read(location, origin_location)

        if self.context.presentation.presenter_class is not None:
            # The presenter class we specified in the context overrides everything
            presenter_class = self.context.presentation.presenter_class
        else:
            try:
                presenter_class = self.context.presentation.presenter_source.get_presenter(raw)
            except PresenterNotFoundError:
                if presenter_class is None:
                    raise
            # We'll use the presenter class we were given (from the presenter that imported us)
            if presenter_class is None:
                raise PresenterNotFoundError('presenter not found')

        presentation = presenter_class(raw=raw)

        if presentation is not None and hasattr(presentation, '_link_locators'):
            presentation._link_locators()

        # Submit imports to executor
        if hasattr(presentation, '_get_import_locations'):
            import_locations = presentation._get_import_locations(self.context)
            if import_locations:
                for import_location in import_locations:
                    # The imports inherit the parent presenter class and use the current location as
                    # their origin location
                    import_location = UriLocation(import_location)
                    executor.submit(self._present, import_location, location, presenter_class,
                                    executor)

        return presentation

    def _read(self, location, origin_location):
        if self.context.reading.reader is not None:
            return self.context.reading.reader.read()
        loader = self.context.loading.loader_source.get_loader(self.context.loading, location,
                                                               origin_location)
        reader = self.context.reading.reader_source.get_reader(self.context.reading, location,
                                                               loader)
        return reader.read()
