#!/usr/bin/python

### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU Library General Public License as published by
### the Free Software Foundation; version 2 only
###
### 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 Library General Public License for more details.
###
### You should have received a copy of the GNU Library 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.
### Copyright 2007 Dag Wieers <dag@wieers.com>

import getopt, sys, os, distutils.sysconfig

try:
    import uno
except:
    extrapaths = ('/usr/lib/openoffice.org2.0/program/',)
    for path in extrapaths:
        if os.path.isfile(os.path.join(path, 'pyuno.so')):
            sys.path.append(path)
            break
    else:
        print >>sys.stderr, "Error: Cannot find the pyuno.so library."
        print >>sys.stderr, "Please locate this library and send feedback to <tools@lists.rpmforge.net>."
        sys.exit(1)

import uno, unohelper
from com.sun.star.beans import PropertyValue
from com.sun.star.uno import Exception as UnoException
from com.sun.star.io import IOException, XOutputStream
from com.sun.star.connection import NoConnectException

__version__ = "$Revision$"
# $Source$

VERSION = '0.1'

class Fmt:
    def __init__(self, name, extension, filter, summary):
        self.name = name
        self.extension = extension
        self.filter = filter
        self.summary = summary

class FmtList:
    def __init__(self):
        self.list = []
    def add(self, name, extension, filter, summary):
        self.list.append(Fmt(name, extension, filter, summary))
    def byextension(self, extension):
        for fmt in self.list:
            if extension == fmt.extension:
                return fmt
    def byname(self, name):
        for fmt in self.list:
            if name == fmt.name:
                return fmt
    def search(self, keyword):
        pass
    def display(self):
        for fmt in self.list:
            print >>sys.stderr, "  %-8s - %s (.%s)" % (fmt.name, fmt.summary, fmt.extension)

class OutputStream( unohelper.Base, XOutputStream ):
    def __init__( self ):
        self.closed = 0
    def closeOutput(self):
        self.closed = 1
    def writeBytes( self, seq ):
        sys.stdout.write( seq.value )
    def flush( self ):
        pass

outputmap = FmtList()
outputmap.add('bib', 'bib', 'BibTeX_Writer', 'BibTeX')
outputmap.add('doc', 'doc', 'MS Word 97', 'Microsoft Word 97/2000/XP')
outputmap.add('doc6', 'doc', 'MS WinWord 6.0', 'Microsoft Word 6.0')
outputmap.add('doc95', 'doc', 'MS Word 95', 'Microsoft Word 95')
outputmap.add('docbook', 'xml', 'DocBook File', 'DocBook')
outputmap.add('html', 'html', 'HTML (StarWriter)', 'HTML Document (OpenOffice.org Writer)')
outputmap.add('odt', 'odt', 'writer8', 'Open Document Text')
outputmap.add('ott', 'ott', 'writer8_template', 'Open Document Text')
outputmap.add('ooxml', 'xml', 'MS Word 2003 XML', 'Microsoft Office Open XML')
outputmap.add('pdb', 'pdb', 'AportisDoc Palm DB', 'AportisDoc (Palm)')
outputmap.add('pdf', 'pdf', 'writer_pdf_Export', 'PDF - Portable Document Format')
outputmap.add('psw', 'psw', 'PocketWord File', 'Pocket Word')
outputmap.add('rtf', 'rtf', 'Rich Text Format', 'Rich Text Format')
outputmap.add('latex', 'ltx', 'LaTeX_Writer', 'LaTeX 2e')
outputmap.add('sdw', 'sdw', 'StarWriter 5.0', 'StarWriter 5.0')
outputmap.add('sdw4', 'sdw', 'StarWriter 4.0', 'StarWriter 4.0')
outputmap.add('sdw3', 'sdw', 'StarWriter 3.0', 'StarWriter 3.0')
outputmap.add('stw', 'stw', 'writer_StarOffice_XML_Writer_Template', 'Open Office.org 1.0 Text Document Template')
outputmap.add('sxw', 'sxw', 'StarOffice XML (Writer)', 'Open Office.org 1.0 Text Document')
outputmap.add('text', 'txt', 'Text (encoded)', 'Text Encoded')
outputmap.add('txt', 'txt', 'Text', 'Plain Text')
outputmap.add('vor', 'vor', 'StarWriter 5.0 Vorlage/Template', 'StarWriter 5.0 Template')
outputmap.add('vor4', 'vor', 'StarWriter 4.0 Vorlage/Template', 'StarWriter 4.0 Template')
outputmap.add('vor3', 'vor', 'StarWriter 3.0 Vorlage/Template', 'StarWriter 3.0 Template')
outputmap.add('xhtml', 'html', 'XHTML Writer File', 'XHTML Document')

