text: # -*- encoding: utf-8 -*-
  
  import os
  
  from lxml import etree
  
  from apps.extractor.base import BaseExtractor
  from apps.extractor.perfectextractor import PerfectExtractor
  from apps.extractor.utils import XML
  
  from .base import BaseBNC
  
  
  class BNCExtractor(BaseBNC, BaseExtractor):
      def process_file(self, filename):
          results = []
  
          # Retrieve the genre
          tree = etree.parse(filename)
          genre = self.get_genre(tree)
  
          # Parse the current tree (create a iterator over 's' elements)
          s_trees = etree.iterparse(filename, tag='s')
  
          # Find potential present perfects
          for _, s in s_trees:
              if self.sentence_ids and s.get('n') not in self.sentence_ids:
                  continue
  
              result = list()
              result.append(os.path.basename(filename))
              result.append(s.get('n'))
              result.append(genre)
              result.append('')
              result.append('')
              if self.output == XML:
                  result.append('<root>' + etree.tostring(s) + '</root>')
              else:
                  result.append(self.get_sentence_words(s))
  
              results.append(result)
          return results
  
      def get_sentence(self, element):
          return element.xpath('ancestor::s')[0]
  
      def get_siblings(self, element, sentence_id, check_preceding):
          return element.itersiblings(tag='w', preceding=check_preceding)
  
      def get_sentence_words(self, sentence):
          """
          Returns all words in the sentence.
          Note that in the BNC, these can be either in w or c tags (the latter are for punctuation)
          :param sentence: the s element
          :return: all w and c texts, joined with a space.
          """
          s = []
          for w in sentence.xpath('.//w | .//c'):
              s.append(w.text.strip() if w.text else ' ')
          return ' '.join(s)
  
      def sort_by_alignment_certainty(self, file_names):
          raise NotImplementedError
  
      def filter_by_file_size(self, file_names):
          raise NotImplementedError
  
      def get_translated_lines(self, alignment_trees, language_from, language_to, segment_number):
          raise NotImplementedError
  
  
  class BNCPerfectExtractor(BNCExtractor, PerfectExtractor):
      def get_line_and_pp(self, tree, language_to, segment_number):
          raise NotImplementedError
  
      def generate_header(self):
          header = [
              'document',
              'genre',
              'is-perfect',
              'tense',
              'words',
              'lemma',
              'is-question',
              'text']
          return header
  
      def process_file(self, filename):
          """
          Processes a single file.
          """
          results = []
  
          # Retrieve the genre
          tree = etree.parse(filename)
          genre = self.get_genre(tree)
  
          # if not genre.startswith('S'):  # Only spoken genre for the moment
          #    return results
  
          # Parse the current tree (create a iterator over 's' elements)
          s_trees = etree.iterparse(filename, tag='s')
  
          # Find potential present perfects
          for _, s in s_trees:
              sentence = self.get_sentence_words(s)
              is_question = self.is_question(sentence)
  
              for e in s.xpath(self.config.get(self.l_from, 'xpath')):
                  pp = self.check_present_perfect(e, self.l_from)
  
                  # If this is really a present perfect, add it to the result
                  if pp:
                      result = list()
                      result.append(os.path.basename(filename))
                      result.append(genre)
                      result.append('1')
                      result.append(pp.perfect_type())
                      result.append(pp.verbs_to_string())
                      result.append(pp.perfect_lemma())
                      result.append('1' if is_question else '0')
                      result.append(sentence)
                      results.append(result)
  
                      # If we want (only) one classification per sentence, break the for loop here.
                      if self.one_per_sentence:
                          break
              else:
                  # If we want one classification per sentence, add the sentence with a classification here.
                  if self.one_per_sentence:
                      tense, tenses = self.get_tenses(s)
  
                      result = list()
                      result.append(os.path.basename(filename))
                      result.append(genre)
                      result.append('0')
                      result.append(tense)
                      result.append(','.join(tenses))
                      result.append('')
                      result.append('1' if is_question else '0')
                      result.append(sentence)
                      results.append(result)
  
          return results
  
      def is_question(self, sentence):
          """
          Naively checks if a sentence is a question.
          :param sentence: a string of words separated by spaces
          :return: whether this sentence contains a question mark
          """
          return '?' in sentence
  
      def get_pos(self, language, element):
          """
          POS-tags in the BNC can potentially consist of two part-of-speech tags,
          but the first tag is the most likely choice.
          See http://www.natcorp.ox.ac.uk/docs/URG/posguide.html#ambiguity
          :param language: the current language
          :param element: the current w element
          :return: the (most likely) part-of-speech tag
          """
          pos = element.get(self.config.get(language, 'pos'))
          return pos.split('-')[0]
  