import math
import random
from django.db import models


class TimeStampedModel (models.Model):
    """
    Base model class for when you want to keep track of created and updated
    times for model instances.

    """
    created_datetime = models.DateTimeField(auto_now_add=True)
    updated_datetime = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class Rating (TimeStampedModel):
    criterion = models.ForeignKey('Criterion', related_name='ratings')
    """ The criterion that this rating is for.
        """

    place1 = models.ForeignKey('Place', related_name='+')
    """ The first place that this rating compares
        """

    place2 = models.ForeignKey('Place', related_name='+')
    """ The second place that this rating compares
        """

    score = models.IntegerField()
    """ The rating score.  1 means that place1 "wins" over place2 for the given
        criterion.  -1 means that place2 "wins".
        """

    user_info = models.ForeignKey('sessions.UserInfo', null=True, related_name='ratings')
    """ The information for the user that made this rating.  Not required, but
        useful for data analysis.
        """

    def __unicode__(self):
        meaning = ({
            -1: 'more {0} than',
            1:  'less {0} than',
            0:  'as {0} as',
        })

        return ('Place #{p1} is {rating} place #{p2}').format(
                p1=self.place1, p2=self.place2,
                rating=meaning[self.score].format(self.criterion.prompt))

    @property
    def question(self):
        """
        The question string to which the rating is a response.
        """
        return self.criterion.prompt


class Criterion (models.Model):
    prompt = models.TextField()
    """ The question prompt, i.e. 'How clean is the street?'.
        """

    def __unicode__(self):
        return self.prompt

    class Meta:
        verbose_name_plural = "criteria"


class Place (models.Model):
    lat = models.FloatField()
    lon = models.FloatField()

    def __unicode__(self):
        return '({0}, {1})'.format(self.lat, self.lon)


class UserInfo (TimeStampedModel):
    lat = models.FloatField(null=True)
    lon = models.FloatField(null=True)
    """ The user's location.
        """

    SOURCES = (
        ('ip', 'IP Address'),
        ('html5', 'HTML5 Geolocation API'),
    )
    location_source = models.CharField(max_length=32, choices=SOURCES)
    location_data = models.CharField(max_length=2048)
    """ The method by which the location was obtained, and any additional
        information required to recreate the location.
        """

    session = models.OneToOneField('sessions.Session')
    """ The Django browser session.
        """

    def __unicode__(self):
        return u'User for session {key}'.format(key=self.session.session_key)

    class Meta:
        app_label = 'sessions'
        db_table = 'project_userinfo'
        verbose_name_plural = 'User info'


class SiteConfiguration (models.Model):
    site = models.OneToOneField('sites.Site', related_name='config')
    google_analytics_key = models.CharField(max_length=256, null=True, blank=True)
    addthis_key = models.CharField(max_length=256, null=True, blank=True)
    addthis_title = models.CharField(max_length=256, null=True, blank=True)

    about_title = models.CharField(max_length=256, null=True, blank=True)
    about_text = models.TextField(null=True, blank=True)
    about_text_is_html = models.BooleanField(blank=True, default=False)

    def __unicode__(self):
        return 'Configuration for {0}'.format(self.site.name)

    class Meta:
        app_label = 'sites'
        db_table = 'project_siteconfiguration'


class SurveySession (object):
    """

    """

    def __init__(self, questions=None, places=None):
        self.__questions = questions
        self.__places = places

    @property
    def questions(self):
        """
        Get the set of questions for this survey.
        """
        return self.__questions or self.init_questions()

    @property
    def places(self):
        """
        Get the block for this session.
        """
        return self.__places or self.init_places()

    def init_places(self):
        """
        Load two places at random.

        TODO: Order the places by those that have the least questions answered
              about them first.
        """
        places = Place.objects.all().order_by('?')[:2]

        self.__places = places
        return self.__places

    def init_questions(self):
        """
        Load a set of questions at random.
        """
        all_questions = (
            Criterion.objects.all()
                .annotate(num_ratings=models.Count('ratings'))
        )
        self.__questions = all_questions
        return self.__questions

    @classmethod
    def make_surveys(cls, count=1):
        # TODO: Choose the places and questions more smartly.  Use the init_...
        #       methods defined above (and make them better too).
        places = list(Place.objects.all().order_by('?')[:(count * 2)])
        questions = list(Criterion.objects.all())
        surveys = []

        for i in range(count):
            place1 = places[2 * i]
            place2 = places[2 * i + 1]

            surveys.append(cls(places=[place1, place2], questions=questions))

        return surveys

