# -*- coding: utf-8 -*-
#
# This file is part of the Anitya project.
# Copyright (C) 2014-2016  Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"""
Exceptions used by Anitya.

Authors:
    Pierre-Yves Chibon <pingou@pingoured.fr>
"""
import arrow


class AnityaException(Exception):
    """ Generic class covering all the exceptions generated by anitya. """

    pass


class AnityaPluginException(AnityaException):
    """Generic exception class that can be used by the plugin to indicate
    an error.
    """

    pass


class ProjectExists(AnityaException):
    """
    Raised when a project already exists in the database.

    This is only raised when a project is part of an ecosystem, since projects
    outside of an ecosystem have no uniqueness constraints.
    """

    def __init__(self, requested_project):
        self.requested_project = requested_project

    def to_dict(self):
        return {"requested_project": self.requested_project.__json__()}

    def __str__(self):
        return "Unable to create project since it already exists."


class AnityaInvalidMappingException(AnityaException):
    """ Specific exception class for invalid mapping. """

    def __init__(
        self,
        pkgname,
        distro,
        found_pkgname,
        found_distro,
        project_id,
        project_name,
        link=None,
    ):
        self.pkgname = pkgname
        self.distro = distro
        self.found_pkgname = found_pkgname
        self.found_distro = found_distro
        self.project_id = project_id
        self.project_name = project_name
        self.link = link

    @property
    def message(self):
        return (
            "Could not edit the mapping of {pkgname} on "
            "{distro}, there is already a package {found_pkgname} on "
            '{found_distro} as part of the project <a href="{link}">'
            "{project_name}</a>.".format(
                pkgname=self.pkgname,
                distro=self.distro,
                found_pkgname=self.found_pkgname,
                found_distro=self.found_distro,
                project_name=self.project_name,
                link=self.link,
            )
        )


class InvalidVersion(AnityaException):
    """
    Raised when the version string is not valid for the given version scheme.

    Args:
        version (str): The version string that failed to parse.
        exception (Exception): The underlying exception that triggered this one.
    """

    def __init__(self, version, exception=None):
        self.version = version
        self.exception = exception

    def __str__(self):
        if self.exception:
            return 'Invalid version "{v}": {e}'.format(
                v=self.version, e=str(self.exception)
            )
        else:
            return 'Invalid version "{v}"'.format(v=self.version)


class RateLimitException(AnityaException):
    """
    Raised when the rate limit for requests is reached.

    Attributes:
        reset_time (`arrow.Arrow`): Time when limit will be reset.
    """

    def __init__(self, reset_time):
        """
        Constructor.

        Arguments:
            reset_time (str): Time when limit will be reset (UTC time encoded in ISO-8601).
        """
        self.reset_time = arrow.get(reset_time)

    def __str__(self):
        return 'Rate limit was reached. Will be reset in "{0}".'.format(
            str(self.reset_time)
        )
