from datetime import *
from dateutil import relativedelta

from django.db import models
from django.db.models import permalink
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.contrib.localflavor.us.models import PhoneNumberField, USStateField
from fields import ZipCodeField
from django_extensions.db.models import TimeStampedModel
import os
import csv
import urllib

# import pbp_com.settings as settings
from django.conf import settings


def get_lat_long(location):
    key = settings.GOOGLE_API_KEY
    output = "csv"
    location = urllib.quote_plus(location)
    request = "http://maps.google.com/maps/geo?q=%s&output=%s&key=%s" % (
        location,
        output,
        key,
    )
    data = urllib.urlopen(request).read()
    dlist = data.split(",")
    if dlist[0] == "200":
        return "%s, %s" % (dlist[2], dlist[3])
    else:
        return ""


class Person(TimeStampedModel):
    """Person model."""

    GENDER_CHOICES = (
        (1, "Male"),
        (2, "Female"),
    )
    title = models.CharField(_("title"), blank=True, null=True, max_length=20)
    first_name = models.CharField(_("first name"), blank=True, max_length=100)
    middle_name = models.CharField(
        _("middle name"), blank=True, null=True, max_length=100
    )
    last_name = models.CharField(_("last name"), blank=True, max_length=100)
    nickname = models.CharField(_("nickname"), blank=True, null=True, max_length=100)
    suffix = models.CharField(_("suffix"), blank=True, null=True, max_length=20)
    slug = models.SlugField(_("slug"), unique=True)
    user = models.ForeignKey(
        User,
        blank=True,
        null=True,
        help_text="If the person is an existing user of your site.",
    )
    gender = models.PositiveSmallIntegerField(
        _("gender"), choices=GENDER_CHOICES, blank=True, null=True
    )
    birth_date = models.DateField(_("birth date"), blank=True, null=True)
    death_date = models.DateField(_("death date"), blank=True, null=True)
    phone = PhoneNumberField(blank=True)
    email = models.EmailField(blank=True)
    town = models.ForeignKey("Town", blank=True, null=True)

    class Meta:
        verbose_name = _("person")
        verbose_name_plural = _("people")
        ordering = ("last_name", "first_name")

    def __unicode__(self):
        return u"%s" % self.full_name

    @property
    def full_name(self):
        return u"%s %s" % (self.first_name, self.last_name)

    @property
    def age(self):
        if self.death_date:
            DELTA = self.death_date
        else:
            DELTA = datetime.today()
        return u"%s" % relativedelta.relativedelta(DELTA, self.birth_date).years

    @permalink
    def get_absolute_url(self):
        return ("di-person-detail", None, {"slug": self.slug})


class Town(TimeStampedModel):
    """Town model."""

    name = models.CharField(_("name"), max_length=100)
    state = USStateField(_("state"))
    slug = models.SlugField(_("slug"), unique=True)
    in_coverage = models.BooleanField(_("in coverage"), default=False)
    zipcode = ZipCodeField(
        _("Zipcode"),
        blank=True,
        null=True,
        help_text="Use for a primary zipcode when town has multiple.",
        max_length=5,
    )

    class Meta:
        unique_together = (("name", "state",),)
        ordering = (
            "state",
            "name",
        )

    def __unicode__(self):
        return u"%s, %s" % (self.name, self.state)

    @permalink
    def get_absolute_url(self):
        return ("di-town-detail", None, {"slug": self.slug})


class PopulationYear(TimeStampedModel):
    """ Population yaer model.

    Keeps track of a population count for a town in a given (usually census) year.
    """

    town = models.ForeignKey(Town)
    year = models.IntegerField(_("year"), max_length=4)
    population = models.IntegerField(_("population"), max_length=7)

    def __unicode__(self):
        return u"%s %s population" % (self.town, self.year)


