# -*- coding: utf-8 -*-
'''
This module is a central location for all hubble exceptions
'''

import copy
import logging
import time

log = logging.getLogger(__name__)

def get_error_message(error):
    '''
    Get human readable message from Python Exception
    '''
    return error.args[0] if error.args else ''


class HubbleException(Exception):
    '''
    Base exception class; all exceptions should subclass this
    '''
    def __init__(self, message=''):
        # Avoid circular import
        import hubblestack.utils.stringutils
        if not isinstance(message, str):
            message = str(message)
        super(HubbleException, self).__init__(
            hubblestack.utils.stringutils.to_str(message)
        )
        self.message = message

class CommandNotFoundError(HubbleException):
    '''
    Used in modules or grains when a required binary is not available
    '''


class CommandExecutionError(HubbleException):
    '''
    Used when a module runs a command which returns an error and wants
    to show the user the output gracefully instead of dying
    '''
    def __init__(self, message=''):
        # Avoid circular import
        import hubblestack.utils.stringutils
        try:
            exc_str = hubblestack.utils.stringutils.to_unicode(message)
        except TypeError:
            # Exception class instance passed. The HubbleException __init__ will
            # gracefully handle non-string types passed to it
            try:
                exc_str = str(message)
            except UnicodeDecodeError:
                exc_str = hubblestack.utils.stringutils.to_unicode(str(message))  # future lint: disable=blacklisted-function

        # We call the parent __init__ last instead of first because we need the
        # logic above to derive the message string to use for the exception
        # message.
        super(CommandExecutionError, self).__init__(exc_str)

class TimedProcTimeoutError(HubbleException):
    '''
    Thrown when a timed subprocess does not terminate within the timeout,
    or if the specified timeout is not an int or a float
    '''

class HubbleInvocationError(HubbleException, TypeError):
    '''
    Used when the wrong number of arguments are sent to modules or invalid
    arguments are specified on the command line
    '''

class LoaderError(HubbleException):
    '''
    Problems loading the right renderer
    '''

class FileLockError(HubbleException):
    '''
    Used when an error occurs obtaining a file lock
    '''
    def __init__(self, message, time_start=None, *args, **kwargs):
        super(FileLockError, self).__init__(message, *args, **kwargs)
        if time_start is None:
            log.warning(
                'time_start should be provided when raising a FileLockError. '
                'Defaulting to current time as a fallback, but this may '
                'result in an inaccurate timeout.'
            )
            self.time_start = time.time()
        else:
            self.time_start = time_start


class GitLockError(HubbleException):
    '''
    Raised when an uncaught error occurs in the midst of obtaining an
    update/checkout lock in gitfs.
    '''
    def __init__(self, errno, message, *args, **kwargs):
        super(GitLockError, self).__init__(message, *args, **kwargs)
        self.errno = errno


class GitRemoteError(HubbleException):
    '''
    Used by GitFS to denote a problem with the existence of the "origin" remote
    or part of its configuration
    '''


class TimeoutError(HubbleException):
    '''
    Thrown when an opration cannot be completet within a given time limit.
    '''

class NotImplemented(HubbleException):
    '''
    Used when a module runs a command which returns an error and wants
    to show the user the output gracefully instead of dying
    '''

class ArgumentValueError(CommandExecutionError):
    '''
    Used when an invalid argument was passed to a command execution
    '''


class MissingSmb(HubbleException):
    '''
    Raised when no smb library is found.
    '''

class MinionError(HubbleException):
    '''
    Minion problems reading uris such as salt:// or http://
    '''

class HubbleConfigurationError(HubbleException):
    """
    Configuration Error
    """

class FileserverConfigError(HubbleException):
    '''
    Used when invalid fileserver settings are detected
    '''

class HubbleRenderError(HubbleException):
    '''
    Used when a renderer needs to raise an explicit error. If a line number and
    buffer string are passed, get_context will be invoked to get the location
    of the error.
    '''
    def __init__(self,
                 message,
                 line_num=None,
                 buf='',
                 marker='    <======================',
                 trace=None):
        # Avoid circular import
        import hubblestack.utils.stringutils
        self.error = message
        try:
            exc_str = hubblestack.utils.stringutils.to_unicode(message)
        except TypeError:
            # Exception class instance passed. The HubbleException __init__ will
            # gracefully handle non-string types passed to it, but since this
            # class needs to do some extra stuff with the exception "message"
            # before handing it off to the parent class' __init__, we'll need
            # to extract the message from the exception instance here
            try:
                exc_str = str(message)
            except UnicodeDecodeError:
                exc_str = hubblestack.utils.stringutils.to_unicode(str(message))  # future lint: disable=blacklisted-function
        self.line_num = line_num
        self.buffer = buf
        self.context = ''
        if trace:
            exc_str += '\n{0}\n'.format(trace)
        if self.line_num and self.buffer:
            self.context = hubblestack.utils.stringutils.get_context(
                self.buffer,
                self.line_num,
                marker=marker
            )
            exc_str += '; line {0}\n\n{1}'.format(
                self.line_num,
                hubblestack.utils.stringutils.to_unicode(self.context),
            )
        super(HubbleRenderError, self).__init__(exc_str)

