#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
Integrated Semantic Framework (coolisf) main application

`coolisf` is read `kul-eye-es-ef` officially (sometimes kul-is-f)
'''

# This code is a part of coolisf library: https://github.com/letuananh/intsem.fx
# :copyright: (c) 2014 Le Tuan Anh <tuananh.ke@gmail.com>
# :license: MIT, see LICENSE for more details.

import os
import logging
import collections

from texttaglib.chirptext.cli import CLIApp, setup_logging
from texttaglib.chirptext import header, confirm, TextReport, FileHelper, Counter, Timer
from texttaglib.chirptext.leutile import is_number
from texttaglib.chirptext import texttaglib as ttl
from lelesk import LeLeskWSD
from lelesk import LeskCache  # WSDResources

from coolisf import __version__
from coolisf.lexsem import Lexsem
from coolisf.config import read_config, _get_config_manager
from coolisf.common import write_file
from coolisf.morph import Transformer
from coolisf.ghub import GrammarHub
from coolisf.util import read_ace_output
from coolisf.dao import read_tsdb
from coolisf.gold_extract import read_tsdb_ttl, tag_doc
from coolisf.gold_extract import generate_gold_profile
from coolisf.gold_extract import export_to_visko
from coolisf.gold_extract import read_gold_sents
from coolisf.model import Document
from coolisf.dao.textcorpus import RawCollection
from coolisf.mappings import PredSense


OUTPUT_DMRS = 'dmrs'
OUTPUT_MRS = 'mrs'
OUTPUT_XML = 'xml'
OUTPUT_FORMATS = [OUTPUT_DMRS, OUTPUT_MRS, OUTPUT_XML]
WSD_CHOICES = [ttl.Tag.LELESK, ttl.Tag.MFS]
setup_logging('logging.json', 'logs')


def getLogger():
    return logging.getLogger(__name__)

########################################################################


def to_visko(cli, args):
    ''' Convert ACE output to ISF XML format '''
    # determine docpath
    if args.bibloc:
        visko_data_dir = os.path.abspath(args.bibloc)
    else:
        # default bibloc
        visko_data_dir = os.path.expanduser('~/workspace/visualkopasu/data/biblioteche')
    if args.separate:
        export_path = os.path.join(visko_data_dir, args.biblioteca, args.corpus, args.doc)
    else:
        export_path = args.doc
    print("Biblioteche location: {}".format(visko_data_dir))
    print("Document location   : {}".format(export_path))
    # which file to export
    if args.file is not None:
        # export MRS file
        sents = read_ace_output(args.file, top1dmrs=args.top1dmrs)  # e.g. data/wndefs.nokey.mrs.txt
        if args.topk:
            sents = sents[:int(args.topk)]
    else:
        if input("No MRS file provided. Proceed to export gold profile to Visko (yes/no)? ").lower() in ['y', 'yes']:
            print("Exporting gold profile to Visko")
            sents = read_gold_sents()
        else:
            print("Aborted")
            return
    export_to_visko(sents, export_path, separate=args.separate, halt_on_error=not args.forgive)


def parse_isf(cli, args):
    ''' Process raw text file '''
    # verification
    if not os.path.isfile(args.infile):
        print("Error. File does not exist. (provided: {})".format(args.infile))
    if args.output and os.path.exists(args.output):
        if not confirm("Output file exists. Do you want to continue (Y/N)? "):
            print("Program aborted.")
            return
    # process
    header("Processing file: {}".format(args.infile))
    report = TextReport(args.output)
    ghub = GrammarHub()
    lines = FileHelper.read(args.infile).splitlines()
    wsd = LeLeskWSD(dbcache=LeskCache())
    ctx = PredSense.wn.ctx()
    timer = Timer(cli.logger)
    timer.start("Parsing {} sentences".format(len(lines)))
    for idx, sent in enumerate(ghub.ERG_ISF.parse_many_iterative(lines, parse_count=args.topk, ignore_cache=args.nocache)):
        if args.max and args.max < idx:
            break
        print("Processing sentence {} of {}".format(idx + 1, len(lines)))
        sent.tag_xml(method=args.wsd, wsd=wsd, ctx=ctx)
        report.writeline(sent.to_xml_str(pretty_print=not args.compact))
        report.writeline("\n\n")
    timer.stop("Finished")


def retag_doc(cli, args):
    ''' Re-tag an ISF document '''
    # verification
    if args.output and os.path.exists(args.output) and not args.yes:
        if not confirm("Output file exists. Do you want to continue (Y/N)? "):
            print("Program aborted.")
            return
    # process
    header("Processing file: {}".format(args.path))
    doc = Document.from_file(args.path, idents=args.ident)
    print("Document size: {}".format(len(doc)))
    if not args.wsd and not args.ttl:
        print("Nothing to do")
        return
    if args.wsd:
        print("Retagging document using {}".format(args.wsd))
        wsd = LeLeskWSD(dbcache=LeskCache())
        wsd.connect()
        ctx = PredSense.wn.ctx()
        for idx, sent in enumerate(doc):
            if args.topk and idx > args.topk:
                break
            if args.ident and sent.ident not in args.ident:
                continue
            print("Tagging sentence #{}/{}".format(idx + 1, len(doc)))
            try:
                sent.tag_xml(method=args.wsd, wsd=wsd, ctx=ctx)
            except Exception as e:
                if args.forgive:
                    getLogger().warning("Could not process sentence {}".format(sent.ID))
                else:
                    raise e
        ctx.close()
        wsd.disconnect()
    if args.ttl:
        print("Tagging doc {} using TTL doc {}".format(doc.name, args.ttl))
        ttl_doc = ttl.read(args.ttl, mode=args.ttl_format)
        kwargs = {}
        if args.mode:
            kwargs['mode'] = args.mode
        tag_doc(doc, ttl_doc, taggold=not args.nogold, on_error=args.on_error, **kwargs)
    doc_xml_str = doc.to_xml_str(pretty_print=not args.compact, with_dmrs=not args.nodmrs)
    write_file(doc_xml_str, args.output)


def extract_tsdb(cli, args):
    ''' Read parsed sentences from a TSDB profile '''
    if not os.path.exists(args.path):
        print("TSDB profile does not exist (path: {})".format(args.path))
    else:
        # read document
        timer = Timer(cli.logger)
        timer.start("Reading document")
        if os.path.isdir(args.path):
            # is TSDB
            if args.ttl:
                doc = read_tsdb_ttl(args.path, ttl_path=args.ttl, name=args.name, title=args.title)
            else:
                doc = read_tsdb(args.path)
            if args.ident or args.ids:
                print("Idents: {}".format(args.ident))
                doc_new = Document(name=doc.name, title=doc.title)
                for sent in doc:
                    if (sent.ident in args.ident) or (sent.ID in args.ids):
                        doc_new.add(sent)
                doc = doc_new
        elif os.path.isfile(args.path):
            # read doc XML
            doc = Document.from_file(args.path, idents=args.ident)
            print(len(doc))
            if args.ttl:
                ttl_doc = ttl.Document.read_ttl(args.ttl)
                doc = tag_doc(doc, ttl_doc)
        # process doc
        print("Found sentences: {}".format(len(doc)))
        print("With shallow: {}".format(len(list(s for s in doc if s.shallow))))