import string
import os
import datetime
import logging
import re
from subprocess import call

import urllib.parse
from decimal import Decimal, getcontext
getcontext().prec=2 #use 2 significant figures for decimal calculations

import settings

from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import Context, loader

import troggle.core.models_survex 

def get_related_by_wikilinks(wiki_text):
    found=re.findall(settings.QM_PATTERN,wiki_text)
    res=[]
    for wikilink in found:
        qmdict={'urlroot':settings.URL_ROOT,'cave':wikilink[2],'year':wikilink[1],'number':wikilink[3]}
        try:
            cave_slugs = models_caves.CaveSlug.objects.filter(cave__kataster_number = qmdict['cave'])
            qm=QM.objects.get(found_by__cave_slug__in = cave_slugs,
                              found_by__date__year = qmdict['year'],
                              number = qmdict['number'])
            res.append(qm)         
        except QM.DoesNotExist:
            print(('fail on '+str(wikilink)))
    
    return res

try:
      logging.basicConfig(level=logging.DEBUG,
                           filename=settings.LOGFILE,
                           filemode='w')
except:
# Opening of file for writing is going to fail currently, so decide it doesn't matter for now    
      pass

#This class is for adding fields and methods which all of our models will have.
class TroggleModel(models.Model):
    new_since_parsing = models.BooleanField(default=False, editable=False)
    non_public = models.BooleanField(default=False)
    def object_name(self):
        return self._meta.object_name

    def get_admin_url(self):
        return urllib.parse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk))

    class Meta:
        abstract = True

class DataIssue(TroggleModel):
    date = models.DateTimeField(auto_now_add=True, blank=True)
    parser = models.CharField(max_length=50, blank=True, null=True)
    message = models.CharField(max_length=400, blank=True, null=True)

    class Meta:
        ordering = ['date']

    def __str__(self):
        return "%s - %s" % (self.parser, self.message)

# 
# single Expedition, usually seen by year
#
class Expedition(TroggleModel):
    year        = models.CharField(max_length=20, unique=True)
    name        = models.CharField(max_length=100)
        
    def __str__(self):
        return self.year

    class Meta:
        ordering = ('-year',)
        get_latest_by = 'year'
    
    def get_absolute_url(self):
        return urllib.parse.urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year]))
    
    # construction function.  should be moved out
    def get_expedition_day(self, date):
        expeditiondays = self.expeditionday_set.filter(date=date)
        if expeditiondays:
            assert len(expeditiondays) == 1
            return expeditiondays[0]
        res = ExpeditionDay(expedition=self, date=date)
        res.save()
        return res
        
    def day_min(self):
        res = self.expeditionday_set.all()
        return res and res[0] or None
    
    def day_max(self):
        res = self.expeditionday_set.all()
        return res and res[len(res) - 1] or None

class ExpeditionDay(TroggleModel):
    expedition  = models.ForeignKey("Expedition")
    date        = models.DateField()

    class Meta:
        ordering = ('date',)

    def GetPersonTrip(self, personexpedition):
        personexpeditions = self.persontrip_set.filter(expeditionday=self)
        return personexpeditions and personexpeditions[0] or None

class Person(TroggleModel):
    """single Person, can go on many years
    """
    first_name  = models.CharField(max_length=100)
    last_name   = models.CharField(max_length=100)
    fullname    = models.CharField(max_length=200)
    is_vfho     = models.BooleanField(help_text="VFHO is the Vereines für Höhlenkunde in Obersteier, a nearby Austrian caving club.", default=False)
    mug_shot    = models.CharField(max_length=100, blank=True,null=True)
    blurb = models.TextField(blank=True,null=True)
    
    #href        = models.CharField(max_length=200)
    orderref    = models.CharField(max_length=200)  # for alphabetic 
    user	= models.OneToOneField(User, null=True, blank=True)
    def get_absolute_url(self):
        return urllib.parse.urljoin(settings.URL_ROOT,reverse('person',kwargs={'first_name':self.first_name,'last_name':self.last_name}))

    class Meta:
        verbose_name_plural = "People"
        ordering = ('orderref',)  # "Wookey" makes too complex for: ('last_name', 'first_name') 
    
    def __str__(self):
        if self.last_name:
            return "%s %s" % (self.first_name, self.last_name)
        return self.first_name


    def notability(self):
        notability = Decimal(0)
        max_expo_val = 0

        max_expo_year = Expedition.objects.all().aggregate(models.Max('year'))
        max_expo_val = int(max_expo_year['year__max']) + 1

        for personexpedition in self.personexpedition_set.all():
             if not personexpedition.is_guest:
                print((personexpedition.expedition.year))
                notability += Decimal(1) / (max_expo_val - int(personexpedition.expedition.year))
        return notability

    def bisnotable(self):
        return self.notability() > Decimal(1)/Decimal(3)
    
    def surveyedleglength(self):
        return sum([personexpedition.surveyedleglength()  for personexpedition in self.personexpedition_set.all()])
    
    def first(self):
        return self.personexpedition_set.order_by('-expedition')[0]
    def last(self):
        return self.personexpedition_set.order_by('expedition')[0]

class PersonExpedition(TroggleModel):
    """Person's attendance to one Expo
    """
    expedition  = models.ForeignKey(Expedition)
    person      = models.ForeignKey(Person)
    slugfield   = models.SlugField(max_length=50,blank=True,null=True)
    
    is_guest    = models.BooleanField(default=False)  
    COMMITTEE_CHOICES = (
        ('leader','Expo leader'),
        ('medical','Expo medical officer'),
        ('treasurer','Expo treasurer'),
        ('sponsorship','Expo sponsorship coordinator'),
        ('research','Expo research coordinator'),
        )
    expo_committee_position = models.CharField(blank=True,null=True,choices=COMMITTEE_CHOICES,max_length=200)
    nickname    = models.CharField(max_length=100,blank=True,null=True)
    
    def GetPersonroles(self):
        res = [ ]
        for personrole in self.personrole_set.order_by('survexblock'):
            if res and res[-1]['survexpath'] == personrole.survexblock.survexpath:
                res[-1]['roles'] += ", " + str(personrole.role)
            else:
                res.append({'date':personrole.survexblock.date, 'survexpath':personrole.survexblock.survexpath, 'roles':str(personrole.role)})
        return res

    class Meta:
        ordering = ('-expedition',)
        #order_with_respect_to = 'expedition'

    def __str__(self):
        return "%s: (%s)" % (self.person, self.expedition)
    
    #why is the below a function in personexpedition, rather than in person? - AC 14 Feb 09
    def name(self):
        if self.nickname:
            return "%s (%s) %s" % (self.person.first_name, self.nickname, self.person.last_name)
        if self.person.last_name:
            return "%s %s" % (self.person.first_name, self.person.last_name)
        return self.person.first_name

    def get_absolute_url(self):
        return urllib.parse.urljoin(settings.URL_ROOT, reverse('personexpedition',kwargs={'first_name':self.person.first_name,'last_name':self.person.last_name,'year':self.expedition.year}))
	
    def surveyedleglength(self):
        survexblocks = [personrole.survexblock  for personrole in self.personrole_set.all() ]
        return sum([survexblock.totalleglength  for survexblock in set(survexblocks)])
    
    # would prefer to return actual person trips so we could link to first and last ones
    def day_min(self):
        res = self.persontrip_set.aggregate(day_min=Min("expeditionday__date"))
        return res["day_min"]

    def day_max(self):
        res = self.persontrip_set.all().aggregate(day_max=models.Max("expeditionday__date"))
        return res["day_max"]