text: # -*- coding: utf-8 -*-
  """
      sanskrit_util.query
      ~~~~~~~~~~~~~~~~~~~~~~~
  
      A simple interface for querying Sanskrit linguistic data.
  
      :license: MIT and BSD
  """
  
  from collections import defaultdict
  import six
  from . import sounds
  from .generate import NominalGenerator
  from .schema import *
  
  
  class SimpleQuery(object):
  
      """A simple API for database access."""
  
      def __init__(self, ctx):
          self.ctx = ctx
          self.session = ctx.session
          self.nominal = NominalGenerator(ctx)
  
          # Store IDs of irregular stems
          irreg = self.session.query(StemIrregularity) \
                      .filter(StemIrregularity.fully_described == True)
  
          self.irregular_stems = set([x.id for x in irreg])
          self.session.remove()
  
      def _fetch_nominal_paradigm(self, stem_id, gender_id):
          """Fetch a nominal paradigm from the database."""
          enum_abbr = self.ctx.enum_abbr
  
          results = self.session.query(Nominal)\
                                .filter(Nominal.stem_id == stem_id)\
                                .filter(Nominal.gender_id == gender_id)
  
          returned = {}
          for nominal in results:
              case = enum_abbr['case'][nominal.case_id]
              number = enum_abbr['number'][nominal.number_id]
              returned[(case, number)] = nominal.name
  
          return returned
  
      def _nominal_stem(self, stem_name, stem_cls=None):
          """Fetch a nominal stem from the database."""
          stem_cls = stem_cls or Stem
          stem = self.session.query(stem_cls)\
                             .filter(stem_cls.name == stem_name)\
                             .first()
          return stem
  
      def _simplify(self, forms):
          """Simplify the given forms by applying consonant reduction."""
          for parse, name in six.iteritems(forms):
              forms[parse] = sounds.Term(name).simplify()
  
      def noun(self, stem_name, gender):
          """Query for nouns.
  
          :param stem_name: the stem name
          :param gender: the noun gender
          """
          stem = self._nominal_stem(stem_name, NominalStem)
          if stem is None:
              return {}
  
          if stem.id in self.irregular_stems:
              gender_id = self.ctx.enum_id['gender'][gender]
              returned = self._fetch_nominal_paradigm(stem.id, gender_id)
          elif stem:
              returned = self.nominal.paradigm(stem_name, gender)
  
          self._simplify(returned)
          return returned
  
      def pronoun(self, stem_name, gender):
          """Query for pronouns.
  
          :param stem_name: the stem name
          :param gender: the pronoun gender
          """
          stem = self._nominal_stem(stem_name, PronounStem)
          if stem is None:
              return {}
  
          gender_id = self.ctx.enum_id['gender'][gender]
          returned = self._fetch_nominal_paradigm(stem.id, gender_id)
  
          self._simplify(returned)
          return returned
  
      def verb(self, root_name, mode, voice, vclass=None, **kw):
          """Query for inflected verbs.
  
          :param root_name: the verb root
          :param mode: the verb mode
          :param voice: the verb voice
          :param vclass: the verb class to use. This can be used to
                         distinguish between homophonous roots, such as
                         'kR' ("do") and 'kR' ("praise").
          """
          enum_id = self.ctx.enum_id
          enum_abbr = self.ctx.enum_abbr
          session = self.session
  
          roots = session.query(Root).filter(Root.name == root_name)
          roots_id = [r.id for r in roots]
          mode_id = enum_id['mode'][mode]
          voice_id = enum_id['voice'][voice]
  
          returned = {}
          results = session.query(Verb)\
                           .filter(Verb.root_id.in_(roots_id))\
                           .filter(Verb.mode_id == mode_id)\
                           .filter(Verb.voice_id == voice_id)
          for verb in results:
              person = enum_abbr['person'][verb.person_id]
              number = enum_abbr['number'][verb.number_id]
              returned[(person, number)] = verb.name
  
          session.close()
          self._simplify(returned)
          return returned
  
      def verb_summary(self, root_name, vclass=None):
          """Query for a summary of a verb's behavior.
  
          The function returns the following information:
  
          - the root ID
          - the 3rd. sg. forms of all verbs produced from the plain root
          - the stems of all participles produced from the plain root
  
          :param root: the verb root
          :param vclass: the verb class to use. This can be used to
                         distinguish between homophonous roots, such as
                         'kR' ("do") and 'kR' ("praise").
          """
          verbs = defaultdict(list)
          participles = defaultdict(list)
  
          ctx = self.ctx
          session = self.session
  
          # abbr -> ID
          ei_person = ctx.enum_id['person']
          ei_number = ctx.enum_id['number']
  
          # ID -> abbr
          ea_mode = ctx.enum_abbr['mode']
          ea_voice = ctx.enum_abbr['voice']
  
          # Root
          root = session.query(Root).filter(Root.name == root_name).first()
          if root is None:
              return {}
          root_id = root.id
  
          # Verbs
          results = session.query(Verb).filter(Verb.root_id == root_id) \
                           .filter(Verb.person_id == ei_person['3']) \
                           .filter(Verb.number_id == ei_number['s'])\
  
          for r in results:
              mode = ea_mode[r.mode_id]
              voice = ea_voice[r.voice_id]
              verbs[(mode, voice)].append(r.name)
  
          # Participles
          results = session.query(ParticipleStem) \
                           .filter(ParticipleStem.root_id == root_id)
  
          for r in results:
              mode = ea_mode[r.mode_id]
              voice = ea_voice[r.voice_id]
              participles[(mode, voice)].append(r.name)
  
          session.close()
          return {
              'root_id': root_id,
              'verbs': verbs,
              'participles': participles,
          }
  