[((243, 282), 'django.db.models.DateTimeField', 'models.DateTimeField', ([], {'auto_now_add': '(True)'}), '(auto_now_add=True)\n', (263, 282), False, 'from django.db import models\n'), ((306, 341), 'django.db.models.DateTimeField', 'models.DateTimeField', ([], {'auto_now': '(True)'}), '(auto_now=True)\n', (326, 341), False, 'from django.db import models\n'), ((434, 488), 'django.db.models.ForeignKey', 'models.ForeignKey', (['"""Criterion"""'], {'related_name': '"""ratings"""'}), "('Criterion', related_name='ratings')\n", (451, 488), False, 'from django.db import models\n'), ((562, 606), 'django.db.models.ForeignKey', 'models.ForeignKey', (['"""Place"""'], {'related_name': '"""+"""'}), "('Place', related_name='+')\n", (579, 606), False, 'from django.db import models\n'), ((683, 727), 'django.db.models.ForeignKey', 'models.ForeignKey', (['"""Place"""'], {'related_name': '"""+"""'}), "('Place', related_name='+')\n", (700, 727), False, 'from django.db import models\n'), ((804, 825), 'django.db.models.IntegerField', 'models.IntegerField', ([], {}), '()\n', (823, 825), False, 'from django.db import models\n'), ((984, 1057), 'django.db.models.ForeignKey', 'models.ForeignKey', (['"""sessions.UserInfo"""'], {'null': '(True)', 'related_name': '"""ratings"""'}), "('sessions.UserInfo', null=True, related_name='ratings')\n", (1001, 1057), False, 'from django.db import models\n'), ((1734, 1752), 'django.db.models.TextField', 'models.TextField', ([], {}), '()\n', (1750, 1752), False, 'from django.db import models\n'), ((1980, 1999), 'django.db.models.FloatField', 'models.FloatField', ([], {}), '()\n', (1997, 1999), False, 'from django.db import models\n'), ((2010, 2029), 'django.db.models.FloatField', 'models.FloatField', ([], {}), '()\n', (2027, 2029), False, 'from django.db import models\n'), ((2160, 2188), 'django.db.models.FloatField', 'models.FloatField', ([], {'null': '(True)'}), '(null=True)\n', (2177, 2188), False, 'from django.db import models\n'), ((2199, 2227), 'django.db.models.FloatField', 'models.FloatField', ([], {'null': '(True)'}), '(null=True)\n', (2216, 2227), False, 'from django.db import models\n'), ((2388, 2436), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(32)', 'choices': 'SOURCES'}), '(max_length=32, choices=SOURCES)\n', (2404, 2436), False, 'from django.db import models\n'), ((2457, 2490), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(2048)'}), '(max_length=2048)\n', (2473, 2490), False, 'from django.db import models\n'), ((2647, 2687), 'django.db.models.OneToOneField', 'models.OneToOneField', (['"""sessions.Session"""'], {}), "('sessions.Session')\n", (2667, 2687), False, 'from django.db import models\n'), ((3023, 3080), 'django.db.models.OneToOneField', 'models.OneToOneField', (['"""sites.Site"""'], {'related_name': '"""config"""'}), "('sites.Site', related_name='config')\n", (3043, 3080), False, 'from django.db import models\n'), ((3108, 3163), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(256)', 'null': '(True)', 'blank': '(True)'}), '(max_length=256, null=True, blank=True)\n', (3124, 3163), False, 'from django.db import models\n'), ((3182, 3237), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(256)', 'null': '(True)', 'blank': '(True)'}), '(max_length=256, null=True, blank=True)\n', (3198, 3237), False, 'from django.db import models\n'), ((3258, 3313), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(256)', 'null': '(True)', 'blank': '(True)'}), '(max_length=256, null=True, blank=True)\n', (3274, 3313), False, 'from django.db import models\n'), ((3333, 3388), 'django.db.models.CharField', 'models.CharField', ([], {'max_length': '(256)', 'null': '(True)', 'blank': '(True)'}), '(max_length=256, null=True, blank=True)\n', (3349, 3388), False, 'from django.db import models\n'), ((3406, 3445), 'django.db.models.TextField', 'models.TextField', ([], {'null': '(True)', 'blank': '(True)'}), '(null=True, blank=True)\n', (3422, 3445), False, 'from django.db import models\n'), ((3471, 3517), 'django.db.models.BooleanField', 'models.BooleanField', ([], {'blank': '(True)', 'default': '(False)'}), '(blank=True, default=False)\n', (3490, 3517), False, 'from django.db import models\n'), ((4707, 4730), 'django.db.models.Count', 'models.Count', (['"""ratings"""'], {}), "('ratings')\n", (4719, 4730), False, 'from django.db import models\n')]