#!/usr/bin/python -u
#
# The exercise of rewriting xsltproc on top of the python
# bindings, not complete yet and shows up the things missing
# from the existing python interfaces
#
import sys
import time
import os
import string
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
import libxslt

debug = 0
repeat = 0
timing = 0
novalid = 0
noout = 0
docbook = 0
html = 0
xinclude = 0
profile = 0
params = {}
output = None
errorno = 0

#
# timing
#
begin = 0
endtime = 0
def startTimer():
    global begin

    begin = time.time()

def endTimer(msg):
    global begin
    global endtime

    endtime = time.time()
    print "%s took %d ms" % (msg, (endtime - begin) * 1000)

def xsltProcess(doc, cur, filename):
    global timing
    global xinclude
    global params
    global html

    if xinclude:
        if timing:
            startTimer()
        doc.XIncludeProcess()
        if timing:
            endTimer("XInclude processing %s" % (filename))

    if timing:
        startTimer()
    if output == None:
        if repeat != 0:
            for j in range(1, repeat):
                res = cur.applyStylesheet(doc, params)
                res.freeDoc()
                doc.freeDoc()
                if html == 1:
                    doc = libxml2.htmlParseFile(filename, None)
                else:
                    doc = libxml2.parseFile(filename, None)
#        ctxt = libxslt.newTransformContext(doc)
#        if ctxt == None:
#            return
        if profile:
            print "TODO: Profiling not yet supported"
        else:
            res = cur.applyStylesheet(doc, params)
        if timing:
            if repeat != 0:
                endTimer("Applying stylesheet %d times" % (repeat))
            else:
                endTimer("Applying stylesheet")
        doc.freeDoc()
        if res == None:
            print "no result for %s" % (filename)
            return
        if noout != 0:
            res.freeDoc()
            return
        if debug == 1:
            res.debugDumpDocument(None)
        else:
            if timing:
                startTimer()
            cur.saveResultToFilename("-", res, 0)
            if timing:
                endTimer("Saving result")
        res.freeDoc()
    else:
        print "TODO: xsltRunStylesheet not yet mapped"

def usage(name = 'pyxsltproc'):
    print "Usage: %s [options] stylesheet file [file ...]" % (name)
    print "a reimplementation of xsltproc(1) on top of libxslt-python"
    print "   Options:"
    print "\t--version or -V: show the version of libxml and libxslt used"
    print "\t--verbose or -v: show logs of what's happening"
    print "\t--output file or -o file: save to a given file"
    print "\t--timing: display the time used"
    print "\t--repeat: run the transformation 20 times"
    print "\t--debug: dump the tree of the result instead"
    print "\t--novalid skip the Dtd loading phase"
    print "\t--noout: do not dump the result"
    print "\t--maxdepth val : increase the maximum depth"
    print "\t--html: the input document is(are) an HTML file(s)"
    print "\t--param name value : pass a (parameter,value) pair"
    print "\t       value is an XPath expression."
    print "\t       string values must be quoted like \"'string'\""
    print "\t       or use stringparam to avoid it"
    print "\t--stringparam name value : pass a (parameter,string value) pair"
    print "\t--nonet refuse to fetch DTDs or entities over network"
    print "\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES"
    print "\t             otherwise XML Catalogs starting from "
    print "\t         file:///etc/xml/catalog are activated by default"
    print "\t--xinclude : do XInclude processing on document input"
    print "\t--profile or --norman : dump profiling informations "
    print "\nProject libxslt home page: http://xmlsoft.org/XSLT/"
    print "To report bugs and get help: http://xmlsoft.org/XSLT/bugs.html"