class HubbleDeserializationError(HubbleException):
    '''
    Thrown when hubble cannot deserialize data.
    '''

class HubbleReqTimeoutError(HubbleException):
    """
    Thrown when a request fails to return within the timeout
    """

class HubbleDeserializationError(HubbleException):
    '''
    Thrown when hubble cannot deserialize data.
    '''

class HubbleCheckVersionIncompatibleError(Exception):
    """
    Used when an audit check is skipped due to Hubble Version check
    """
    def __init__(self, message):
        super().__init__(message)

class HubbleCheckFailedError(Exception):
    """
    Used when an audit check is failed
    """
    def __init__(self, message):
        super().__init__(message)

class HubbleCheckValidationError(Exception):
    """
    Used when an audit check is wrongly written or some mandatory params are not passed
    """
    def __init__(self, message):
        super().__init__(message)

# -*- coding: utf-8 -*-
'''
This module is a central location for all hubble exceptions
'''

import copy
import logging
import time

log = logging.getLogger(__name__)

def get_error_message(error):
    '''
    Get human readable message from Python Exception
    '''
    return error.args[0] if error.args else ''


class HubbleException(Exception):
    '''
    Base exception class; all exceptions should subclass this
    '''
    def __init__(self, message=''):
        # Avoid circular import
        import hubblestack.utils.stringutils
        if not isinstance(message, str):
            message = str(message)
        super(HubbleException, self).__init__(
            hubblestack.utils.stringutils.to_str(message)
        )
        self.message = message

class CommandNotFoundError(HubbleException):
    '''
    Used in modules or grains when a required binary is not available
    '''


class CommandExecutionError(HubbleException):
    '''
    Used when a module runs a command which returns an error and wants
    to show the user the output gracefully instead of dying
    '''
    def __init__(self, message=''):
        # Avoid circular import
        import hubblestack.utils.stringutils
        try:
            exc_str = hubblestack.utils.stringutils.to_unicode(message)
        except TypeError:
            # Exception class instance passed. The HubbleException __init__ will
            # gracefully handle non-string types passed to it
            try:
                exc_str = str(message)
            except UnicodeDecodeError:
                exc_str = hubblestack.utils.stringutils.to_unicode(str(message))  # future lint: disable=blacklisted-function

        # We call the parent __init__ last instead of first because we need the
        # logic above to derive the message string to use for the exception
        # message.
        super(CommandExecutionError, self).__init__(exc_str)

class TimedProcTimeoutError(HubbleException):
    '''
    Thrown when a timed subprocess does not terminate within the timeout,
    or if the specified timeout is not an int or a float
    '''

class HubbleInvocationError(HubbleException, TypeError):
    '''
    Used when the wrong number of arguments are sent to modules or invalid
    arguments are specified on the command line
    '''

class LoaderError(HubbleException):
    '''
    Problems loading the right renderer
    '''

class FileLockError(HubbleException):
    '''
    Used when an error occurs obtaining a file lock
    '''
    def __init__(self, message, time_start=None, *args, **kwargs):
        super(FileLockError, self).__init__(message, *args, **kwargs)
        if time_start is None:
            log.warning(
                'time_start should be provided when raising a FileLockError. '
                'Defaulting to current time as a fallback, but this may '
                'result in an inaccurate timeout.'
            )
            self.time_start = time.time()
        else:
            self.time_start = time_start


class GitLockError(HubbleException):
    '''
    Raised when an uncaught error occurs in the midst of obtaining an
    update/checkout lock in gitfs.
    '''
    def __init__(self, errno, message, *args, **kwargs):
        super(GitLockError, self).__init__(message, *args, **kwargs)
        self.errno = errno


class GitRemoteError(HubbleException):
    '''
    Used by GitFS to denote a problem with the existence of the "origin" remote
    or part of its configuration
    '''


class TimeoutError(HubbleException):
    '''
    Thrown when an opration cannot be completet within a given time limit.
    '''

class NotImplemented(HubbleException):
    '''
    Used when a module runs a command which returns an error and wants
    to show the user the output gracefully instead of dying
    '''

class ArgumentValueError(CommandExecutionError):
    '''
    Used when an invalid argument was passed to a command execution
    '''


