#!/usr/bin/env python
#-*- coding: UTF-8 -*-

__author__ = 'helljump'

from PyQt4 import QtGui
from PyQt4 import QtCore
import logging
import startup
import re
import pymorphy2
import sys
from os.path import dirname
from ui.tagger_ui import Ui_Dialog
import transaction
from utils import MyProgressDialog
from collections import defaultdict


log = logging.getLogger(__name__)


TAG = re.compile('(</?[^>]+>)', re.U | re.S | re.M)
WORD = re.compile('([^\w]+)', re.U | re.S | re.M)


class Tagger(object):

    def __init__(self):
        if hasattr(sys, "frozen"):
            root = dirname(sys.executable)
        else:
            root = r'build\exe.win32-2.7'
        root = unicode(root, encoding=sys.getfilesystemencoding())
        self.morph = pymorphy2.MorphAnalyzer(root + '/morph')
        self._tags = defaultdict(int)

    def infos(self, text):
        for chunk in re.split(TAG, text, re.U):
            if chunk and chunk[0] == '<':
                continue
            sp = re.split(WORD, chunk, re.U)
            for word in sp:
                if len(word) < 4:
                    continue
                inf = self.morph.parse(word.lower())
                if not inf:
                    continue
                yield inf

    def words(self, text):
        s = set()
        for inf in self.infos(text):
            grm = inf[0].tag.grammemes
            if 'NOUN' in grm and 'sing' in grm:
                f = inf[0].normal_form
                s.add(f)
        return s

    def generate(self, text):
        for inf in self.infos(text):
            grm = inf[0].tag.grammemes
            if 'NOUN' in grm and 'sing' in grm:
                f = inf[0].normal_form
                self._tags[f] += 1

    def tags(self, limit=100):
        d = self._tags
        return sorted(d, key=d.get, reverse=True)[:limit]


class Dialog(QtGui.QDialog, Ui_Dialog):
    def __init__(self, project, parent=None):
        super(Dialog, self).__init__(parent)
        self.setupUi(self)
        self.prj = project
        self.parent = parent
        tags = project.root()['tags']
        self.tags_te.setPlainText(', '.join(tags))
        if startup.CFG.contains('tagger/geometry'):
            self.restoreGeometry(startup.CFG.value('tagger/geometry').toByteArray())
        prefs = self.prj.root().get('prefs/tagger', [3])
        self.maximum_sb.setValue(prefs[0])

    def closeEvent(self, evt):
        log.debug('close event')
        tags = set([tag.strip() for tag in unicode(self.tags_te.toPlainText()).split(',') if tag.strip()])
        self.prj.root()['tags'] = tags
        self.prj.root()['prefs/tagger'] = [self.maximum_sb.value()]
        transaction.commit()
        startup.CFG.setValue('tagger/geometry', self.saveGeometry())
        evt.accept()

    @QtCore.pyqtSlot()
    def on_actionApply_triggered(self):
        log.debug('apply tags')
        docs = self.prj.root()['documents']
        pdlg = MyProgressDialog(u'Генератор меток', u'Поиск меток в документах', u'Отмена', 0, len(docs), parent=self)
        pdlg.show()
        tagger = Tagger()
        alltags = set([tag.strip() for tag in unicode(self.tags_te.toPlainText()).split(',') if tag.strip()])
        mtags = self.maximum_sb.value()
        for i, doc in enumerate(docs):
            doctags = tagger.words(doc.title) | tagger.words(doc.text)
            egg = list(doctags & alltags)
            doc.tags = set(egg[:mtags])
            pdlg.set_value(i)
            QtGui.qApp.processEvents()
            if pdlg.wasCanceled():
                transaction.abort()
                break
        transaction.commit()
        if self.parent is not None:
            self.parent.model.layoutChanged.emit()
        pdlg.close()

    @QtCore.pyqtSlot()
    def on_actionCreate_triggered(self):
        rc = QtGui.QMessageBox.question(self, u'Генерация меток', u'Текущие метки будут очищены. Продолжать?',
            QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        if rc == QtGui.QMessageBox.No:
            return
        docs = self.prj.root()['documents']
        pdlg = MyProgressDialog(u'Генератор меток', u'Обработка', u'Отмена', 0, len(docs), parent=self)
        pdlg.show()
        tagger = Tagger()
        for i, doc in enumerate(docs):
            tagger.generate(doc.title)
            tagger.generate(doc.text)
            pdlg.set_value(i)
            QtGui.qApp.processEvents()
            if pdlg.wasCanceled():
                break
        self.tags_te.setPlainText(', '.join(tagger.tags()))
        pdlg.close()


def process(prj, parent=None):
    dlg = Dialog(prj, parent)
    rc = dlg.exec_()

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    root = startup.CONN.root()
    prj = root["projects"][0]
    prj.open()
    process(prj)
    prj.close()