class TownInfo(TimeStampedModel):
    """ Town info model.

    Keeps track of various pieces of town info for our register.
    
    We create a separate model so that we can use a really simple
    setup for our legacy website and just rewrite this whole class
    when we're ready to implement some higher-level town info stuff.

    This way we do not have to delete town ids and mess up all related_name
    applications.
    """

    town = models.ForeignKey(Town)
    office = models.ForeignKey("Place")
    po_box = models.IntegerField(_("PO Box"))
    map = models.FileField(
        _("Town map"), blank=True, null=True, upload_to="directory/maps/"
    )
    time_info = models.TextField(_("Contact info"))
    description = models.TextField(_("Description"))
    officials = models.TextField(_("Officials"))
    tax_info = models.TextField(_("Tax info"))
    permits = models.TextField(_("Permits"))
    town_ordinances = models.TextField(_("Town ordinances"))
    post_offices = models.TextField(_("Post offices"))
    total_area = models.IntegerField(_("Total area"), help_text="In acres")
    land_area = models.IntegerField(_("Land"), help_text="In acres")
    bog_area = models.IntegerField(_("Bog"), help_text="In acres", default=0)
    flood_plain_area = models.IntegerField(
        _("Flood plain"), help_text="In acres", default=0
    )
    inland_water_area = models.IntegerField(
        _("Inland water"), help_text="In acres", default=0
    )
    shoreline = models.IntegerField(_("Shoreline"), help_text="In miles", default=0)
    populations = models.ManyToManyField(PopulationYear, blank=True, null=True)
    edu_contact = models.TextField(_("Education contact"))
    enrollment = models.TextField(_("Enrollment numbers"))
    fire_dept_info = models.TextField(_("Fire department"))
    cemetery_info = models.TextField(_("Cemeteries"), blank=True, null=True)
    trash_recycle_info = models.TextField(_("Trash & recycling"), blank=True, null=True)
    public_restrooms = models.TextField(_("Public restrooms"), blank=True, null=True)
    walking_trails = models.TextField(_("Walking trails"), blank=True, null=True)
    public_landings = models.TextField(_("Public landings"), blank=True, null=True)

    def __unicode__(self):
        return u"%s information" % (self.town)

    @permalink
    def get_absolute_url(self):
        return ("di-town-info", None, {"slug": self.town.slug})


class Committee(TimeStampedModel):
    """Committee model."""

    title = models.CharField(_("title"), max_length=100)
    slug = models.SlugField(_("slug"), unique=True)
    town = models.ForeignKey(Town, related_name="town_committee")
    members = models.ManyToManyField(Person, blank=True, null=True)

    def __unicode__(self):
        return u"%s %s" % (self.town, self.title)

    def get_absolute_url(self):
        args = self.slug
        return reverse("di-committee-detail", args=args)


class Point(TimeStampedModel):
    lat_lon = models.CharField(_("coordinates"), blank=True, null=True, max_length=255)
    address = models.CharField(_("address"), max_length=255)
    town = models.ForeignKey(Town)
    zipcode = models.CharField(_("zip"), max_length=10, blank=True)

    def __unicode__(self):
        return u"%s, %s" % (self.address, self.town)

    class Meta:
        verbose_name = _("point")
        verbose_name_plural = _("points")

    def save(self, *args, **kwargs):
        if not self.lat_lon:
            location = "%s +%s +%s +%s" % (
                self.address,
                self.town,
                self.town.state,
                self.zipcode,
            )
            self.lat_lon = get_lat_long(location)
            if not self.lat_lon:
                location = "%s +%s +%s" % (self.town, self.town.state, self.zipcode)
                self.lat_lon = get_lat_long(location)
        super(Point, self).save(*args, **kwargs)


class Place(TimeStampedModel):
    """Place model for Directory application."""

    STATUS_CHOICES = (
        (0, "Inactive"),
        (1, "Active"),
    )
    point = models.ForeignKey(Point, blank=True, null=True)
    title = models.CharField(_("Title"), max_length=255)
    slug = models.SlugField(_("Slug"))
    description = models.TextField(_("Description"), blank=True, null=True)
    status = models.IntegerField(_("Status"), choices=STATUS_CHOICES, default=1)
    po_box = models.IntegerField(_("P.O. Box"), blank=True, null=True, max_length=5)
    po_box_town = models.ForeignKey(Town, blank=True, null=True)
    phone = PhoneNumberField(_("Phone"), blank=True, null=True)
    fax = PhoneNumberField(_("Fax"), blank=True, null=True)
    email = models.EmailField(_("Email"), blank=True, null=True)
    website = models.URLField(_("Website"), blank=True, null=True, verify_exists=False)

    def __unicode__(self):
        return self.title

    @permalink
    def get_absolute_url(self):
        return ("di-place-detail", None, {"slug": self.slug})


