#!/usr/bin/env python
#-*- encoding:utf-8 -*-

# run_palavras.py - A set of functions to run the PALAVRAS parser [Bick, 2000]
# and automatically add "semantic tags"
#
# Copyright (C) 2015  SAMSUNG Eletrônica da Amazônia LTDA
#
# Authors:  Alessandro Bokan Garay <alessandro.bokan@gmail.com>

from __future__ import unicode_literals

from xml.dom import minidom

import sys
import os
import codecs

PATH_RESOURCES = os.path.dirname(os.path.realpath(__file__)) +\
    '/../src/bin/resources/'

PATH_UTILS = os.path.dirname(os.path.realpath(__file__))

PATH_INPUT = PATH_UTILS + '/input.txt'

PATH_OUTPUT = PATH_UTILS + '/input.xml'

PATH_CALL_PHP = PATH_UTILS + '/call_palavras_tree.php'


def has_nonterminals_edges(nontermianls):
    """
    Problem: PALAVRAS generates nonterminals without elements (<edges>).
    Solution: Remove sentence/instance (<s>)

    """
    for i in nontermianls:
        cont = 0
        for j in i.childNodes:
            if j.nodeType == j.ELEMENT_NODE:
                cont += 1
        if cont == 0:
            return False
    return True


def modifier(element, nameID, strID):
    """
    Modify specific id from some xml element (s, t, graph, t, nt, edges)

    """
    finder = element.attributes[nameID].value.find('.')
    val = element.attributes[nameID].value
    rsp = strID + val[finder:] if finder > -1 else strID + '.' + val
    element.attributes[nameID].value = rsp


def modify_identifiers(sentence, terminals, nonterminals, strID):
    """
    Modifiy all identifiers for an instance (sentence): sentence <s>,
    graph <graph>, terminals <t>, nonterminals <nt> and edges <edge>.

        <s id="1.s1">
        <s id="2.s1">
        <s id="3.s1">
        <s id="1.s2">
        <s id="1.s3">
        <s id="2.s3">

    """
    # Modify sentence id '<s>'
    modifier(sentence, 'id', strID)
    # Modify graph id '<graph>'
    modifier(sentence.getElementsByTagName('graph')[0], 'root', strID)
    # Modify all terminal ids '<t>'
    for t in terminals:
        if t.nodeType == t.ELEMENT_NODE:
            modifier(t, 'id', strID)
    # Modify all nonterminal ids '<nt>'
    for nt in nonterminals:
        modifier(nt, 'id', strID)
        # Modify all nonterminal edge ids '<edge>'
        for edge in nt.childNodes:
            if edge.nodeType == edge.ELEMENT_NODE:
                modifier(edge, 'idref', strID)


