#!/usr/bin/python

# tz_word_doc.py
#       --copyright--                   Copyright 2007 (C) Tranzoa, Co. All rights reserved.    Warranty: You're free and on your own here. This code is not necessarily up-to-date or of public quality.
#       --url--                         http://www.tranzoa.net/tzpython/
#       --email--                       pycode is the name to send to. tranzoa.com is the place to send to.
#       --bodstamps--
#       January 18, 2008        bar
#       January 23, 2008        bar     handle errors
#       March 19, 2008          bar     save_as()
#       May 17, 2008            bar     email adr
#       August 23, 2008         bar     don't error out on linux systems
#       October 8, 2008         bar     try both word app names
#       November 22, 2008       bar     back-slash-ize the file name
#       November 29, 2011       bar     pyflake cleanup
#       May 27, 2012            bar     doxygen namespace
#       January 10, 2013        bar     update_docx_image()
#       January 11, 2013        bar     move that zip file update logic over to zipem
#       --eodstamps--
##      \file
#       \namespace              tzpython.tz_word_doc
#
#
#       Operate on Word documents
#
#

import  os
import  sys

import  replace_file
import  zipem


noway       = True
try :
    import  win32com.client
    import  pywintypes
    noway   = False
except :
    e   = sys.exc_info()
    # print e[0], e[1], e[2]
    pass

import  tzlib



class   a_word_doc_exception(Exception) :
        pass


