#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2008-2011 Zuza Software Foundation
#
# This file is part of Virtaal.
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, print_function, unicode_literals

from six import text_type
from translate.search import match

from .basetmmodel import BaseTMModel


class TMModel(BaseTMModel):
    """Translation memory model that matches against translated strings from current file"""

    __gtype_name__ = 'CurrentFileTMModel'
    display_name = _('Current File')
    description = _('Translated units from the currently open file')

    default_config = { 'max_length': 1000 }

    # INITIALIZERS #
    def __init__(self, internal_name, controller):
        super(TMModel, self).__init__(controller)

        self.matcher = None
        self.internal_name = internal_name
        self.load_config()

        self._connect_ids.append((
            self.controller.main_controller.store_controller.connect('store-loaded', self.recreate_matcher),
            self.controller.main_controller.store_controller
        ))
        if self.controller.main_controller.store_controller.get_store() is not None:
            self.recreate_matcher(self.controller.main_controller.store_controller)

        self._connect_ids.append((
            self.controller.main_controller.store_controller.unit_controller.connect('unit-done', self._on_unit_modified),
            self.controller.main_controller.store_controller.unit_controller
        ))


    # METHODS #
    def recreate_matcher(self, storecontroller):
        store = storecontroller.get_store()._trans_store
        if self.matcher is None:
            options = {
                'max_length': int(self.config['max_length']),
                'max_candidates': self.controller.max_matches,
                'min_similarity': self.controller.min_quality
            }
            self.matcher = match.matcher(store, **options)
        else:
            self.matcher.extendtm(store.units)
        self.cache = {}

    def query(self, tmcontroller, unit):
        query_str = unit.source
        matches = []
        # The cache is cleared when translated units change, so this is safe
        if query_str in self.cache:
            matches = self.cache[query_str]
        else:
            matches = self._check_other_units(unit)
            # Cache even empty results, so we don't need to query again
            self.cache[query_str] = matches
            # We don't want to cache alt trans, since this is different for
            # units with the same source text.

        matches += self._check_alttrans(unit)
        if matches:
            self.emit('match-found', query_str, matches)

    def _check_other_units(self, unit):
        matches = []

        query_str = unit.source
        if not isinstance(query_str, text_type):
            query_str = query_str.decode('utf-8')

        for candidate in self.matcher.matches(query_str):
            m = match.unit2dict(candidate)
            #l10n: Try to keep this as short as possible.
            m['tmsource'] = _('This file')
            matches.append(m)
        return [m for m in matches if m['quality'] != u'100']

    def _check_alttrans(self, unit):
        if not hasattr(unit, 'getalttrans'):
            return []
        alttrans = unit.getalttrans()
        if not alttrans:
            return []

        from translate.search.lshtein import LevenshteinComparer
        lcomparer = LevenshteinComparer(max_len=1000)

        results = []
        for alt in alttrans:
            quality = lcomparer.similarity(unit.source, alt.source, self.controller.min_quality - 15)
            # let's check if it is useful, but be more lenient
            if quality < self.controller.min_quality - 10:
                continue
            tmsource = _('This file')

            xmlelement = getattr(alt, 'xmlelement', None)
            if xmlelement is not None:
                origin = alt.xmlelement.get('origin', '')
                if origin:
                    if origin == "lmc":
                        # Experimental code to test lmc research. Everything
                        # in a try block, just in case.
                        try:
                            from lxml import etree
                            import os.path
                            extras = xmlelement.xpath('processing-instruction()')
                            meta = dict((pi.target, pi.text) for pi in extras)
                            tmsource = [meta.get("contact-name", ""), meta.get("category", ""), os.path.splitext(meta.get("original", ""))[0]]
                            tmsource = u"\n".join(filter(None, tmsource))
                        except Exception as e:
                            import logging
                            logging.info(e)

                    tmsource += "\n" + origin

            results.append({
                'source': alt.source,
                'target': alt.target,
                'quality': quality,
                'tmsource': tmsource,
            })
        return results


    # EVENT HANDLERS #
    def _on_unit_modified(self, widget, new_unit, modified):
        """Add the new translation unit to the TM."""
        if modified and new_unit.istranslated():
            self.matcher.extendtm(new_unit)
            # This new target text might be relevant for other units that are
            # already cached, so let's remove ones with source text of similar
            # length
            min_quality = self.controller.min_quality
            start = self.matcher.getstartlength(min_quality, new_unit.source)
            stop = self.matcher.getstoplength(min_quality, new_unit.source)
            def unaffected(key):
                l = len(key)
                return l < start or l > stop

            self.cache = dict((k,v) for (k,v) in self.cache.iteritems() if unaffected(k))
