"""
IPAddressField for models with IPv4 & IPv6 support

Requires: IPy
http://software.inl.fr/trac/wiki/IPy http://c0re.23.nu/c0de/IPy/
On Debian/Ubuntu: apt-get install python-ipy

Example:
 
class Host(models.Model):
       hostname = models.CharField()
       ip = IPAddressField()

>>> my_host = Host()
>>> my_host.hostname = 'server'
>>> my_host.ip = '192.168.0.1'
>>> my_host.save()
>>> my_host.ip
IP('192.168.0.1')
>>> my_host.ip = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
>>> dir(my_host.ip)
['NoPrefixForSingleIp', 'WantPrefixLen', '__add__', '__cmp__', '__contains__',
'__doc__', '__getitem__', '__hash__', '__init__', '__len__', '__module__',
'__nonzero__', '__repr__', '__str__', '_ipversion', '_prefixlen', '_printPrefix',
'broadcast', 'int', 'ip', 'iptype', 'len', 'make_net', 'net', 'netmask', 'overlaps',
'prefixlen', 'reverseName', 'reverseNames', 'strBin', 'strCompressed', 'strDec',
'strFullsize', 'strHex', 'strNetmask', 'strNormal', 'version']
>>> my_host.ip.reverseName()
'f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.ip6.arpa.'
>>> my_host.ip.version()
6
>>> my_host.ip = '1.2.3.4.5'
ValidationError: IPv4 Address with more than 4 bytes
>>> my_host.ip = 'aa:dd:xx'
ValidationError: 'aa:dd:xx': Invalid IPv6 address: should have 8 hextets
"""

from django.forms import ValidationError as FormValidationError
from django.core.exceptions import ValidationError
from django.forms import fields, widgets
from django.db import models

from decimal import Decimal
from IPy import IP

IP.__long__ = IP.int

def clean_ip(ip):
	'Method for validating IPs on forms'
        try:
                IP(ip)
        except Exception, e:
                raise FormValidationError(e)

	return ip

class IPAddressWidget(widgets.TextInput):
        def render(self, name, value, attrs=None):
                if isinstance(value, IP):
                        value = unicode(value)

                return super(IPAddressWidget, self).render(name, value, attrs)

class IPAddressField(models.Field):
        __metaclass__ = models.SubfieldBase

	def db_type(self):
                return 'numeric(39, 0)'

        def to_python(self, value):
                if not value:
                        return None
                elif isinstance(value, Decimal):
                        value = long(value)

                try:
                        return IP(value)
                except Exception, e:
                        raise ValidationError(e)

	def get_db_prep_lookup(self, lookup_type, value):
		try:
			if lookup_type in ('range', 'in'):
        	                         return [self.get_db_prep_value(v) for v in value]

			return [self.get_db_prep_value(value)]
		except ValidationError:
			return super(IPAddressField, self).get_db_prep_lookup(lookup_type, value)

	def get_db_prep_value(self, value):
		try:
			return long(self.to_python(value))
		except TypeError:
			return None

        def formfield(self, **kwargs):
                defaults = {
                        'form_class': fields.CharField,
                        'widget': IPAddressWidget,
                }
                defaults.update(kwargs)
                return super(IPAddressField, self).formfield(**defaults)