# Copyright (c) 2001 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# 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, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
from narval.lib import *
__revision__ = '$Id: Diff.py,v 1.9 2001/12/21 13:44:03 syt Exp $'

XUPD_NS = 'http://www.xmldb.org/xupdate'
MOD_XML = """<?xml version="1.0" encoding="ISO-8859-1"?>
<al:module xmlns:al='%s' xmlns:xupd='%s'>""" % (AL_NS, XUPD_NS)

try:
    from logilab.xmldiff import input, fmes, format
except Exception:
    print 'Package logilab.xmldiff should be installed'
    import traceback
    traceback.print_exc()
    raise Exception
    
def _dom_remove_narval_attrs(node):
    node.removeAttributeNS(AL_NS, 'timestamp')
    node.removeAttributeNS(AL_NS, 'eid')
    
def tree_remove_narval_attrs(node):
    from logilab.xmldiff.objects import N_CHILDS, N_TYPE, NT_SYST, NT_ATTN
    index = 1
    for n in node[N_CHILDS][1:]:
        if n[N_TYPE] == objects.NT_SYST and \
           n[N_CHILDS][0][N_TYPE] == objects.NT_ATTN:
            if n.childs[0].name in ['from_plan', 'from_step', 'timestamp', 
                                    'eid', 'input-id', 'output-id']:
                node[N_CHILDS].pop(index)
                del n
            else: index += 1
        else:
            break
    
def xmldiff_f(args, doc):
    """ extract differences between 2 dom trees """
    ## retrieve arguments ##
    domtree1 = args['old'].firstChild
    domtree2 = args['new'].firstChild
    clean_tree = args['clean'] or 1
    ## remove Narval attributes ##
    if clean_tree:
        _dom_remove_narval_attrs(domtree1)
        _dom_remove_narval_attrs(domtree2)
    ## convert dom trees to internal tree ##
    tree1 = input.tree_from_dom(domtree1)
    tree2 = input.tree_from_dom(domtree2)
    ## apply tree to tree algorithm ##
    strategy = fmes.FmesCorrector(0.59, 0.5)
    actions = strategy.process_trees(tree1, tree2)
    ## format and return output ##
    xupd = format.xupdate_dom(doc, actions)
    return {'output': xupd}

MOD_XML = MOD_XML + """
<al:action name='xmldiff' func='xmldiff_f'>
 <al:input id='old'/>
 <al:input id='new'/>
 <al:input id='clean' optional='yes'><al:match>clean_tree</al:match></al:input>
 <al:output id='output'><al:match>xupd:modifications</al:match></al:output>
</al:action> 
""" 


def xmldiff_files_f(args, doc):
    """ extract differences between 2 xml files """
    from xml.sax import SAXParseException
    import urllib
    ## retrieve arguments ##
    url1 = args['oldurl'].firstChild.data
    url2 = args['newurl'].firstChild.data
    clean_tree = args['clean'] or 1
    norm_sp = args['norm'] or 1
    try:
        fh1 = urllib.urlopen(normalize_url(url1)[0])
        fh2 = urllib.urlopen(normalize_url(url2)[0])
    except IOError, msg :
        return {'error': error(doc, 'No such url', msg)}

    ## convert xlm files to tree ##
    try:
        tree1 = input.tree_from_stream(fh1, norm_sp)
        tree2 = input.tree_from_stream(fh2, norm_sp)
        fh1.close (); fh2.close ()
    except SAXParseException, msg:
        return {'error': error(doc, 'Error in xml file', msg)}
    
    # remove Narval attributes
    if clean_tree:
        tree_remove_narval_attrs(tree1)
        tree_remove_narval_attrs(tree2)
    ## apply tree to tree algorithm ##
    strategy = fmes.FmesCorrector(0.59, 0.5)
    actions = strategy.process_trees(tree1, tree2)
    ## format output ##
    xupd = format.xupdate_dom(doc, actions)
    
    return {'output': xupd}

MOD_XML = MOD_XML +"""
<al:action name='xmldiff_files' func='xmldiff_files_f'>
  <al:input id='oldurl'><al:match>url/text()</al:match></al:input>
  <al:input id='newurl'><al:match>url/text()</al:match></al:input>
  <al:input id='norm'  optional='yes'><al:match>normalize</al:match></al:input>
  <al:input id='clean'  optional='yes'><al:match>clean_tree</al:match></al:input>
  <al:output id='output' ><al:match>xupd:modifications</al:match></al:output>
</al:action> 
"""


def xmldiff_file_elmt_f(args, doc):
    """
    extract differences between a XLM file (old document) and a DOM tree (new document)
    """
    from xml.sax import SAXParseException
    import urllib
    ## retrieve arguments ##
    url1 = args['oldurl'].firstChild.data
    domtree2 = args['new'].firstChild
    clean_tree = args['clean'] or 1
    norm_sp = args['norm'] or 1
    ## get norm tree from url1 ##
    try:
        print 'URL',url1
        fh1 = urllib.urlopen(normalize_url(url1)[0])
    except IOError, msg :
        print 'Error 1'
        return {'error': error(doc, 'No such url', str(msg))}
    # convert xlm file to tree
    try:
        tree1 = input.tree_from_stream(fh1, norm_sp)
        fh1.close ()
    except SAXParseException, msg:
        print 'Error 2'
        return {'error': error(doc, 'Error in xml file', str(msg))}
    ## get norm tree from domtree2 ##
    # remove Narval attributes
    if clean_tree:
        tree_remove_narval_attrs(tree1)
        _dom_remove_narval_attrs(domtree2)
    # convert dom trees to internal tree
    tree2 = input.tree_from_dom(domtree2)

    ## apply tree to tree algorithm ##
    strategy = fmes.FmesCorrector(0.59, 0.5)
    actions = strategy.process_trees(tree1, tree2)
    ## format output ##
    xupd = format.xupdate_dom(doc, actions)
    return {'output': xupd}

MOD_XML = MOD_XML + """
<al:action name='xmldiff_file_elmt' func='xmldiff_file_elmt_f'>
  <al:input id='oldurl'><al:match>url/text()</al:match></al:input>
  <al:input id='new'/>
  <al:input id='norm' optional='yes'><al:match>normalize</al:match></al:input>
  <al:input id='clean' optional='yes'><al:match>clean_tree</al:match></al:input>
  <al:output id='output'><al:match>xupd:modifications</al:match></al:output>
</al:action> 
          """ 
MOD_XML = MOD_XML + "</al:module>"