class SchoolAdministrativeUnit(TimeStampedModel):
    """
    An SAU, as defined by the state of Maine.
    """

    name = models.CharField(_("name"), max_length=100)
    slug = models.SlugField(_("slug"), unique=True)
    union = models.IntegerField(_("union"), max_length=2, blank=True, null=True)
    #    governor=models.ForeignKey(Board, blank=True, null=True)

    def __unicode__(self):
        return self.name

    @permalink
    def get_absolute_url(self):
        return ("di-sau-detail", None, {"slug": self.slug})


class School(Place):
    """
    School model.
    A school derives from the Place model, adding a few school-specific fields
    """

    TYPE_CHOICES = (
        ("E", "Elementary School"),
        ("H", "High School"),
        ("C", "Combined School"),
        ("U", "College/University"),
        ("O", "Other"),
    )

    CLASS_CHOICES = (
        ("N", "None"),
        ("A", "A"),
        ("B", "B"),
        ("C", "C"),
        ("D", "D"),
    )

    REGION_CHOICES = (
        ("N", "None"),
        ("W", "West"),
        ("E", "East"),
    )

    short_title = models.CharField(_("short title"), max_length=30)
    type = models.CharField(_("type"), choices=TYPE_CHOICES, default="O", max_length=1)
    # enrollment=models.ManyToMany(Enrollment?)

    administration = models.ForeignKey(SchoolAdministrativeUnit)
    title_one_eligible = models.BooleanField(_("title one eligible"), default=False)
    title_one_recipient = models.BooleanField(_("title one recipient"), default=False)

    school_class = models.CharField(
        _("class"), max_length=1, choices=CLASS_CHOICES, default="N"
    )
    region = models.CharField(
        _("region"), max_length=2, choices=REGION_CHOICES, default="N"
    )
    mascot = models.CharField(_("mascot"), max_length=50, blank=True, null=True)
    athletic_director = models.ForeignKey(
        Person, related_name="athletic_director", blank=True, null=True
    )
    principal = models.ForeignKey(
        Person, related_name="principal", blank=True, null=True
    )

    @permalink
    def get_absolute_url(self):
        return ("di-school-detail", None, {"slug": self.slug})


class PhoneBookEntry(TimeStampedModel):
    entry = models.CharField(_("entry"), max_length=100)
    phone = PhoneNumberField()
    town = models.ForeignKey(Town)
    owner = models.ForeignKey(Person, blank=True, null=True)
    related_place = models.ForeignKey(Place, blank=True, null=True)

    def __unicode__(self):
        return u"%s: %s" % (self.entry, self.phone)

    class Meta:
        verbose_name = _("phone book entry")
        verbose_name_plural = _("phone book entries")


class PhoneBookEntryUpload(models.Model):
    data_file = models.FileField(
        _("data file (.csv)"),
        upload_to="temp",
        help_text=_("Select a .csv file of phone book data to upload."),
    )
    town = models.ForeignKey(Town)

    class Meta:
        verbose_name = _("phone book entry upload")
        verbose_name_plural = _("phone book entry uploads")

    def save(self):
        super(PhoneBookEntryUpload, self).save()
        self.process_datafile()
        super(PhoneBookEntryUpload, self).delete()

    def process_datafile(self):
        if os.path.isfile(self.data_file.path):
            entry_data = csv.reader(open(self.data_file.path), delimiter="\t")
            for row in entry_data:
                args = {}
                args["town"] = self.town
                args["entry"] = row[0]
                if len(row[1]) > 8 or len(row[1]) < 4:
                    args["phone"] = row[1]
                else:
                    args["phone"] = "207-" + row[1]
                entry = PhoneBookEntry.objects.create(**args)
                try:
                    entry.save()
                except:
                    pass
