text: # -*- coding: utf-8 -*-
  """Report for the Czech Government Council for Drug Policy Coordination."""
  from copy import deepcopy
  
  from datetime import datetime, date, time
  from django.db.models import Count
  from django.db.models import Sum
  from django.template import loader
  from django.template.context import RequestContext
  from django.utils.translation import ugettext as _
  
  from boris.classification import (DRUGS, RISKY_BEHAVIOR_PERIODICITY, RISKY_BEHAVIOR_KIND)
  from boris.clients.models import Client, Anamnesis, RiskyManners, Town
  from boris.dashboard import MONTHS_SHORT
  from boris.impact.core import BaseImpact
  from boris.reporting.reports.council import GovCouncilReport
  from boris.services.models import (Encounter, HarmReduction, IncomeExamination, Service)
  
  _CONTENT_TYPES = {}
  
  
  class ImpactReport(BaseImpact, GovCouncilReport):
      title = u'Impakt'
      description = u'Podklady pro dopadovou zprávu pro koordinaci protidrogové politiky.'
  
      all_towns = Town.objects.all()
      first_contact = None
  
      def __init__(self, date_from=None, date_to=None, towns=None):
          if Encounter.objects.count():
              self.first_contact = Encounter.objects.order_by('performed_on')[0]
  
          if date_from is None:
              date_from = self.first_contact.performed_on if self.first_contact is not None else None
          if date_to:
              date_to = datetime.today()
          if towns is None or len(towns) == 0:
              towns = self.all_towns
  
          self.datetime_from = datetime.combine(date_from, time(0))
          self.datetime_to = datetime.combine(date_to, time(23, 59, 59))
          self.towns = towns
          self.clients_in_location = self._get_all_drug_users().count()
          self.potential_clients = 6 * self.clients_in_location
          self.town_population = 10000
  
          GovCouncilReport.__init__(self, self.datetime_from, self.datetime_to, 1, self.towns)
  
          self.encounters = []
          self.persons = []
          self.syringe = []
          self.months = deepcopy(MONTHS_SHORT)
  
          year = datetime.today().year - 1
          month = datetime.today().month
  
          for i in range(12):
              month += 1
              if month == 13:
                  month = 1
                  year += 1
  
              enc_count = Encounter.objects.filter(performed_on__month=month, performed_on__year=year).count()
              person_count = Client.objects.filter(created__month=month, created__year=year).count()
  
              syringe_count = HarmReduction.objects.filter(encounter__performed_on__month=month,
                                                           encounter__performed_on__year=year).aggregate(
                                                              Sum('out_count')).get('out_count__sum', 0) or 0
  
              self.encounters.append(enc_count)
              self.persons.append(person_count)
              self.syringe.append(syringe_count)
  
          self.months = self.months[month:] + self.months[:month]
  
  
  class ImpactTimeseries(ImpactReport):
      title = _(u'Časové řady')
      description = _(u'Časové řady')
  
      def render(self, request, display_type):
          return loader.render_to_string(
              self.get_template(display_type),
              {
                  'date_from': self.datetime_from,
                  'date_to': self.datetime_to,
                  'towns': [t.title for t in self.towns],
                  'encounters': self.encounters,
                  'persons': self.persons,
                  'syringe': self.syringe,
                  'months': self.months,
                  'first_contact': self.first_contact.performed_on.year,
                  'clients_in_location': self.clients_in_location, 
                  'potential_clients': self.potential_clients,
                  'town_population': self.town_population - (7 * self.clients_in_location),
              },
              context_instance=RequestContext(request)
          )
  
  
  class ImpactClient(ImpactReport):
      title = _(u'Klienti')
      description = _(u'Statistická analýza klientů')
  
      def get_drug_occurrence(self):
          drug = lambda *drugs: self._get_primary_drug_users(*drugs).count()
          counts_by_category = {
              'heroin': drug(DRUGS.HEROIN),
              'buprenorfin': drug(DRUGS.SUBUTEX_LEGAL, DRUGS.SUBUTEX_ILLEGAL, DRUGS.SUBOXONE),
              'metadon': drug(DRUGS.METHADONE),
              'opiáty': drug(DRUGS.VENDAL, DRUGS.RAW_OPIUM, DRUGS.BRAUN, DRUGS.FENTANYL),
              'pervitin': drug(DRUGS.METHAMPHETAMINE),
              'kokain/crack': drug(DRUGS.COCAINE),
              'kanabinoidy': drug(DRUGS.THC),
              'extáze': drug(DRUGS.ECSTASY),
              'halucinogeny': drug(DRUGS.LSD, DRUGS.PSYLOCIBE),
              'těkavé látky': drug(DRUGS.INHALER_DRUGS)
          }
          return { 'labels': counts_by_category.keys(), 'values': counts_by_category.values()}
  
      def get_enc_distribution(self):
          bin_bounds = [0, 1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 200, 300, 400]
          bin_number = len(bin_bounds)
          counts = [0] * bin_number
          bin_labels = [''] * bin_number
          client_encs = Client.objects.annotate(encounter_count=Count('encounters')).order_by('encounter_count')
          anonymous_ids = self._get_anonymous_ids()
          anonymous_encs = Encounter.objects.filter(person__in=anonymous_ids).count()
          for i in xrange(bin_number-1):
              if bin_bounds[i+1] - bin_bounds[i] == 1:
                  bin_labels[i+1] = str(bin_bounds[i+1]) 
              else:
                  bin_labels[i+1] = str(bin_bounds[i]+1) + '-' + str(bin_bounds[i+1])
      
              for client_enc in client_encs:
                  if bin_bounds[i] < client_enc.encounter_count <= bin_bounds[i+1]:
                      counts[i] += 1
          
          return {'bounds': bin_bounds[1:bin_number], 'labels': bin_labels[1:bin_number], 'counts': counts[0:bin_number-1], 'anonymous': anonymous_encs}
  
      def render(self, request, display_type):
          return loader.render_to_string(
              self.get_template(display_type),
              {
                  'date_from': self.datetime_from,
                  'date_to': self.datetime_to,
                  'towns': [t.title for t in self.towns],
                  'encounters': self.encounters,
                  'persons': self.persons,
                  'syringe': self.syringe,
                  'months': self.months,
                  'first_contact': self.first_contact.performed_on.year,
                  'clients_in_location': self.clients_in_location, 
                  'potential_clients': self.potential_clients,
                  'town_population': self.town_population-(7*self.clients_in_location),
                  'drug_type_occurrence': self.get_drug_occurrence(),
                  'enc_dist': self.get_enc_distribution(),
              },
              context_instance=RequestContext(request)
          )
  
  
  class ImpactAnamnesis(ImpactReport):
      title = u'Anamnézy'
      description = (u'Statistický výtah z anamnéz')
  
      def anamnesis_dictionary(self, x):
          p = RISKY_BEHAVIOR_PERIODICITY
          return {
              p.NEVER: 'never',
              p.ONCE: 'once',
              p.OFTEN: 'often',
              p.UNKNOWN: 'unknown'               
          }.get(x, 'not found')
  
      def get_anamnesis_list(self):
          """
          Returns all anamnesis to report in the resulting output.
  
          Filters clients using following rules::
              * Client must have Anamnesis filled up
              * First recorded encounter with the client in the given year (and possibly towns)
                must be witin quarter limited by date range.
          """
          # tmp store periodicity
  
          p = RISKY_BEHAVIOR_PERIODICITY
          # Get QuerySet of first encounters in the given year/town for all clients.
          encounters = Encounter.objects.first(year = 2015, towns=self.towns)
  
          # Filter encounters so that only the specified date range is present.
          encounters = encounters.filter(performed_on__gte=self.datetime_from,
                                         performed_on__lt=self.datetime_to)
  
          # Get all clients whose first encounters fall into the specified range.
          clients = encounters.values('person')
  
          # Now get all the encounters for these clients that fulfill the specified criteria.
          encounters = Encounter.objects.filter(performed_on__gte=self.datetime_from,
                                                performed_on__lt=self.datetime_to,
                                                where__in=self.towns,
                                                person__in=clients)
  
          # Get client PKs from filtered encounters.
          encounter_data = {}
  
          for e in encounters:
              encounter_data.setdefault(e.person_id, {'first_encounter_date': date.max, 'objects': []})
              encounter_data[e.person_id]['first_encounter_date'] = min(encounter_data[e.person_id]['first_encounter_date'], e.performed_on)
              encounter_data[e.person_id]['objects'].append(e)
  
          # Finally, select these clients if they have anamnesis filled up.
          _a = Anamnesis.objects.filter(client__pk__in=encounter_data.keys()).select_related()
          _all = []
  
          # Annotate extra information needed in report.
          for a in _a:
              # Date of first encounter with client.
              a.extra_first_encounter_date = encounter_data[a.client_id]['first_encounter_date']
              # If has been cured before - True if there is not IncomeExamination
              # within selected encounters.
              a.extra_been_cured_before = not Service.objects.filter(encounter__in=encounter_data[a.client_id]['objects'],
                                                                     content_type=IncomeExamination.real_content_type()).exists()
              # When showing 'incidency', only those, who have not been cured before
              # should be returned.
              # if self.kind == 'incidence' and a.extra_been_cured_before is True:
              if a.extra_been_cured_before is True:
                  continue
  
              # Information about risky behaviour and it's periodicity.
              try:
                  ivrm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.INTRAVENOUS_APPLICATION)
  
                  a.iv_past = self.anamnesis_dictionary(ivrm.periodicity_in_past)
                  a.iv_present = self.anamnesis_dictionary(ivrm.periodicity_in_present)
  
                  if (ivrm.periodicity_in_present, ivrm.periodicity_in_past) == (p.NEVER, p.NEVER):
                      a.extra_intravenous_application = 'c'
                  elif ivrm.periodicity_in_present in (p.ONCE, p.OFTEN):
                      a.extra_intravenous_application = 'b'
                  elif ivrm.periodicity_in_present == p.NEVER and ivrm.periodicity_in_past in (p.ONCE, p.OFTEN):
                      a.extra_intravenous_application = 'a'
                  else:
                      a.extra_intravenous_application = 'd'
              except RiskyManners.DoesNotExist:
                  a.extra_intravenous_application = 'd'
                  a.iv_past = 'unknown'
                  a.iv_present = 'unknown'
  
              # Information about syringe sharing activity.
              if a.extra_intravenous_application not in ('c',):
                  try:
                      ssrm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.SYRINGE_SHARING)
  
                      # Use current periodicity in past/current according to
                      # `extra_intravenous_application`
                      a.ss_past = self.anamnesis_dictionary(ivrm.periodicity_in_past)
                      a.ss_present = self.anamnesis_dictionary(ivrm.periodicity_in_present)
  
                      per = (ssrm.periodicity_in_present
                             if a.extra_intravenous_application == 'b'
                             else ssrm.periodicity_in_past)
  
                      if per in (p.ONCE, p.OFTEN):
                          a.extra_syringe_sharing = 'yes'
                      elif per == p.NEVER:
                          a.extra_syringe_sharing = 'no'
                      else:
                          a.extra_syringe_sharing = 'unknown'
                  except RiskyManners.DoesNotExist:
                      a.extra_syringe_sharing = 'unknown'
                      a.ss_past = 'unknown'
                      a.ss_present = 'unknown'
  
              try:
                  usrm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.SEX_WITHOUT_PROTECTION)
                  a.us_past = self.anamnesis_dictionary(usrm.periodicity_in_past)
                  a.us_present = self.anamnesis_dictionary(usrm.periodicity_in_present)
              except RiskyManners.DoesNotExist:
                  a.us_past = 'unknown'
                  a.us_present = 'unknown'
   
              try:
                  rarm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.RISKY_APPLICATION)
                  a.ra_past = self.anamnesis_dictionary(rarm.periodicity_in_past)
                  a.ra_present = self.anamnesis_dictionary(rarm.periodicity_in_present)
              except RiskyManners.DoesNotExist:
                  a.ra_past = 'unknown'
                  a.ra_present = 'unknown'
  
              try:
                  odrm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.OVERDOSING)
                  a.od_past = self.anamnesis_dictionary(odrm.periodicity_in_past)
                  a.od_present = self.anamnesis_dictionary(odrm.periodicity_in_present)
              except RiskyManners.DoesNotExist:
                  a.od_past = 'unknown'
                  a.od_present = 'unknown'
  
              try:
                  hcrm = a.riskymanners_set.get(behavior=RISKY_BEHAVIOR_KIND.HEALTH_COMPLICATIONS)
                  a.hc_past = self.anamnesis_dictionary(hcrm.periodicity_in_past)
                  a.hc_present = self.anamnesis_dictionary(hcrm.periodicity_in_present)
              except RiskyManners.DoesNotExist:
                  a.hc_past = 'unknown'
                  a.hc_present = 'unknown'
  
              _all.append(a)
  
          return _all
  
      def get_anamnesis_improvements(self):
          anamnesis = self.get_anamnesis_list()
  
          periodicity_dict = {
              'not found': -2,
              'unknown': -1,
              'never': 0,
              'once': 1,
              'often': 2
          }
  
          manner_dict = {
              'iv': 'Nitrožílní aplikace',
              'ss': 'Sdílení jehel',
              'ra': 'Riziková aplikace',
              'us': 'Nechráněný sex',
              'od': 'Předávkování',
          }
  
          labels = []
          counts = []
  
          for manner in manner_dict: 
              label = ''
              improvement = 0
  
              manner_key_prefix = "%s" % manner 
              past_key = manner_key_prefix+'_past'
              present_key = manner_key_prefix+'_present'
              for a in anamnesis:
                  past = periodicity_dict[getattr(a,past_key)]
                  present = periodicity_dict[getattr(a,present_key)]              
                  if present > -1 and past > -1:
                      if past > present:
                          improvement += 1
                      elif past < present:
                          improvement -= 1
  
              labels.append(manner_dict[manner])
              counts.append(improvement)
  
          data_dummy = {
                  'labels': labels,
                  'counts': counts,
          }
               
          return data_dummy
   
      def render(self, request, display_type):
          return loader.render_to_string(
              self.get_template(display_type),
              {
                  'date_from': self.datetime_from,
                  'date_to': self.datetime_to,
                  'towns': [t.title for t in self.towns],
                  'encounters': self.encounters,
                  'persons': self.persons,
                  'syringe': self.syringe,
                  'months': self.months,
                  'first_contact': self.first_contact.performed_on.year,
                  'clients_in_location': self.clients_in_location, 
                  'anamnesis': self.get_anamnesis_list(),
                  'rm_improvements': self.get_anamnesis_improvements(),
              },
              context_instance=RequestContext(request)
          )
  