#!/usr/bin/python
import sys, os, logging
from os.path import samefile, exists, basename, dirname, realpath, islink
from optparse import OptionParser

def optarg(option, opt, value, parser):
    value = option.default
    rargs = parser.rargs
    arg = rargs[0]
    if not ((arg[:2] == "--" and len(arg) > 2) or
        (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
        value=arg
        del rargs[0]
    if value:
        setattr(parser.values, option.dest, value)

usage = "usage: %prog [options] stylesheet.xsl tinderboxFile"
parser = OptionParser(usage=usage)
parser.add_option("-s", "--stylesheet")
parser.add_option("--stringparam",action="append",nargs=2,default=[])
parser.add_option("-o", "--output-file")
parser.add_option("-a", "--open-with-application", action="callback", callback=optarg, dest="open_with")
parser.add_option("-i", "--in-place",help="transform the file in place. Please provide the backup suffix.")
parser.add_option("-d", "--debug",action="store_true",default=False)
parser.add_option("-y", "--applet",action="store_true",default=False)
(options, args) = parser.parse_args()

if options.applet:
    import EasyDialogs
    if len(args) < 1:
        EasyDialogs.Message("Please drag a Tinderbox file on TinderToolBox")
        sys.exit()
    if len(args) > 2:
        EasyDialogs.Message("Please drag only one Tinderbox file on TinderToolBox")
        sys.exit()

import libxml2, libxslt
from TinderboxDoc import TinderboxDoc, log

styledoc = None

if options.applet:
    if len(args) == 2:
        fullpath1 = args[0]
        fullpath2 = args[1]
        try:
            doc1 = libxml2.parseFile(fullpath1)
        except:
            EasyDialogs.Message("%s is not a proper XML document"%(basename(fullpath1),))
            sys.exit()
        try:
            doc2 = libxml2.parseFile(fullpath2)
        except:
            EasyDialogs.Message("%s is not a proper XML document"%(basename(fullpath2),))
            sys.exit()
        if doc1.getRootElement().name == 'tinderbox':
            doc = doc1
            fullpath = fullpath1
            styledoc = doc2
        elif doc2.getRootElement().name == 'tinderbox':
            doc = doc2
            fullpath = fullpath2
            styledoc = doc1
        else:
            EasyDialogs.Message("Neither %s nor %s are Tinderbox documents"%
                (basename(fullpath1),basename(fullpath2)))
            sys.exit()
        try:
            from TinderboxXslExtension import TinderboxXslExtension
            tbDoc = TinderboxXslExtension(doc)
            # must come after creation of tbDoc
            style = libxslt.parseStylesheetDoc(styledoc)
        except:
            EasyDialogs.Message("%s is a Tinderbox document, but %s is not a valid XSLT stylesheet."%
               (basename(doc.name),basename(styledoc.name)))
            sys.exit()
        
        saveDefault = basename(fullpath).split('.')
        if len(saveDefault) > 1:
            saveDefault.pop()
        saveDefault.append('xml')
        saveDefault = '.'.join(saveDefault)
        ctx=styledoc.xpathNewContext()
        ctx.xpathRegisterNs('xsl','http://www.w3.org/1999/XSL/Transform')
        paramsEls = ctx.xpathEval("/xsl:stylesheet/xsl:param")
        params = {}
        for p in paramsEls:
            name = p.prop('name')
            #BUG: In a select, we have values that will be evaluated further.
            default = p.prop('select') or p.content or ''
            result = EasyDialogs.AskString("Value for XSL parameter "+name, default)
            if result == None:
                # user canceled
                sys.exit()
            if result != default:
                params[name] = result
        result = style.applyStylesheet(doc, params)
    else:
        fullpath = args[0]
        saveDefault = basename(fullpath) # overwrite
        try:
            doc = libxml2.parseFile(fullpath)
        except:
            EasyDialogs.Message("%s is not a valid XML document"%(basename(fullpath),))
            sys.exit()
        if doc.getRootElement().name != 'tinderbox':
            EasyDialogs.Message("%s is not a Tinderbox document"%(basename(fullpath),))
            sys.exit()
        tbDoc = TinderboxDoc(doc)
        tbDoc.transform()
        result = tbDoc.document
else:
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if (options.output_file and options.in_place):
        parser.error("Cannot specify both output-file and in-place")
    if options.debug:
        import logging

        log.setLevel(logging.DEBUG)
        from debugWrapper import debugWrapper
        if options.stylesheet:
            from TinderboxXslExtension import _TextRange, TinderboxXslExtension
            debugWrapper.wrapClass(log, TinderboxXslExtension)
            debugWrapper.wrapClass(log, _TextRange)
        else:
            debugWrapper.wrapClass(log, TinderboxDoc)
            from TinderboxDoc import _styleRun,_styleRuns
            debugWrapper.wrapClass(log, _styleRun)
            debugWrapper.wrapClass(log, _styleRuns)
        log.setLevel(logging.DEBUG)
        #log.setLevel(logging.WARNING)
    else:
        log.setLevel(logging.WARNING)
    fullpath = args[0]
    saveDefault = basename(fullpath) # overwrite
    try:
        doc = libxml2.parseFile(fullpath)
    except:
        print "%s is not a valid XML document"%(basename(fullpath),)
        sys.exit()
    if doc.getRootElement().name != 'tinderbox':
        print "%s is not a Tinderbox document"%(basename(fullpath),)
        sys.exit()
    if options.stylesheet:
        styledoc = libxml2.parseFile(options.stylesheet)
        from TinderboxXslExtension import TinderboxXslExtension
        tbDoc = TinderboxXslExtension(doc)
        # must come after creation of tbDoc
        style = libxslt.parseStylesheetDoc(styledoc)
        result = style.applyStylesheet(doc, dict(options.stringparam))
    else:
        tbDoc = TinderboxDoc(doc)
        tbDoc.transform()
        result = tbDoc.document

if not result:
    if options.applet:
        EasyDialogs.Message("Transform failed")
    else:
        sys.stderr.write("Transform failed\n")
    sys.exit()

docName = doc.xpathEval("/tinderbox/item/attribute[@name='Name']/text()")[0].content

if options.output_file:
    destination = options.output_file
elif not styledoc:
    import EasyDialogs
    destination = EasyDialogs.AskFileForSave(
        message="Where do you want to save %s?"%(docName,),
        savedFileName=saveDefault,
        defaultLocation=dirname(fullpath),
        dialogOptionFlags=0x00010000,#kNavDontConfirmReplacement
        )
    if destination is None:
        # user chose cancel
        sys.exit()
else:
    destination = None

if destination and exists(destination) and not styledoc:
    #write over; make backup
    suffix = ".bak"
    suffixNum = 0
    while exists(fullpath+suffix):
        suffixNum+=1
        suffix = ".bak"+str(suffixNum)
    os.rename(fullpath, fullpath+suffix)

result.saveFile(destination)

if not styledoc:

    import MacOS
    MacOS.SetCreatorAndType(destination, 'Cere', 'Cere')
    if MacOS.WMAvailable():
        from TinderboxAE import TinderboxAE
        tbapp = TinderboxAE()
        doOpen = False
        if samefile(fullpath,destination):
            try:
                tbapp.revert(tbapp.document(basename(fullpath)))
            except:
                doOpen = True
        else:
            doOpen = True
        if doOpen:
            from Carbon.File import FSSpec
            fsspec=FSSpec(fullpath)
            tbapp.open(fsspec)
        
        tbapp.activate()
    else:
        appPath = join(dirname(normpath(join(os.getcwd(), __file__))),'revertTbFile.app')
        os.spawnl(os.P_NOWAIT,"/usr/bin/open", "open", "-a", appPath, fullpath)
