#!/usr/bin/env python
# Copyright 2017 F5 Networks Inc.
#
# Licensed 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.
#

"""
This is an exceptions module holding exception classes that are of use to the
rest of the pkg building architecture.
"""

import errno

from inspect import currentframe as cf
from inspect import getframeinfo as gfi
from inspect import getouterframes as gof


class BuildError(Exception):
    """Creates a BuildError exception-type class

An excpetion class that will drop concise error messages into the terminal
rather than fill up the terminal with stacktraces.  Full stack traces can then
be generated by the person troubleshooting the issue.
    """
    default_msg = "An unknown error has occurred"
    default_errnum = errno.ESPIPE

    def __init__(self, *args, **kargs):
        self._set_errnum(kargs)
        self._set_frame(kargs)
        self._set_msg(args, kargs)
        super(BuildError, self).__init__(self.msg)

    def _set_errnum(self, kargs):
        if 'errnum' in kargs:
            self.errnum = kargs['errnum']
        elif 'errno' in kargs:
            self.errnum = kargs['errno']
        else:
            self.errnum = self.default_errnum

    def _set_frame(self, kargs):
        if 'frame' in kargs:
            self.frame = kargs['frame']
        else:
            # gof gets a stack of [inner->outer] tuples. tuple[0] is frame
            self.frame = gfi(gof(cf())[2][0])

    def _set_msg(self, args, kargs):
        msg = ''
        frame = self.frame
        if args:
            msg = ': %s' % (', '.join(map(str, args)))
        elif 'message' in kargs:
            msg = kargs['message'] + msg
        elif 'msg' in kargs:
            msg = kargs['msg'] + msg
        else:
            msg = self.default_msg + msg
        self.msg = "(%s) %s [%s:%s]" % (str(self.errnum), msg, frame.filename,
                                        str(frame.lineno))

    def print_msg(self, *args, **kargs):
        """print_msg

A method used often in-code as a means of a catch method.  This method can
accept any number of arguments or key-based arguments; however, it will not
interpret any of them by design.

The function of the method is to print out the exception object's message
attribute.
        """
        print(self.message)


class DebianError(BuildError):
    """DebianError

Raised when there is an issue producing the .deb package for Debian builds.
    """
    default_msg = "An error occurred while building the .deb pkg"

    def __init__(self, *args, **kargs):
        # exception-specific logic here...
        super(DebianError, self).__init__(*args, **kargs)


class RedhatError(BuildError):
    """RedhatError

Raised when there is an issue producing the .rpm package for Redhat builds.
    """
    default_msg = "An error occurred while building the .rpm pkg"

    def __init__(self, *args, **kargs):
        # excpetion-specific logic here...
        super(RedhatError, self).__init__(*args, **kargs)


class TestError(BuildError):
    """TestError

An Error occurred during testing...
    """
    default_msg = "An error occurred during testing phases!"

    def __init__(self, *args, **kargs):
        # exception-specific logic here...
        super(TestError, self).__init__(*args, **kargs)


# vim: set fileencoding=utf-8