def add_semantic_tags(inputFile):
    """
    Function to add semantic tags in a "xml" file generated by PALAVRAS

        For example, a XML input have 2 sentences (s1, s2), where s1 have
        3 verbs. Then, 3 instances will be created for s1 and, at the same
        time, it will be added a semantic tag (<sem>) for each instance.

    """
    # Initialize word terminals list
    trms = []
    # Initilize wrong sentence positions
    position = 1
    # Open files
    inFile = open(inputFile, mode='r')
    outFile = open(PATH_RESOURCES + 'input.xml', mode='w')
    # Write 'xml' header
    header = '<?xml version="1.0" encoding="UTF-8"?>\n\n<corpus>\n<body>\n\n'
    outFile.write(header)
    # Parse 'xml' document
    dom = minidom.parse(inFile)
    # Iterate all sentence elements
    for i in dom.getElementsByTagName('s'):
        hasVerb = 0
        # All nonterminals in a sentence must have child elements
        nonterminals = i.getElementsByTagName('nt')
        if has_nonterminals_edges(nonterminals):
            # Update id sentences value (p.e: id='.s1')
            i.attributes['id'].value = '.' + i.attributes['id'].value
            i.removeAttribute('source')
            strID = 1
            # Iterate all terminal elements
            terminals = i.getElementsByTagName('t')
            for j in terminals:
                isVerb = j.getAttribute('pos').find('v-')
                isVerbAux = j.getAttribute('extra').find('aux')
                # Terminal must be a verb and not be an auxiliar verb
                if isVerb == 0 and isVerbAux == -1:
                    hasVerb = 1
                    # Modify all ids in a <s> instance
                    modify_identifiers(i, terminals, nonterminals, str(strID))
                    # Get verb ID
                    verbID = j.getAttribute('id')
                    # Create <sem> child
                    sem = dom.createElement('sem')
                    sem.appendChild(dom.createTextNode('\n\t\t'))
                    frames = dom.createElement('frames')
                    frames.appendChild(dom.createTextNode('\n\t\t\t'))
                    sem.appendChild(frames)
                    frame = dom.createElement('frame')
                    frame.appendChild(dom.createTextNode('\n\t\t\t\t'))
                    frame.setAttribute('name', 'Argumentos')
                    frames.appendChild(frame)
                    target = dom.createElement('target')
                    target.appendChild(dom.createTextNode('\n\t\t\t\t\t'))
                    frame.appendChild(target)
                    fenode = dom.createElement('fenode')
                    target.appendChild(fenode)
                    fenode.setAttribute('idref', verbID)
                    target.appendChild(dom.createTextNode('\n\t\t\t\t'))
                    frame.appendChild(dom.createTextNode('\n\t\t\t'))
                    frames.appendChild(dom.createTextNode('\n\t\t'))
                    sem.appendChild(dom.createTextNode('\n\t'))
                    # Add child to the last position
                    if strID == 1:
                        i.appendChild(dom.createTextNode('\t'))
                        i.appendChild(sem)
                        i.appendChild(dom.createTextNode('\n'))
                    else:
                        i.childNodes[-2] = sem
                    # Write into the file
                    instance = i.toxml() + '\n'
                    outFile.write(instance.encode('utf-8'))
                    strID += 1
            if hasVerb == 0:
                msg = "S" + str(position) + ": '" + i.getAttribute('text')
                # print msg + "' hasn't verb"
            else:
                trms.append(
                    [t.attributes['word'].value.replace('_', ' ') for t in terminals]
                )
        else:
            msg = "S" + str(position) + ": '" + i.getAttribute('text')
            # print msg + "' hasn't nonterminal edges"
        position += 1
    # Write 'xml' footer
    footer = '\n</body>\n</corpus>'
    outFile.write(footer)
    # Close files
    outFile.close()
    inFile.close()
    # Remove "input.xml" file
    #os.remove(PATH_OUTPUT)
    return trms


def run_palavras_file(inputFile):
    """
    Function to run the PALAVRAS system (tree format) given a input file

    """
    outputFile = inputFile.replace('.txt', '.xml')
    # Create command
    cmd = "cat " + PATH_INPUT + " |"\
        "/opt/palavras/por.pl 2> /dev/null | "\
        "/opt/palavras/bin/dep2tree 2> /dev/null | "\
        "/opt/palavras/bin/visl2extranodes.pl 2> /dev/null | "\
        "perl -wnpe 's/^=//;' |"\
        "/opt/palavras/bin/visl2tiger.pl > " + PATH_OUTPUT + " 2> /dev/null"
    # Run Palavras
    os.system(cmd)
    # Return output file
    return PATH_OUTPUT


def run_palavras_sentence(sentence):
    """
    Function to run the PALAVRAS system (tree format) given a input sentence.

    """
    cmd = "echo '" + sentence + "' |"\
        "/opt/palavras/por.pl 2> /dev/null |"\
        "/opt/palavras/bin/dep2tree 2> /dev/null |"\
        "/opt/palavras/bin/visl2extranodes.pl 2> /dev/null |"\
        "perl -wnpe 's/^=//;' |"\
        "/opt/palavras/bin/visl2tiger.pl > " + PATH_INPUT + " 2> /dev/null"
    # Run Palavras
    os.system(cmd.encode('utf8'))
    # Return PALAVRAS xml file
    return PATH_INPUT


def run_palavras_sentence_by_web_service(sentence):
    """
    Function to run the PALAVRAS system (tree format) by a "web service"
    given a input sentence.

    """
    # Create a "input.txt" file that contains the input sentence
    f = codecs.open(PATH_INPUT, 'w', 'utf-8')
    f.write(sentence)
    f.close()
    # Set the command line 
    cmd = 'php ' + PATH_CALL_PHP + ' ' + PATH_INPUT + ' > ' + PATH_OUTPUT
    # Run Palavras
    os.system(cmd)
    # Remove "input.txt" file
    #os.remove(PATH_INPUT)
    # Return PALAVRAS xml file
    return PATH_OUTPUT
