from django.db import models
from tx_people import fields
from tx_people.models import Membership, Organization, Post

from . import managers
from . import mixins


def get_top_level_departments():
    """
    Utility function for getting top-level organizations

    This is a helper for querying the tx_people.Organization model.  It
    simply looks for all top-level organizations that have at least one
    employee associated with one of their children.  Once the queryset
    is retrieved, you can continue filtering, ordering, and so as you
    please.

    Note: This only works for the current situation of non-nested
    departments.
    """
    return (Organization.objects.select_related('stats')
            .filter(parent=None)
            .exclude(children__members__employee=None))


def get_top_level_departments_with_stats():
    """
    Get top-level organizations with annotated stats

    This is a convenience function that adds stats to the returned
    ``get_top_level_departments`` QuerySet.
    """
    number_of_employees = models.Count('children__members__employee')
    return (get_top_level_departments()
            .annotate(number_of_employees=number_of_employees))


class CompensationType(models.Model):
    name = models.CharField(max_length=250)
    description = models.TextField()
    # TODO
    # calculator = models.CharField(choices=constants.AVAILABLE_CALCULATORS)

    def __unicode__(self):
        return self.name


class Employee(mixins.DenormalizeOnSaveMixin, mixins.TimeTrackingMixin,
        mixins.ReducedDateStartAndEndMixin, models.Model):
    """
    # TODO

    This uses the tx_people.Membership model to represent the
    relationship between a Person and an Organization.  The Membership
    contains all title information and those Membership instances can
    be a part of a particular Post.

    For example, consider Alice President.  She is the President of the
    University of Texas at Sometown, has an annual salary of $100k, and
    was hired in December of 2034.  The following models must be
    created or used to represent that:

    ``Person``
        Alice President
    ``Organization``
        University of Sometown
    ``Post``
        For President connected to the ``Organization``
    ``Membership``
        Connecting the ``Person``, ``Organizations`` and the ``Post``
    ``CompensationType``
        Full-Time Employee
    ``Employee``
        Connects to ``Membership``, has a ``start_date`` of ``2034-12``,
        a ``compensation`` of ``100000`` and connected to the
        appropriate ``CompensationType``.
    """
    position = models.ForeignKey(Membership)
    hire_date = fields.ReducedDateField()
    compensation = models.DecimalField(decimal_places=4, max_digits=12)
    compensation_type = models.ForeignKey(CompensationType)

    def __unicode__(self):
        return u'{title}, {person}'.format(title=self.position.post,
                person=self.position.person)


def create_highest_lowest_mixin(prefix):
    def generate_kwargs(field):
        return {
            'related_name': '{0}_stats_{1}'.format(prefix, field),
            'null': True,
            'blank': True,
        }

    class HighestLowestMixin(models.Model):
        highest_paid = models.ForeignKey('Employee', **generate_kwargs('highest'))
        lowest_paid = models.ForeignKey('Employee', **generate_kwargs('lowest'))

        class Meta:
            abstract = True

    return HighestLowestMixin


class PositionStats(create_highest_lowest_mixin('position'), models.Model):
    position = models.ForeignKey(Post, related_name='stats')

    objects = managers.PositionStatsManager()


class OrganizationStats(create_highest_lowest_mixin('organization'),
        models.Model):
    organization = models.ForeignKey(Organization, related_name='stats')

    objects = managers.OrganizationStatsManager()

@@ -2970,38 +2970,29 @@
 %0Adef create_
-highest_lowest
+stats
 _mixin(prefi
@@ -3185,29 +3185,26 @@
   class 
-HighestLowest
+Statistics
 Mixin(mo
@@ -3445,21 +3445,18 @@
 urn 
-HighestLowest
+Statistics
 Mixi
@@ -3482,38 +3482,29 @@
 tats(create_
-highest_lowest
+stats
 _mixin('posi
@@ -3671,22 +3671,13 @@
 ate_
-highest_lowest
+stats
 _mix

Rename to more general purpose name