# -*- coding: UTF-8 -*-
# models.py
#
# Copyright (C) 2013 Cleany
#
# Author(s): Cédric Gaspoz <cga@cleany.ch>
#
# This file is part of Cleany.
#
# Cleany is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Cleany is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Cleany.  If not, see <http://www.gnu.org/licenses/>.

# Stdlib imports

# Core Django imports
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.text import get_text_list

# Third-party app imports
from django_extensions.db.models import TimeStampedModel
from geoposition.fields import GeopositionField

# Cleany imports
from core.models import RenameFilesModel
from customers.models import Organization, ManagersGroup
from maps.models import Map
from issues.models import IssueGroup


class Location(TimeStampedModel):
    """
    A geographical location where a facility is located. The location is a hierarchy of locations (self) and can be
    indefinitely extended to add intermediate levels.
    """
    name = models.CharField(_("name"), max_length=100, help_text=_("The name of the geographical location."))
    short_name = models.CharField(_("short name"), max_length=20, blank=True, help_text=_("The short name of the location. This name is used in reports and in the back-office. If the field is null, the name is truncated to 20 characters."))
    identification = models.CharField(_("identification"), max_length=100, blank=True, help_text=_("The identification of the geographical location. This can be used to add intern identification code to the location. This field could be null."))
    description = models.TextField(_("description"), blank=True, help_text=_("The description of the geographical location. The description is public."))
    notes = models.TextField(_("notes"), blank=True, help_text=_("Private notes related to the geographical location. This field could be null."))
    map_background = models.ForeignKey(Map, verbose_name=_('map'), related_name=_('locations'), null=True, blank=True, help_text=_("The map used to display this location. This field could be null."))
    map_shape = models.CharField(_("map shape"), max_length=30, blank=True, help_text=_("The name of a shape representing the area of the geographical location on a map."))
    geo_position = GeopositionField(_("geographical position"), blank=True, null=True, help_text=_("The geographical position of the location. This field could be null."))
    country_code = models.CharField(_("country code"), max_length=3, blank=True, help_text=_("The country code (ISO 3166-1 Alpha 2) if the location is a country. This field could be null is the origin is not a country."))
    parent = models.ForeignKey('self', verbose_name=_('parent'), null=True, blank=True, default=None, help_text=_("The parent origin (town, region, country, continent). This field could be null."))
    organization = models.ForeignKey(Organization, verbose_name=_('organization'), related_name=_('locations'), help_text=_("The organization managing this location."))
    managers = models.ForeignKey(ManagersGroup, verbose_name=_('location manager(s)'), related_name=_('locations'), null=True, blank=True, help_text=_("The location managers' group. This field could be null."))
    ordering = models.IntegerField(_("ordering"), max_length=10, default=0, help_text=_("The ordering of the locations. It is used to have an alternative to the alphabetical order."))

    class Meta:
        verbose_name = _('location')
        verbose_name_plural = _('locations')
        ordering = ['name']

    def __unicode__(self):
        return self.name


class Site(RenameFilesModel, TimeStampedModel):
    """
    A regrouping of multiple facilities. This is used to add an intermediate hierarchical level between locations and
    facilities.
    """
    name = models.CharField(_("name"), max_length=100, help_text=_("The name of the site."))
    short_name = models.CharField(_("short name"), max_length=20, blank=True, help_text=_("The short name of the site. This name is used in reports and in the back-office. If the field is null, the name is truncated to 20 characters."))
    description = models.TextField(_("description"), blank=True, help_text=_("The description of the site. The description is public."))
    notes = models.TextField(_("notes"), blank=True, help_text=_("Private notes related to the site. This field could be null."))
    map_background = models.ForeignKey(Map, verbose_name=_('map'), related_name=_('sites'), null=True, blank=True, help_text=_("The map used to display this site. This field could be null."))
    map_shape = models.CharField(_("map shape"), max_length=30, blank=True, help_text=_("The name of a shape representing the area of the site on a map."))
    geo_position = GeopositionField(_("geographical position"), blank=True, null=True, help_text=_("The geographical position of the site. This field could be null."))
    location = models.ForeignKey('Location', verbose_name=_('location'), related_name=_('sites'), help_text=_("The location of the site."))
    managers = models.ForeignKey(ManagersGroup, verbose_name=_('site manager(s)'), related_name=_('sites'), null=True, blank=True, help_text=_("The site managers' group. If no group is specified, the location's managers group will be used. This field could be null."))
    ordering = models.IntegerField(_("ordering"), max_length=10, default=0, help_text=_("The ordering of the sites. It is used to have an alternative to the alphabetical order."))
    logo_file = models.ImageField(_("site's logo"), upload_to='tmp', blank=True, null=True, help_text="A logo that will be displayed on all screens related to this site. If no logo is uploaded, the organization's logo will be used.")

    RENAME_FILES = {
        'logo_file': {'dest': 'logos', 'suffix': '_site', 'keep_ext': True},
    }

    class Meta:
        verbose_name = _('site')
        verbose_name_plural = _('sites')
        ordering = ['name']

    def __unicode__(self):
        return self.name

    def _get_organization(self):
        return self.location.organization
    organization = property(_get_organization, doc="The organization managing this site.")


