# Copyright (C) The Arvados Authors. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

# errors.py - Arvados-specific exceptions.

import json

from apiclient import errors as apiclient_errors
from collections import OrderedDict

class ApiError(apiclient_errors.HttpError):
    def _get_reason(self):
        try:
            return '; '.join(json.loads(self.content.decode('utf-8'))['errors'])
        except (KeyError, TypeError, ValueError):
            return super(ApiError, self)._get_reason()


class KeepRequestError(Exception):
    """Base class for errors accessing Keep services."""
    def __init__(self, message='', request_errors=(), label=""):
        """KeepRequestError(message='', request_errors=(), label="")

        :message:
          A human-readable message describing what Keep operation
          failed.

        :request_errors:
          An iterable that yields 2-tuples of keys (where the key refers to
          some operation that was attempted) to the error encountered when
          talking to it--either an exception, or an HTTP response object.
          These will be packed into an OrderedDict, available through the
          request_errors() method.

        :label:
          A label indicating the type of value in the 'key' position of request_errors.

        """
        self.label = label
        self._request_errors = OrderedDict(request_errors)
        if self._request_errors:
            exc_reports = [self._format_error(*err_pair)
                           for err_pair in self._request_errors.items()]
            base_msg = "{}: {}".format(message, "; ".join(exc_reports))
        else:
            base_msg = message
        super(KeepRequestError, self).__init__(base_msg)
        self.message = message

    def _format_error(self, key, error):
        if isinstance(error, HttpError):
            err_fmt = "{} {} responded with {e.status_code} {e.reason}"
        else:
            err_fmt = "{} {} raised {e.__class__.__name__} ({e})"
        return err_fmt.format(self.label, key, e=error)

    def request_errors(self):
        """request_errors() -> OrderedDict

        The keys of the dictionary are described by `self.label`
        The corresponding value is the exception raised when sending the
        request to it."""
        return self._request_errors


class HttpError(Exception):
    def __init__(self, status_code, reason):
        self.status_code = status_code
        self.reason = reason


class ArgumentError(Exception):
    pass
class SyntaxError(Exception):
    pass
class AssertionError(Exception):
    pass
class CommandFailedError(Exception):
    pass
class KeepReadError(KeepRequestError):
    pass
class KeepWriteError(KeepRequestError):
    pass
class NotFoundError(KeepReadError):
    pass
class NotImplementedError(Exception):
    pass
class NoKeepServersError(Exception):
    pass
class StaleWriterStateError(Exception):
    pass
class FeatureNotEnabledError(Exception):
    pass