def version():
    print 'unoconv %s' % VERSION
    print 'Written by Dag Wieers <dag@wieers.com>'
    print 'Homepage at http://dag.wieers.com/home-made/unoconv/'
    print
    print 'platform %s/%s' % (os.name, sys.platform)
    print 'python %s' % sys.version
    print
    print 'build revision $Rev$'

def usage():
    print >>sys.stderr, 'usage: unoconv [options] <fmt> file1 file2'

def help():
    print >>sys.stderr, '''Convert from and to any format supported by OpenOffice

unoconv options:
  -c, --connection=<conn>  use a custom connection string
  -e, --extension=ext      specify custom extension
  -f, --format=format      specify the format to convert to
  -l, --list               list the available formats to convert to
  -s, --stdout             write output to stdout
'''

args = sys.argv[1:]
stdout = False
showlist = False
format = 'pdf'
server = 'localhost'
port = '2002'
connection = "uno:socket,host=%s,port=%s;urp;StarOffice.ComponentContext" % (server, port)

try:
    opts, args = getopt.getopt (args, 'c:e:f:hlsv',
                ['connection:', 'extension:', 'format:', 'help', 'list', 'stdout', 'version'] )
except getopt.error, exc:
    print >>sys.stderr, 'unoconv: %s, try unoconv -h for a list of all the options' % str(exc)
    sys.exit(1)

for opt, arg in opts:
    if opt in ['-h', '--help']:
        help()
        sys.exit(1)
    elif opt in ['-c', '--connection']:
        connection = arg
    elif opt in ['-f', '--format']:
        format = arg
    elif opt in ['-l', '--list']:
        showlist = True
    elif opt in ['-s', '--stdout']:
        stdout = True
    elif opt in ['-v', '--version']:
        version()
        sys.exit(1)

if showlist or format == 'list':
    print >>sys.stderr, 'The following list of formats are currently available:'
    print >>sys.stderr
    outputmap.display()
    print >>sys.stderr
    sys.exit(1)

outputfmt = outputmap.byname(format)
if not args:
    print >>sys.stderr, 'You have to provide a file to convert.'
    sys.exit(1)

if not outputfmt:
    print >>sys.stderr, 'Format is not known to unoconv.'
    sys.exit(1)

rc = 0
doc = None

try:
    context = uno.getComponentContext()
    svcmgr = context.ServiceManager

    resolver = svcmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", context)
    unocontext = resolver.resolve(connection)
    unosvcmgr = unocontext.ServiceManager

    desktop = unosvcmgr.createInstanceWithContext("com.sun.star.frame.Desktop", unocontext)
    cwd = unohelper.systemPathToFileUrl( os.getcwd() )

    inProps = PropertyValue( "Hidden" , 0 , True, 0 )
    outProps = (
                PropertyValue( "FilterName" , 0, outputfmt.filter , 0 ),
                PropertyValue( "Overwrite" , 0, True , 0 ),
                PropertyValue( "OutputStream", 0, OutputStream(), 0)
               )
    
    for path in args:
        try:

            filename = unohelper.absolutize(cwd, unohelper.systemPathToFileUrl(path))
            doc = desktop.loadComponentFromURL( filename , "_blank", 0, inProps )
    
            if not doc:
                raise UnoException( "Couldn't open stream for unknown reason", None )
    
            if not stdout:
                (dest, ext) = os.path.splitext(path)
                dest = dest + '.' + outputfmt.extension
                destUrl = unohelper.absolutize( cwd, unohelper.systemPathToFileUrl(dest) )
                print >>sys.stderr, destUrl
                doc.storeToURL(destUrl, outProps)
            else:
                doc.storeToURL("private:stream", outProps)

        except IOException, e:
            print >>sys.stderr, "Error during conversion: %s" % e.Message
            sys.exit(1)
        except UnoException, e:
            print >>sys.stderr, "Error (%s) during conversion: %s" % (repr(e.__class__), e.Message)
            rc = 1
            if doc:
                doc.dispose()
 
except NoConnectException, e:
    print >>sys.stderr, "Error: Could not find an existing connection to Open Office at %s:%s." % (server, port)
    print >>sys.stderr, "Please start an ooffice instance by doing:\n    ooffice -headless -accept=\"socket,host=%s,port=%s;urp;\"" % (server, port)
    sys.exit(1)

except UnoException, e:
    print >>sys.stderr, "Error (%s) : %s" % (repr(e.__class__), e.Message)
    sys.exit(1)

sys.exit(rc)
