

class EzazException(Exception):
    pass


class RequiredCommand(EzazException):
    pass


class NoDefaultAction(EzazException):
    pass


class ChoiceError(EzazException):
    pass


class NoChoices(ChoiceError):
    pass


class NoneOfTheAboveChoice(ChoiceError):
    pass


class ImageError(EzazException):
    pass


class UnknownImageFormat(ImageError):
    def __init__(self, filename):
        super().__init__(f"Unknown image format for '{filename}'")


class ImageConversionFailed(ImageError):
    pass


class CacheError(EzazException):
    pass


class InvalidCache(CacheError):
    pass


class InvalidCacheExpiry(CacheError):
    pass


class CacheMiss(CacheError):
    pass


class NoCache(CacheMiss):
    pass


class CacheExpired(CacheError):
    pass


class FilterError(EzazException):
    pass


class FilterRequiresInfo(FilterError):
    pass


class InvalidFilterType(FilterError):
    def __init__(self, filter_type):
        super().__init__(f"Invalid filter type '{filter_type}'")


class InvalidFilter(FilterError):
    pass


class InvalidFilterRegex(InvalidFilter):
    def __init__(self, regex):
        super().__init__(f"Invalid regex: '{regex}'")


class NoParentClass(EzazException):
    pass


class NoParentInstance(EzazException):
    pass


class NoAncestorInstance(EzazException):
    pass


class AzCommandError(EzazException):
    def __init__(self, cmd, stdout=None, stderr=None):
        super().__init__(f'az command failed: {" ".join(cmd)}\n{stderr}')
        self.cmd = cmd
        self.stdout = stdout
        self.stderr = stderr


class NoAzObjectExists(EzazException):
    def __init__(self, obj_name, obj_id):
        super().__init__(f'{obj_name} (id: {obj_id}) does not exist.')


class AzObjectExists(EzazException):
    def __init__(self, obj_name, obj_id):
        super().__init__(f'{obj_name} (id: {obj_id}) already exists.')


class NullAzObject(EzazException):
    def __init__(self, func):
        super().__init__(f'Internal error: null object attempt to use {func}')


class InvalidAzObjectName(EzazException):
    pass


class ConfigError(EzazException):
    pass


class ConfigNotFound(ConfigError):
    pass


class DefaultConfigNotFound(ConfigNotFound):
    def __init__(self, azcls):
        super().__init__(f"Default configuration for {azcls.azobject_text()} not found.")
        self.azobject_class = azcls


class AlreadyLoggedIn(EzazException):
    def __init__(self, info):
        super().__init__(f'You are already logged in as {info}')


class AlreadyLoggedOut(EzazException):
    def __init__(self):
        super().__init__('You are already logged out')


class NotLoggedIn(EzazException):
    def __init__(self, msg='please login and try again.'):
        super().__init__(f'Not logged in: {msg}')


class InteractiveLoginRequired(NotLoggedIn):
    def __init__(self, msg):
        super().__init__(f'Azure reported that interactive/special login is required, see below:\n{msg}')


class UnsupportedAction(EzazException):
    def __init__(self, cls, action=None):
        if action:
            super().__init__(f'Object type {cls.azobject_text()} does not support action {action}.')
        else:
            super().__init__(f'Object type {cls.azobject_text()} is not {self._actionable}.')

    @property
    def _actionable(self):
        return None


class ArgumentError(EzazException):
    def _arg(self, arg):
        return arg if arg.startswith('-') else f"--{arg.replace('_', '-')}"

    def _args(self, args):
        return ', '.join([self._arg(a) for a in args])


class RequiredArgument(ArgumentError):
    def __init__(self, arg, required_by=None, **kwargs):
        super().__init__(self._msg(arg, required_by, **kwargs))

    def _msg(self, arg, by, **kwargs):
        return f'The argument {self._arg(arg)} is required{self._by(by)}.'

    def _by(self, required_by):
        return f' by {required_by}' if required_by else ''


class RequiredArgumentGroup(RequiredArgument):
    def __init__(self, args, required_by=None, exclusive=False, **kwargs):
        super().__init__(args, required_by=required_by, exclusive=exclusive, **kwargs)

    def _msg(self, args, by, exclusive, **kwargs):
        return f'{"One" if exclusive else "At least one"} of the arguments ({self._args(args)}) are required{self._by(by)}.'


class DuplicateArgument(ArgumentError):
    def __init__(self, arg, value_a, value_b):
        super().__init__(f'The argument {self._arg(arg)} was added multiple times: {value_a} and {value_b}')


class MultipleArgumentValues(ArgumentError):
    def __init__(self, *args, values):
        argstr = f'group ({self._args(args)})' if len(args) > 1 else self._arg(*args)
        super().__init__(f"The argument {argstr} has multiple values: {', '.join(map(str, values))}")


class NoMatchingArgumentValue(ArgumentError):
    def __init__(self, args):
        super().__init__(f"The arguments ({self._args(args)}) applied together filtered out all possible results.")


class InvalidArgument(ArgumentError):
    def __init__(self, arg):
        super().__init__(f'The argument {self._arg(arg)} is invalid.')


class InvalidArgumentValue(ArgumentError):
    def __init__(self, arg, value):
        super().__init__(f'The argument {self._arg(arg)} value {value} is invalid.')


class InvalidDateTimeArgumentValue(ArgumentError):
    def __init__(self, arg, value):
        super().__init__(f'The argument {self._arg(arg)} date/time expression was not understood: {value}')


class InvalidX509DERArgumentValue(ArgumentError):
    def __init__(self, arg):
        super().__init__(f'The argument {self._arg(arg)} value is not a DER-format X509 certificate')


class ArgcompleteError(EzazException):
    pass


class TooLongForArgcomplete(ArgcompleteError):
    def __init__(self, name, action):
        super().__init__(self._msg(name, action))

    def _msg(self, name, action):
        return f"This command takes too long to perform during tab-completion; please cache it first with 'ezaz {name} {action}'"


class InfoError(EzazException):
    pass


class InvalidInfo(InfoError):
    pass


class VmError(EzazException):
    pass


class NoPrimaryNic(VmError):
    def __init__(self, vm):
        super().__init__(f'The virtual machine {vm.info().name} has no primary nic')


class NicError(EzazException):
    pass


class NoPrimaryIpAddr(NicError):
    def __init__(self, nic):
        super().__init__(f'The nic {nic.azobject_id} has no primary ip address')


class IpAddrError(EzazException):
    pass


class NoPublicIp(IpAddrError):
    def __init__(self, nic):
        super().__init__(f'The ip address {ipaddr.azobject_id} has no public ip')
