# -*- coding: utf-8 -*-
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

import time, re
from anki.db import DB
from anki.importing.noteimp import NoteImporter, ForeignNote, ForeignCard
from anki.stdmodels import addBasicModel, addClozeModel
from anki.lang import ngettext

class MnemosyneImporter(NoteImporter):

    needMapper = False
    update = False
    allowHTML = True

    def run(self):
        db = DB(self.file)
        ver = db.scalar(
            "select value from global_variables where key='version'")
        assert ver.startswith('Mnemosyne SQL 1')
        # gather facts into temp objects
        curid = None
        notes = {}
        note = None
        for _id, id, k, v in db.execute("""
select _id, id, key, value from facts f, data_for_fact d where
f._id=d._fact_id"""):
            if id != curid:
                if note:
                    notes[note['_id']] = note
                note = {'_id': _id}
                curid = id
            note[k] = v
        if note:
            notes[note['_id']] = note
        # gather cards
        front = []
        frontback = []
        vocabulary = []
        cloze = {}
        for row in db.execute("""
select _fact_id, fact_view_id, tags, next_rep, last_rep, easiness,
acq_reps+ret_reps, lapses, card_type_id from cards"""):
            # categorize note
            note = notes[row[0]]
            if row[1].endswith(".1"):
                if row[1].startswith("1.") or row[1].startswith("1::"):
                    front.append(note)
                elif row[1].startswith("2.") or row[1].startswith("2::"):
                    frontback.append(note)
                elif row[1].startswith("3.") or row[1].startswith("3::"):
                    vocabulary.append(note)
                elif row[1].startswith("5.1"):
                    cloze[row[0]] = note
            # merge tags into note
            tags = row[2].replace(", ", "\x1f").replace(" ", "_")
            tags = tags.replace("\x1f", " ")
            if "tags" not in note:
                note['tags'] = []
            note['tags'] += self.col.tags.split(tags)
            note['tags'] = self.col.tags.canonify(note['tags'])
            # if it's a new card we can go with the defaults
            if row[3] == -1:
                continue
            # add the card
            c = ForeignCard()
            c.factor = int(row[5]*1000)
            c.reps = row[6]
            c.lapses = row[7]
            # ivl is inferred in mnemosyne
            next, prev = row[3:5]
            c.ivl = max(1, (next - prev)/86400)
            # work out how long we've got left
            rem = int((next - time.time())/86400)
            c.due = self.col.sched.today+rem
            # get ord
            m = re.search(".(\d+)$", row[1])
            ord = int(m.group(1))-1
            if 'cards' not in note:
                note['cards'] = {}
            note['cards'][ord] = c
        self._addFronts(front)
        total = self.total
        self._addFrontBacks(frontback)
        total += self.total
        self._addVocabulary(vocabulary)
        self.total += total
        self._addCloze(cloze)
        self.total += total
        self.log.append(ngettext("%d note imported.", "%d notes imported.", self.total) % self.total)

    def fields(self):
        return self._fields

    def _mungeField(self, fld):
        # \n -> br
        fld = re.sub("\r?\n", "<br>", fld)
        # latex differences
        fld = re.sub("(?i)<(/?(\$|\$\$|latex))>", "[\\1]", fld)
        # audio differences
        fld = re.sub("<audio src=\"(.+?)\">(</audio>)?", "[sound:\\1]", fld)
        return fld

    def _addFronts(self, notes, model=None, fields=("f", "b")):
        data = []
        for orig in notes:
            # create a foreign note object
            n = ForeignNote()
            n.fields = []
            for f in fields:
                fld = self._mungeField(orig.get(f, ''))
                n.fields.append(fld)
            n.tags = orig['tags']
            n.cards = orig.get('cards', {})
            data.append(n)
        # add a basic model
        if not model:
            model = addBasicModel(self.col)
            model['name'] = "Mnemosyne-FrontOnly"
        mm = self.col.models
        mm.save(model)
        mm.setCurrent(model)
        self.model = model
        self._fields = len(model['flds'])
        self.initMapping()
        # import
        self.importNotes(data)

    def _addFrontBacks(self, notes):
        m = addBasicModel(self.col)
        m['name'] = "Mnemosyne-FrontBack"
        mm = self.col.models
        t = mm.newTemplate("Back")
        t['qfmt'] = "{{Back}}"
        t['afmt'] = t['qfmt'] + "\n\n<hr id=answer>\n\n{{Front}}"
        mm.addTemplate(m, t)
        self._addFronts(notes, m)

    def _addVocabulary(self, notes):
        mm = self.col.models
        m = mm.new("Mnemosyne-Vocabulary")
        for f in "Expression", "Pronunciation", "Meaning", "Notes":
            fm = mm.newField(f)
            mm.addField(m, fm)
        t = mm.newTemplate("Recognition")
        t['qfmt'] = "{{Expression}}"
        t['afmt'] = t['qfmt'] + """\n\n<hr id=answer>\n\n\
{{Pronunciation}}<br>\n{{Meaning}}<br>\n{{Notes}}"""
        mm.addTemplate(m, t)
        t = mm.newTemplate("Production")
        t['qfmt'] = "{{Meaning}}"
        t['afmt'] = t['qfmt'] + """\n\n<hr id=answer>\n\n\
{{Expression}}<br>\n{{Pronunciation}}<br>\n{{Notes}}"""
        mm.addTemplate(m, t)
        mm.add(m)
        self._addFronts(notes, m, fields=("f", "p_1", "m_1", "n"))

    def _addCloze(self, notes):
        data = []
        notes = notes.values()
        for orig in notes:
            # create a foreign note object
            n = ForeignNote()
            n.fields = []
            fld = orig.get("text", "")
            fld = re.sub("\r?\n", "<br>", fld)
            state = dict(n=1)
            def repl(match):
                # replace [...] with cloze refs
                res = ("{{c%d::%s}}" % (state['n'], match.group(1)))
                state['n'] += 1
                return res
            fld = re.sub("\[(.+?)\]", repl, fld)
            fld = self._mungeField(fld)
            n.fields.append(fld)
            n.fields.append("") # extra
            n.tags = orig['tags']
            n.cards = orig.get('cards', {})
            data.append(n)
        # add cloze model
        model = addClozeModel(self.col)
        model['name'] = "Mnemosyne-Cloze"
        mm = self.col.models
        mm.save(model)
        mm.setCurrent(model)
        self.model = model
        self._fields = len(model['flds'])
        self.initMapping()
        self.importNotes(data)