class MissingSmb(HubbleException):
    '''
    Raised when no smb library is found.
    '''

class MinionError(HubbleException):
    '''
    Minion problems reading uris such as salt:// or http://
    '''

class HubbleConfigurationError(HubbleException):
    """
    Configuration Error
    """

class FileserverConfigError(HubbleException):
    '''
    Used when invalid fileserver settings are detected
    '''

class HubbleRenderError(HubbleException):
    '''
    Used when a renderer needs to raise an explicit error. If a line number and
    buffer string are passed, get_context will be invoked to get the location
    of the error.
    '''
    def __init__(self,
                 message,
                 line_num=None,
                 buf='',
                 marker='    <======================',
                 trace=None):
        # Avoid circular import
        import hubblestack.utils.stringutils
        self.error = message
        try:
            exc_str = hubblestack.utils.stringutils.to_unicode(message)
        except TypeError:
            # Exception class instance passed. The HubbleException __init__ will
            # gracefully handle non-string types passed to it, but since this
            # class needs to do some extra stuff with the exception "message"
            # before handing it off to the parent class' __init__, we'll need
            # to extract the message from the exception instance here
            try:
                exc_str = str(message)
            except UnicodeDecodeError:
                exc_str = hubblestack.utils.stringutils.to_unicode(str(message))  # future lint: disable=blacklisted-function
        self.line_num = line_num
        self.buffer = buf
        self.context = ''
        if trace:
            exc_str += '\n{0}\n'.format(trace)
        if self.line_num and self.buffer:
            self.context = hubblestack.utils.stringutils.get_context(
                self.buffer,
                self.line_num,
                marker=marker
            )
            exc_str += '; line {0}\n\n{1}'.format(
                self.line_num,
                hubblestack.utils.stringutils.to_unicode(self.context),
            )
        super(HubbleRenderError, self).__init__(exc_str)

class HubbleDeserializationError(HubbleException):
    '''
    Thrown when hubble cannot deserialize data.
    '''

class HubbleReqTimeoutError(HubbleException):
    """
    Thrown when a request fails to return within the timeout
    """

class HubbleDeserializationError(HubbleException):
    '''
    Thrown when hubble cannot deserialize data.
    '''

class HubbleCheckVersionIncompatibleError(Exception):
    """
    Used when an audit check is skipped due to Hubble Version check
    """
    def __init__(self, message):
        super().__init__(message)

class HubbleCheckFailedError(Exception):
    """
    Used when an audit check is failed
    """
    def __init__(self, message):
        super().__init__(message)

class HubbleCheckValidationError(Exception):
    """
    Used when an audit check is wrongly written or some mandatory params are not passed
    """
    def __init__(self, message):
        super().__init__(message)

# -*- coding: utf-8 -*- This module is a central location for all hubble exceptions Get human readable message from Python Exception Base exception class; all exceptions should subclass this # Avoid circular import Used in modules or grains when a required binary is not available Used when a module runs a command which returns an error and wants     to show the user the output gracefully instead of dying # Avoid circular import # Exception class instance passed. The HubbleException __init__ will # gracefully handle non-string types passed to it # future lint: disable=blacklisted-function # We call the parent __init__ last instead of first because we need the # logic above to derive the message string to use for the exception # message. Thrown when a timed subprocess does not terminate within the timeout,     or if the specified timeout is not an int or a float Used when the wrong number of arguments are sent to modules or invalid     arguments are specified on the command line Problems loading the right renderer Used when an error occurs obtaining a file lock Raised when an uncaught error occurs in the midst of obtaining an     update/checkout lock in gitfs. Used by GitFS to denote a problem with the existence of the "origin" remote     or part of its configuration Thrown when an opration cannot be completet within a given time limit. Used when a module runs a command which returns an error and wants     to show the user the output gracefully instead of dying Used when an invalid argument was passed to a command execution Raised when no smb library is found. Minion problems reading uris such as salt:// or http:// Configuration Error Used when invalid fileserver settings are detected Used when a renderer needs to raise an explicit error. If a line number and     buffer string are passed, get_context will be invoked to get the location     of the error. # Avoid circular import # Exception class instance passed. The HubbleException __init__ will # gracefully handle non-string types passed to it, but since this # class needs to do some extra stuff with the exception "message" # before handing it off to the parent class' __init__, we'll need # to extract the message from the exception instance here # future lint: disable=blacklisted-function Thrown when hubble cannot deserialize data. Thrown when a request fails to return within the timeout Thrown when hubble cannot deserialize data. Used when an audit check is skipped due to Hubble Version check Used when an audit check is failed Used when an audit check is wrongly written or some mandatory params are not passed