#
# I got it on https://github.com/django-macaddress/django-macaddress
#
from ipaddress import ip_address
from netaddr import EUI, AddrFormatError
from django.core.exceptions import ValidationError
from django.db import models

from .formfields import MACAddressField as MACAddressFormField
from . import default_dialect
import warnings


class MACAddressField(models.Field):
    description = "A MAC address validated by netaddr.EUI"
    empty_strings_allowed = False
    dialect = None

    def __init__(self, *args, **kwargs):
        self.integer = kwargs.pop('integer', True)
        if not self.integer:  # If storing MAC address as string, set max_length to default (17) or use supplied kwarg value.
            kwargs['max_length'] = kwargs.get('max_length', 17)
        super(MACAddressField, self).__init__(*args, **kwargs)

    def deconstruct(self):
        ''' Django 1.7 migrations require this method
            https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#field-deconstruction
        '''
        name, path, args, kwargs = super(MACAddressField, self).deconstruct()
        kwargs['integer'] = self.integer
        return name, path, args, kwargs

    @classmethod
    def set_dialect(cls, new_dialect_clazz):
        ''' Setting dialect for EUI (MAC addresses) globally to this Field
        class.
        Class new_dialect_clazz should (finally) extend
        netaddr.strategy.eui48.mac_eui48.
        '''
        warnings.warn(
            "The set_dialect method has been deprecated, in favor of the default_dialect utility function and "
            " settings.MACADDRESS_DEFAULT_DIALECT. See macaddress.__init__.py source or the project README for "
            "more information.",
            DeprecationWarning,
        )
        cls.dialect = new_dialect_clazz

    def get_prep_value(self, value):
        if value is None:
            return None
        if not isinstance(value, EUI):
            value = self.to_python(value)
            if self.integer:
                return int(value)
            return str(value)
        value.dialect = default_dialect(self)
        if self.integer:
            return int(value)
        return str(value)

    def get_internal_type(self):
        if self.integer:
            return 'BigIntegerField'
        return 'CharField'

    def from_db_value(self, value, expression, connection):
        return self.to_python(value)

    def to_python(self, value):
        if value is None:
            return value
        if isinstance(value, EUI):
            value.dialect = default_dialect(value)
            return value
        try:
            return EUI(value, version=48, dialect=default_dialect())
        except (TypeError, ValueError, AddrFormatError):
            raise ValidationError(
                "This value must be a valid MAC address.")

    def formfield(self, **kwargs):
        defaults = {'form_class': MACAddressFormField}
        defaults.update(kwargs)
        return super(MACAddressField, self).formfield(**defaults)

    def get_prep_lookup(self, lookup_type, value):
        # data is stored internally as integer so searching as string
        # yeild 0 result. for example: useful for search in admin.
        if lookup_type in ('exact', 'iexact', 'icontains', 'icontains'):
            try:
                return self.get_prep_value(value)
            except AddrFormatError:
                return None
        elif lookup_type == 'in':
            try:
                macs = []
                for mac in value:
                    macs.extend(self.get_prep_value(mac))
                return macs
            except AddrFormatError:
                return None
        else:
            raise TypeError('Lookup type %r not supported.' % lookup_type)


try:
    from south.modelsinspector import add_introspection_rules

    add_introspection_rules((), ("^macaddress\.fields\.MACAddressField",))
except ImportError:
    pass


# DEPRECATED: remove after clean old migrations
class MyGenericIPAddressField(models.GenericIPAddressField):
    description = "Int32 notation ip address"

    def __init__(self, protocol='ipv4', *args, **kwargs):
        super(MyGenericIPAddressField, self).__init__(protocol=protocol, *args, **kwargs)
        self.max_length = 8

    def get_prep_value(self, value):
        # strIp to Int
        value = super(MyGenericIPAddressField, self).get_prep_value(value)
        if value:
            return int(ip_address(value))

    def to_python(self, value):
        return value

    def get_internal_type(self):
        return 'PositiveIntegerField'

    @staticmethod
    def from_db_value(value, expression, connection):
        if value:
            return str(ip_address(value))

    def int_ip(self):
        return int(ip_address(self))