def main(args = None):
    global debug
    global repeat
    global timing
    global novalid
    global noout
    global docbook
    global html
    global xinclude
    global profile
    global params
    global output
    global errorno

    done = 0
    cur = None

    if not args:
        args = sys.argv[1:]
        if len(args) <= 0:
            usage(sys.argv[0])
            

    i = 0
    while i < len(args):
        if args[i] == "-":
            break
        if args[i][0] != '-':
            i = i + 1
            continue
        if args[i] == "-timing" or args[i] == "--timing":
            timing = 1
        elif args[i] == "-debug" or args[i] == "--debug":
            debug = 1
        elif args[i] == "-verbose" or args[i] == "--verbose" or \
             args[i] == "-v":
            print "TODO: xsltSetGenericDebugFunc() mapping missing"
        elif args[i] == "-version" or args[i] == "--version" or \
             args[i] == "-V":
            print "TODO: version informations mapping missing"
        elif args[i] == "-verbose" or args[i] == "--verbose" or \
             args[i] == "-v":
            if repeat == 0:
                repeat = 20
            else:
                repeat = 100
        elif args[i] == "-novalid" or args[i] == "--novalid":
            print "TODO: xmlLoadExtDtdDefaultValue mapping missing"
            novalid = 1
        elif args[i] == "-noout" or args[i] == "--noout":
            noout = 1
        elif args[i] == "-html" or args[i] == "--html":
            html = 1
        elif args[i] == "-nonet" or args[i] == "--nonet":
            print "TODO: xmlSetExternalEntityLoader mapping missing"
            nonet = 1
        elif args[i] == "-catalogs" or args[i] == "--catalogs":
            try:
                catalogs = os.environ['SGML_CATALOG_FILES']
            except:
                catalogs = None
            if catalogs != none:
                libxml2.xmlLoadCatalogs(catalogs)
            else:
                print "Variable $SGML_CATALOG_FILES not set"
        elif args[i] == "-xinclude" or args[i] == "--xinclude":
            xinclude = 1
            libxslt.setXIncludeDefault(1)
        elif args[i] == "-param" or args[i] == "--param":
            i = i + 1
            params[args[i]] = args[i + 1]
            i = i + 1
        elif args[i] == "-stringparam" or args[i] == "--stringparam":
            i = i + 1
            params[args[i]] = "'%s'" % (args[i + 1])
            i = i + 1
        elif args[i] == "-maxdepth" or args[i] == "--maxdepth":
            print "TODO: xsltMaxDepth mapping missing"
        else:
            print "Unknown option %s" % (args[i])
            usage()
            return(3)
        
        
        
        
        i = i + 1
        
    libxml2.lineNumbersDefault(1)
    libxml2.substituteEntitiesDefault(1)
    # TODO: xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS
    # if novalid:
    # TODO: xmlLoadExtDtdDefaultValue = 0

    # TODO libxslt.exsltRegisterAll();
    libxslt.registerTestModule()

    i = 0
    while i < len(args) and done == 0:
        if args[i] == "-maxdepth" or args[i] == "--maxdepth":
            i = i + 2
            continue
        if args[i] == "-o" or args[i] == "-output" or args[i] == "--output":
            i = i + 2
            continue
        if args[i] == "-param" or args[i] == "--param":
            i = i + 3
            continue
        if args[i] == "-stringparam" or args[i] == "--stringparam":
            i = i + 3
            continue
        if args[i] != "-" and args[i][0] == '-':
            i = i + 1
            continue
        if timing:
            startTimer()
        style = libxml2.parseFile(args[i])
        if timing:
            endTimer("Parsing stylesheet %s" % (args[i]))
        if style == None:
            print "cannot parse %s" % (args[i])
            cur = None
            errorno = 4
            done = 1
        else:
            cur = libxslt.loadStylesheetPI(style)
            if cur != None:
                xsltProcess(style, cur, args[i])
                cur = None
            else:
                cur = libxslt.parseStylesheetDoc(style)
                if cur == None:
                    style.freeDoc()
                    errorno = 5
                    done = 1
        i = i + 1
        break

    while i < len(args) and done == 0 and cur != None:
        if timing:
            startTimer()
        if html:
            doc = libxml2.htmlParseFile(args[i], None)
        else:
            doc = libxml2.parseFile(args[i])
        if doc == None:
            print "unable to parse %s" % (args[i])
            errorno = 6
            i = i + 1
            continue
        if timing:
            endTimer("Parsing document %s" % (args[i]))
        xsltProcess(doc, cur, args[i])
        i = i + 1

    if cur != None:
        cur.freeStylesheet()
    params = None

if __name__ == "__main__":
    main()

# Memory debug specific
libxslt.cleanup()
if libxml2.debugMemory(1) != 0:
    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
    libxml2.dumpMemory()

sys.exit(errorno)