class Facility(RenameFilesModel, TimeStampedModel):
    """
    A facility (a building) with levels and locals.
    """
    name = models.CharField(_("name"), max_length=100, help_text=_("The name of the facility."))
    short_name = models.CharField(_("short name"), max_length=20, blank=True, help_text=_("The short name of the facility. This name is used in reports and in the back-office. If the field is null, the name is truncated to 20 characters."))
    description = models.TextField(_("description"), blank=True, help_text=_("The description of the facility. The description is public."))
    notes = models.TextField(_("notes"), blank=True, help_text=_("Private notes related to the facility. This field could be null."))
    map_background = models.ForeignKey(Map, verbose_name=_('map'), related_name=_('facilities'), null=True, blank=True, help_text=_("The map used to display this facility. This field could be null."))
    map_shape = models.CharField(_("map shape"), max_length=30, blank=True, help_text=_("The name of a shape representing this facility on a map."))
    geo_position = GeopositionField(_("geographical position"), blank=True, null=True, help_text=_("The geographical position of the facility. This field could be null."))
    site = models.ForeignKey('Site', verbose_name=_('site'), related_name=_('facilities'), help_text=_("The site of the facility."))
    managers = models.ForeignKey(ManagersGroup, verbose_name=_('facility manager(s)'), related_name=_('facilities'), null=True, blank=True, help_text=_("The facility managers' group. If no group is specified, the site's managers group will be used. This field could be null."))
    ordering = models.IntegerField(_("ordering"), max_length=10, default=0, help_text=_("The ordering of the sites. It is used to have an alternative to the alphabetical order."))
    logo_file = models.ImageField(_("facility's logo"), upload_to='tmp', blank=True, null=True, help_text="A logo that will be displayed on all screens related to this facility. If no logo is uploaded, the site's logo will be used.")

    RENAME_FILES = {
        'logo_file': {'dest': 'logos', 'suffix': '_facility', 'keep_ext': True},
    }

    class Meta:
        verbose_name = _('facility')
        verbose_name_plural = _('facilities')
        ordering = ['name']

    def __unicode__(self):
        return self.name

    def _get_organization(self):
        return self.site.location.organization
    organization = property(_get_organization, doc="The organization managing this facility.")


class Level(TimeStampedModel):
    """
    The level of a facility. A level comprises multiple locals.
    """
    name = models.CharField(_("name"), max_length=100, help_text=_("The name of the level."))
    short_name = models.CharField(_("short name"), max_length=20, blank=True, help_text=_("The short name of the level. This name is used in reports and in the back-office. If the field is null, the name is truncated to 20 characters."))
    level = models.IntegerField(_("level"), max_length=5, default=0, help_text=_("The numerical level."))
    description = models.TextField(_("description"), blank=True, help_text=_("The description of the level. The description is public."))
    notes = models.TextField(_("notes"), blank=True, help_text=_("Private notes related to the level. This field could be null."))
    map_background = models.ForeignKey(Map, verbose_name=_('map'), related_name=_('levels'), null=True, blank=True, help_text=_("The map used to display this level. This field could be null."))
    map_shape = models.CharField(_("map shape"), max_length=30, blank=True, help_text=_("The name of a shape representing this level on a map."))
    facility = models.ForeignKey('Facility', verbose_name=_('facility'), related_name=_('levels'), help_text=_("The facility of the level."))
    managers = models.ForeignKey(ManagersGroup, verbose_name=_('level manager(s)'), related_name=_('levels'), null=True, blank=True, help_text=_("The level managers' group. If no group is specified, the facility's managers group will be used. This field could be null."))

    class Meta:
        verbose_name = _('level')
        verbose_name_plural = _('levels')
        ordering = ['level']

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

    def _get_organization(self):
        return self.facility.site.location.organization
    organization = property(_get_organization, doc="The organization managing this level.")


class Space(TimeStampedModel):
    """
    A monitored space on the level of a facility.
    """
    name = models.CharField(_("name"), max_length=100, help_text=_("The name of the space."))
    short_name = models.CharField(_("short name"), max_length=20, blank=True, help_text=_("The short name of the space. This name is used in reports and in the back-office. If the field is null, the name is truncated to 20 characters."))
    space_number = models.CharField(_("space number"), max_length=10, blank=True, help_text=_("The space number (alphanumerical)."))
    description = models.TextField(_("description"), blank=True, help_text=_("The description of the space. The description is public."))
    notes = models.TextField(_("notes"), blank=True, help_text=_("Private notes related to the space. This field could be null."))
    map_shape = models.CharField(_("map shape"), max_length=30, blank=True, help_text=_("The name of a shape representing this space on a map."))
    level = models.ForeignKey('Level', verbose_name=_('level'), related_name=_('locals'), help_text=_("The level of the space."))
    managers = models.ForeignKey(ManagersGroup, verbose_name=_('space manager(s)'), related_name=_('spaces'), null=True, blank=True, help_text=_("The space managers' group. If no group is specified, the level's managers group will be used. This field could be null."))
    issues_groups = models.ManyToManyField(IssueGroup, verbose_name=_('issues'), related_name=_('spaces'), help_text=_("The issues that could be notified."))

    class Meta:
        verbose_name = _('space')
        verbose_name_plural = _('spaces')
        ordering = ['space_number', 'name']

    def __unicode__(self):
        if self.space_number:
            return "%s. %s" % (self.space_number, self.name)
        else:
            return self.name

    def _get_organization(self):
        return self.level.facility.site.location.organization
    organization = property(_get_organization, doc="The organization managing this space.")