class   a_word_doc(object) :

    def __init__(me, file_name) :
        me.app          = None
        me.doc          = None
        me.file_name    = os.path.normpath(os.path.abspath(file_name))


        if  noway :
            raise       a_word_doc_exception("I can use Word only under Windows for now!")


        for wa in [ 'Word.Application', 'Word.Application.8' ] :
            try :
                me.app      = win32com.client.Dispatch(wa)
                break
            except AttributeError :
                e   = sys.exc_info()
                print e[0], e[1], e[2]
                es          = "Cannot find "  + wa
            except pywintypes.com_error :
                e   = sys.exc_info()
                print e[0], e[1], e[2]
                es          = "Cannot find '" + wa + "' name"
            pass
        if  not me.app :
            raise a_word_doc_exception(es)


        try :
            me.doc      = me.app.Documents.Open(FileName                =   me.file_name,
                                                ConfirmConversions      =   False,
                                                ReadOnly                =   True,
                                                AddToRecentFiles        =   False,
                                                PasswordDocument        =   "",
                                                PasswordTemplate        =   "",
                                                Revert                  =   False,
                                                WritePasswordDocument   =   "",
                                                WritePasswordTemplate   =   "",
                                                # Format                  =   win32com.client.constants.wdOpenFormatAuto
                                               )
        except AttributeError :
            me.close()
            e   = sys.exc_info()
            print e[0], e[1], e[2]
            raise a_word_doc_exception("Cannot open " + wa)
        except pywintypes.com_error :
            me.close()
            raise IOError, "Cannot use " + wa + " to open %s" % ( me.file_name )
        pass



    def as_unicode(me) :
        if  not me.doc :    return(None)

        return(me.doc.Content.Text)


    def as_utf8(me) :
        if  not me.doc :    return(None)

        return(me.doc.Content.Text.encode('utf-8'))


    def as_ascii(me) :
        if  not me.doc :    return(None)

        return(tzlib.lf_only(tzlib.ascii(me.as_unicode())))



    def as_quiet_ascii(me) :
        if  not me.doc :    return(None)

        return(me.as_ascii().replace('\007', ""))



    def __str__(me) :
        return(me.as_quiet_ascii())



    fmts    = {}
    fmts['wdFormatDocument']                        =   0
    fmts['wdFormatDocument97']                      =   0
    fmts['wdFormatTemplate']                        =   1
    fmts['wdFormatTemplate97']                      =   1
    fmts['wdFormatText']                            =   2
    fmts['wdFormatTextLineBreaks']                  =   3
    fmts['wdFormatDOSText']                         =   4
    fmts['wdFormatDOSTextLineBreaks']               =   5
    fmts['wdFormatRTF']                             =   6
    fmts['wdFormatEncodedText']                     =   7
    fmts['wdFormatUnicodeText']                     =   7
    fmts['wdFormatHTML']                            =   8
    fmts['wdFormatWebArchive']                      =   9
    fmts['wdFormatFilteredHTML']                    =   10
    fmts['wdFormatXML']                             =   11
    fmts['wdFormatXMLDocument']                     =   12
    fmts['wdFormatXMLDocumentMacroEnabled']         =   13
    fmts['wdFormatXMLTemplate']                     =   14
    fmts['wdFormatXMLTemplateMacroEnabled']         =   15
    fmts['wdFormatDocumentDefault']                 =   16
    fmts['wdFormatPDF']                             =   17
    fmts['wdFormatXPS']                             =   18
    fmts['wdFormatFlatXML']                         =   19
    fmts['wdFormatFlatXMLMacroEnabled']             =   20
    fmts['wdFormatFlatXMLTemplate']                 =   21
    fmts['wdFormatFlatXMLTemplateMacroEnabled']     =   22


    try     :   fmts['wdFormatDocument']            =   win32com.client.constants.wdFormatDocument
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatText']                =   win32com.client.constants.wdFormatText
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatRTF']                 =   win32com.client.constants.wdFormatRTF
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatHTML']                =   win32com.client.constants.wdFormatHTML
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatHTML']                =   win32com.client.constants.wdFormatHTML
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatPDF']                 =   win32com.client.constants.wdFormatPDF
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatXML']                 =   win32com.client.constants.wdFormatXML
    except AttributeError : pass
    except NameError      : pass

    try     :   fmts['wdFormatXPS']                 =   win32com.client.constants.wdFormatXPS
    except AttributeError : pass
    except NameError      : pass


    ext_fmts    = {
                    '.doc'  :           fmts['wdFormatDocument'],
                    '.txt'  :           fmts['wdFormatText'],
                    '.rtf'  :           fmts['wdFormatRTF'],
                    '.htm'  :           fmts['wdFormatHTML'],
                    '.html' :           fmts['wdFormatHTML'],
                    '.pdf'  :           fmts['wdFormatPDF'],
                    '.xml'  :           fmts['wdFormatXML'],
                    '.xps'  :           fmts['wdFormatXPS'],
                  }



    def save_as(me, file_name, fmt = None) :
        file_name   = os.path.abspath(file_name)
        ( fn, ext)  = os.path.splitext(file_name)

        if  fmt is None :
            fmt = me.ext_fmts.get(ext.lower(), me.fmts['wdFormatDocument'])
        elif isinstance(fmt, basestring) :
            fmt = me.fmts[fmt]

        tfn     = fn + "_tmp" + ext

        me.doc.SaveAs(tfn, fmt)
        me.doc.Close()                                                  # unfortunately, replace file fails if we don't do this (timing?) when we write a non-.pdf file
        replace_file.replace_file(file_name, tfn, file_name + ".bak")




    def close(me) :
        me.doc  = None
        a       = me.app
        me.app  = None
        if  a :
            # a.Quit()              # unfortunately, this closes word 2007 completely, including docs you have open. so we'll leave it running
            pass
        pass



    def __del__(me) :
        me.close()



    pass    # a_word_doc



def update_docx_image(dfn, img_name, ifn, min_size_factor = None, max_size_factor = None) :
    """
        Update the given image (by base name - e.g. "image1.png") in a .docx file with the given image file.
        Do not update if the new image is smaller than the current image times the 'min_size_factor'.
        Do not update if the new image is lareger than the current image times the 'max_size_factor'.
        Return True if the image is updated OK, False otherwise.
    """
    img_name    = os.path.join('word', 'media', img_name)
    return(zipem.update_zip_file(dfn, img_name, ifn, min_size_factor = min_size_factor, max_size_factor = max_size_factor))



#
#
#       Test
#
#
if __name__ == '__main__' :
    import  sys

    import  TZCommandLineAtFile


    del(sys.argv[0])

    TZCommandLineAtFile.expand_at_sign_command_line_files(sys.argv)

    while len(sys.argv) :
        ifn = sys.argv.pop(0)
        ofn = sys.argv.pop(0)

        doc = a_word_doc(ifn)

        if  os.path.splitext(ofn)[1].lower() == '.txt' :
            txt = doc.as_quiet_ascii()
            doc.close()
            tfn = ofn + ".tmp"
            tzlib.write_whole_text_file(tfn, txt)
            replace_file.replace_file(ofn, tfn, ofn + ".bak")
        else :
            doc.save_as(ofn)

        pass

    pass

#
#
#
# eof
