#**********************************************************************
#   Gnu Cash to OpenOffice.org (gnuc2ooo.py)
#   
#   Macros for the download of GnuCash Data to OpenOffice.org Base
#
#   Macro SetGnuCashFilePaths:
#       Set or change the filepaths of the (GnuCash) data source
#       and of the new OpenOffice.org database that will be created
#       in this macro though still empty
#
#   Macro fillGnuCashDB:
#       Download data from the GnuCash data source to OpenOffice.org
#       Base
#   
#
#**********************************************************************
#   Copyright (c) 2008 Knut Gerwens
#   gnuc2ooo@alice-dsl.net
#
#   This library is free software; you can redistribute it and/or
#   modify it under the terms of the GNU Lesser General Public
#   License as published by the Free Software Foundation; either
#   version 2.1 of the License, or (at your option) any later version.
#
#   This library 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
#   Lesser General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public
#   License along with this library; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   See:  https://www.gnu.org/licenses/lgpl.html
#
#**********************************************************************
#   Acknowledgements: Special thanks go to the authors on OpenOffice.org
#   macro programming Roberto Benitez(http://www.baseprogramming.com) and
#   Andrew Pitonyak (http://www.pitonyak.org)
#**********************************************************************
#   Changes
#   Knut Gerwens, 2008-09-16:
#   Bugfix: locale.getlocale() -> locale.getdefaultlocale()
#   Extension: field description in table TRN from 256 to 512 Bytes
#
#   Knut Gerwens, 2008-09-20:
#   try/unconditional except for read input, so Windows XP-Users can use
#   the program with unzipped GnuCashFiles (no valid gzip module).
#   try/except for sort on hierarchy (accounttree), because python 2.3.4
#   does not support keyword argument in sort.
#   Infobox/Success-message at end of FillGnuCashDB
#
#   Knut Gerwens, 2008-09-29:
#   Improved Errorhandling. Errors are intercepted, Some Error and
#   Trace-Information is written to logfile GnuCashFilePaths.txt
#
#   Knut Gerwens, 2008-10-02:
#   Checkpoint-Statement at the end added, so tables are actually stored
#   in database and not only as logfile
#
#   Knut Gerwens, 2008-10-04:
#   Improved memory-mangement. Writing to disc is enforced every 1000 rows
#

import uno, unohelper
import gzip
import xml.sax as sax
import os.path, locale
import time

# ********************** OPENOFFICE.ORG-API *******************************
# Component Context und Service Manager
ctx = uno.getComponentContext()
smgr = ctx.ServiceManager
# create database context
Context = smgr.createInstanceWithContext(
    "com.sun.star.sdb.DatabaseContext", ctx)
# Star Desktop
Desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
# user directory
PathSettings = smgr.createInstanceWithContext(
    "com.sun.star.util.PathSettings", ctx)


# ************************** PROLOG ***************************************
from com.sun.star.ui.dialogs.TemplateDescription import FILEOPEN_SIMPLE, FILESAVE_AUTOEXTENSION
lcodec = locale.getdefaultlocale()[1]
set_macro = "SetGnuCashFilePaths"
settings_textentrance = "#This file was generated by OpenOfficeMacro: "
settings_textinp = "GnuCashDatafile: "
settings_textoutp = "Registered Database in Openoffice.org: "
# Trace / Error - Information
global crout
crout = 'main'
last_input_getDBFilename = 'not available'
last_input_createDB = 'not available'
last_input_createdelete = 'not available'
last_input_eval_fraction = 'not available'
last_input_view_all_transactions = 'not available'
last_input___init__ = 'not available'
last_input_startElement = 'not available'
last_input_endElement = 'not available'
last_input_insert_statement = 'not available'
last_input_characters = 'not available'
last_input_MessageBox = 'not available'
insert_ct = 0
maxmemory = 1000

def settings_filepath():
    userdir_url = PathSettings.UserConfig
    userdir = unohelper.fileUrlToSystemPath(userdir_url)
    userfile = os.path.join(userdir, 'GnuCashFilePaths.txt')
    return userfile

def getGCFilename():
    global crout
    crout = 'getGCFilename'
    fp_read.Title = "Pick Output Data File of GnuCash Program"
    fp_read.initialize((FILEOPEN_SIMPLE,))
    fp_read.MultiSelectionMode = False
    if fp_read.execute():
        return fp_read.Files[0]

def getDBFilename(default):
    global crout
    crout = 'getDBFilename'
    global last_input_getDBFilename
##    last_input_getDBFilename = str(default) + '\n'
    
    fp_write.Title = "Enter Database Filename"
    fp_write.MultiSelectionMode = False
    try:
        fp_write.appendFilter("Base Files (*.odb)", "*.odb")
    except:
        fp_write.setCurrentFilter("Base Files (*.odb)")
    fp_write.initialize((FILESAVE_AUTOEXTENSION,))
    fp_write.setDefaultName(default)
    if fp_write.execute():
        return fp_write.Files[0] 

def createDB(db_defaultname):
    global crout
    crout = 'createDB'
    global last_input_createDB
##    last_input_createDB = str(db_defaultname)

    fileurl=getDBFilename(db_defaultname)
    if fileurl:
        DB = Context.createInstance()
        DB.URL = "sdbc:embedded:hsqldb"
        DB.DatabaseDocument.storeAsURL(fileurl, ())
        filepath = unohelper.fileUrlToSystemPath(fileurl)
        filename = os.path.basename(filepath)
        datasource = Context.getByName(fileurl)
        dbname = filename[:-4]
        Context.registerObject(dbname, datasource)
        return dbname
    else:
        return None

def exec_SetGnuCashFilePaths():
    """ Definition of data source and target files, creation of empty database """
    
    global fp_read, fp_write
    global crout
    crout = 'SetGnuCashFilePaths'
    # uno service for filepickers
    # There was a bug under ubuntu 8.04 when I took the normal,
    # i.e. Gnom FilePicker, so I had to take the Office File Picker
    fp_read = smgr.createInstanceWithContext(
        "com.sun.star.ui.dialogs.OfficeFilePicker", ctx)
    fp_write = smgr.createInstanceWithContext(
        "com.sun.star.ui.dialogs.OfficeFilePicker", ctx)

    GCFileURL = getGCFilename()
    if GCFileURL:
        GCFile = unohelper.fileUrlToSystemPath(GCFileURL)
    else:
        return None
    settings = open(settings_filepath(), 'w')
    entrance_line = settings_textentrance + set_macro + '\n'
    settings.write(entrance_line)
    settings.write(settings_textinp)
    settings.write(GCFile.encode(lcodec) + '\n')

    gcfilename = os.path.basename(GCFile)
    dbname = createDB(gcfilename)
    if dbname:
        settings.write(settings_textoutp)
        settings.write(dbname.encode(lcodec) + '\n')
    else:
        return None
    
    settings.close()
    
    MessageBox('A new Openoffice.org database has been created.\n' +
               'To fill with data please run macro "fillGnuCashDB."',
               MsgType="infobox")  

def read_filepaths():
    global crout
    crout = 'read_filepaths'
    try:
        settings = open(settings_filepath(), 'r')
    except IOError:
        return []
    gcfile = ""
    dbname = ""
    for line in settings:
        lineparts = line.split(": ")
        if lineparts[0] == settings_textinp[:-2]:
            gcfile = lineparts[1].rstrip().decode(lcodec)
        elif lineparts[0] == settings_textoutp[:-2]:
            dbname = lineparts[1].rstrip().decode(lcodec)
        else:
            pass

    settings.close()
    if gcfile == "" or dbname == "":
        return []
    else:
        return [gcfile, dbname]
    
# ***********************  TABLES ooo-DB **********************************

# Three definitions for account: must be kept in sync
create_account = """CREATE TABLE ACCOUNT (
                    NAME VARCHAR(256),
                    ID VARCHAR(256),
                    TYPE VARCHAR(256),
                    DESCRIPTION VARCHAR(256),
                    PARENT VARCHAR(256))
           """
insert_account = """INSERT INTO ACCOUNT(
                    NAME, ID, TYPE, DESCRIPTION, PARENT)
                    VALUES (?, ?, ?, ?, ?)"""
##        """
def init_account():
    global crout
    crout = 'init_account'
    account0 = {}.fromkeys(['name', 'id', 'type', 'description', 'parent'], '')
    return account0


# Definitions transaction: must be kept in sync
# As many reports will evaluate on a monthly base I prefer to store
# date:year/month and date/day into separate columns
create_trn = """ CREATE TABLE TRN (
                    ID VARCHAR(256) NOT NULL,
                    NUM VARCHAR(256),
                    DESCRIPTION VARCHAR(512),
                    DATE_YM CHAR(7),
                    DATE_D CHAR(2)
)
"""
insert_trn = """INSERT INTO TRN(
        ID, NUM, DESCRIPTION, DATE_YM, DATE_D)
        VALUES (?, ?, ?, ?, ?)"""
def init_trn():
    global crout
    crout = 'init_trn'
    trn0 = {}.fromkeys(['id', 'num', 'description', 'date_ym', 'date_d'], '')
    return trn0

# Definitions for splits
create_split = """ CREATE TABLE SPLIT (
                    ID VARCHAR(256) NOT NULL,
                    TRN_ID VARCHAR(256),
                    VALUE DOUBLE,
                    QUANTITY DOUBLE,
                    ACCOUNT VARCHAR(256)
)
"""
insert_split = """INSERT INTO SPLIT(
        ID, TRN_ID, VALUE, QUANTITY, ACCOUNT)
        VALUES (?, ?, ?, ?, ?)"""
def init_split():
    global crout
    crout = 'init_split'
    split0 = {}.fromkeys(['id', 'trn_id', 'value', 'quantity', 'account'], '')
    return split0

# Definitions for acct_tree, will be completed before execution
create_accttree0 = """CREATE TABLE ACCTTREE (ID VARCHAR(256) NOT NULL"""
insert_accttree0 = """INSERT INTO ACCTTREE VALUES (?"""


def createdelete(create_statement, table_name):
    global crout
    crout = 'createdelete'
    global last_input_createdelete
##    last_input_createdelete = str(create_statement) + ' ' + str(table_name)

    try:
        Stmt.execute(create_statement)
    except:
        if table_name:
            Stmt.execute("DELETE FROM " + table_name)

def eval_fraction(cont):
    global crout
    crout = 'eval_fraction'
    global last_input_eval_fraction
##    last_input_eval_fraction = str(cont) 

    l_split = cont.split('/')
    numerator = cont.split('/')[0]
    denominator = cont.split('/')[1]
    if denominator.isdigit() and float(denominator) != 0:
        floatnumber = float(numerator) / float(denominator)
    else:
        floatnumber = 0
    return floatnumber

def accounttree():
    global crout
    crout = 'accounttree'
    accrowlist = []
    accrowdict = {}
    accrowsresult = Stmt.executeQuery("SELECT ID, PARENT, NAME, TYPE FROM ACCOUNT")
    while accrowsresult.next():
        acc = []
        for i in range(accrowsresult.Columns.Count):
            acc.append(accrowsresult.getString(i + 1))
        accrowlist.append(acc)
    for acc in accrowlist:
        accrowdict.update({acc[0]: acc[1:]})
    hierarchy = []
    maxlvl = 0
    for acc in accrowdict:
        namelist = []
        clist = accrowdict[acc]
        while clist[0]:
            namelist.append(clist[1])
            clist = accrowdict[clist[0]]
        namelist.reverse()
        maxlvl = max(maxlvl, len(namelist))
        namelist.insert(0, acc)
        hierarchy.append(namelist)
    try:
        hierarchy.sort(key=lambda l: l[1:])
    except:
        pass

    filler = []
    create_accttree = create_accttree0
    insert_accttree = insert_accttree0
    for i in range(maxlvl):
        create_accttree += ", " + "LEVEL" + str(i + 1) + " VARCHAR(256)"
        insert_accttree += ", ?"
        filler.append(' ')
    create_accttree += ')'
    insert_accttree += ')'
    createdelete(create_accttree, "ACCTTREE")
    Stmt_ins_accttree = Connection.prepareStatement(insert_accttree)
    for namelist in hierarchy:
        i = len(namelist)
        t_namelist = tuple(namelist + filler[i-1:])
        ct = 0
        for col in t_namelist:
            ct = ct + 1
            Stmt_ins_accttree.setString(ct, col)
        Stmt_ins_accttree.executeUpdate()
    createdelete("CREATE INDEX ACCTTREE_ID ON ACCTTREE (ID)", None)
    return maxlvl

def view_all_transactions(ct_lvl):
    global crout
    crout = 'view_all_transactions'
    global last_input_view_all_transactions
##    last_input_view_all_transactions = str(ct_lvl)

    def vardefs(ct_lvl = ct_lvl):
        global crout
        crout = 'vardefs'
        v2 = """"ACCTTREE"."LEVEL?"  AS "LEVEL?",
            """
        v4 = """ "LEVEL?","""
        vd2 = ""
        vd4 = ""
        for i in range(ct_lvl):
            sl = str(i + 1)
            vd2 = vd2 + v2.replace("?", sl)
            vd4 = vd4 + v4.replace("?", sl)
        vtup = (vd2, vd4)
        return vtup
        
##    viewdef = 
##    "ACCTTREE"."LEVEL1" AS "LEVEL1",
##    "ACCTTREE"."LEVEL2" AS "LEVEL2",
##    "ACCTTREE"."LEVEL3" AS "LEVEL3",
##    "ACCTTREE"."LEVEL4" AS "LEVEL4",
## "LEVEL1", "LEVEL2", "LEVEL3", "LEVEL4",
##
    viewdef1 = """CREATE VIEW ALL_TRANSACTIONS AS
    SELECT "ACCOUNT"."TYPE" AS "ACCOUNT-TYPE",
    """
    viewdef3 = """    "ACCOUNT"."NAME" AS "ACCOUNT-NAME",
    "TRN"."DATE_YM" AS "DATE_YM", "TRN".
    "DATE_D" AS "DATE_D",
    "TRN"."NUM" AS "TRN-NUMBER",
    "TRN"."DESCRIPTION" AS "DESCRIPTION",
    CAST ( "SPLIT"."VALUE" AS "DECIMAL" ) AS "VALUE"
    FROM "SPLIT", "TRN", "ACCOUNT", "ACCTTREE"
    WHERE "TRN"."ID" = "SPLIT"."TRN_ID"
    AND "ACCOUNT"."ID" = "SPLIT"."ACCOUNT"
    AND "ACCTTREE"."ID" = "SPLIT"."ACCOUNT"
    AND "SPLIT"."VALUE" != '0'
    ORDER BY"""
    viewdef5 =  """ "DATE_YM", "DATE_D",
    "TRN-NUMBER", "DESCRIPTION" """ 

    vtup = vardefs()
    viewdef2 = vtup[0]
    viewdef4 = vtup[1]

    viewdef = viewdef1 + viewdef2 + viewdef3 + viewdef4 + viewdef5

    Stmt.execute(viewdef)

#**************************** SAX / XML ***********************************

class GCContent(sax.handler.ContentHandler):

    def __init__(self):
        global crout
        crout = '__init__'
        global last_input___init__
##        last_input___init__ = str(self)

        self.account = init_account()
        self.trn = init_trn()
        self.split = init_split()
        self.tbl = ''
        self.name = ''
        self.status_date_posted = False
        self.date_posted = ''
        self.status_template_trns = False

    def startElement(self, name, attrs):
        global crout
        crout = 'startElement'
        global last_input_startElement
        last_input_startElement = str(name.encode(lcodec))

        if ':' in name:
            self.tbl = name.split(':')[0]
            self.key = name.split(':')[1]
            

    def endElement(self, name):
        global crout
        crout = 'endElement'
        global last_input_endElement
        last_input_endElement = str(name.encode(lcodec))

        def insert_statement(kind, value_dict):
            global crout
            global last_input_insert_statement
            crout = 'insert_statement'
            last_input_insert_statement = str(kind.encode(lcodec)) + ' ' + str(value_dict)
            global insert_ct
            insert_ct = insert_ct + 1
            if insert_ct >= maxmemory:
                Stmt.execute("CHECKPOINT")
                insert_ct = insert_ct - maxmemory
            if kind == 'account': 
                Stmt_ins_account.setString(1, value_dict['name'])
                Stmt_ins_account.setString(2, value_dict['id'])
                Stmt_ins_account.setString(3, value_dict['type'])
                Stmt_ins_account.setString(4, value_dict['description'])
                Stmt_ins_account.setString(5, value_dict['parent'])
                Stmt_ins_account.executeUpdate()                
            elif kind == 'trn':
                Stmt_ins_trn.setString(1, value_dict['id'])
                Stmt_ins_trn.setString(2, value_dict['num'])
                Stmt_ins_trn.setString(3, value_dict['description'])
                Stmt_ins_trn.setString(4, value_dict['date_ym'])
                Stmt_ins_trn.setString(5, value_dict['date_d'])
                Stmt_ins_trn.executeUpdate()                
            elif kind == 'split':
                Stmt_ins_split.setString(1, value_dict['id'])
                Stmt_ins_split.setString(2, value_dict['trn_id'])
                Stmt_ins_split.setDouble(3, value_dict['value'])
                Stmt_ins_split.setDouble(4, value_dict['quantity'])
                Stmt_ins_split.setString(5, value_dict['account'])
                Stmt_ins_split.executeUpdate()

        if name == 'gnc:account':
            for tup in self.account.iteritems():
                self.account[tup[0]] = tup[1].rstrip()
            if self.status_template_trns == False:
                insert_statement('account', self.account)
            self.account = init_account()
            self.tbl = ''
            self.key = ''
        elif name == 'trn:date-posted':
            self.trn['date_ym'] = self.date_posted[0:7]
            self.trn['date_d'] = self.date_posted[8:10]
            self.status_date_posted = False
            self.date_posted = ''
        elif name == 'trn:split':
            self.split['trn_id'] = self.trn['id']
            for tup in self.split.iteritems():
                self.split[tup[0]] = tup[1].rstrip()
            self.split['value'] = eval_fraction(self.split['value'])
            self.split['quantity'] = eval_fraction(self.split['quantity'])
            if self.status_template_trns == False:
                insert_statement('split', self.split)
            self.split = init_split()
            self.tbl = ''
            self.key = ''
        elif name == 'gnc:transaction':
            for tup in self.trn.iteritems():
                self.trn[tup[0]] = tup[1].rstrip()
            if self.status_template_trns == False:
                insert_statement('trn', self.trn)
            self.trn = init_trn()
            self.tbl = ''
            self.key = ''
        elif name == 'gnc:template-transactions':
            self.status_template_trns = False
        elif name == 'gnc:book':
            createdelete("CREATE INDEX ACCOUNT_ID ON ACCOUNT (ID)", None)
            createdelete("CREATE INDEX TRN_ID ON TRN (ID)", None)
            createdelete("CREATE INDEX SPLIT_ID ON SPLIT (ID)", None)
            createdelete("CREATE INDEX S_TRN_ID ON SPLIT (TRN_ID)", None)
            createdelete("CREATE INDEX S_ACCOUNT ON SPLIT (ACCOUNT)", None)

            
    def characters(self, content):
        global crout
        crout = 'characters'
        global last_input_characters
##        last_input_characters = str(self) + ' ' + str(content.encode(lcodec))

        if self.tbl == 'act':
            if self.key in self.account:
                self.account[self.key] += content
        elif self.tbl == 'trn':
            if self.key in self.trn:
                self.trn[self.key] += content
            elif self.key == 'date-posted':
                self.status_date_posted = True
        elif self.tbl == 'ts':
            if self.key == 'date' and self.status_date_posted == True:
                self.date_posted += content
        elif self.tbl == 'split':
            if self.key in self.split:
                self.split[self.key] += content
        elif self.tbl == 'gnc':
            if self.key == 'template-transactions':
                self.status_template_trns = True

# ***************************** MSGBOX / XRAY *****************************
# Show a message box with the UNO based toolkit
# This function was copied and adapted from OpenOffice.org API - Code Snippet Base
# http://codesnippets.services.openoffice.org

from com.sun.star.awt import Rectangle
from com.sun.star.awt import WindowDescriptor

from com.sun.star.awt.WindowClass import MODALTOP
from com.sun.star.awt.VclWindowPeerAttribute import OK, OK_CANCEL, YES_NO, YES_NO_CANCEL, RETRY_CANCEL, DEF_OK, DEF_CANCEL, DEF_RETRY, DEF_YES, DEF_NO

def MessageBox(MsgText, MsgTitle="GnuCash to Ooo", MsgType="messbox", MsgButtons=OK, ParentWin=None):
    global crout
    crout = 'MessageBox'
    global last_input_MessageBox
##    last_input_MessageBox = str(MsgText)

    if not ParentWin:
            doc = XSCRIPTCONTEXT.getDocument()
            try:
                ParentWin = doc.CurrentController.Frame.ContainerWindow
            except AttributeError:               
                ParentWin = doc.Frame.ContainerWindow

    
    MsgType = MsgType.lower()
    
    #available msg types
    MsgTypes = ("messbox", "infobox", "errorbox", "warningbox", "querybox")
    
    if not ( MsgType in MsgTypes ):
        MsgType = "messbox"
    
    #describe window properties.
    aDescriptor = WindowDescriptor()
    aDescriptor.Type = MODALTOP
    aDescriptor.WindowServiceName = MsgType
    aDescriptor.ParentIndex = -1
    aDescriptor.Parent = ParentWin
    #aDescriptor.Bounds = Rectangle()
    aDescriptor.WindowAttributes = MsgButtons
    
    tk = ParentWin.getToolkit()
    msgbox = tk.createWindow(aDescriptor)
    
    msgbox.setMessageText(MsgText)
    if MsgTitle :
        msgbox.setCaptionText(MsgTitle)
        
    return msgbox.execute()

##    callXray(DB)

##def callXray(obj):
##    """Macro to call Basic XRay by Bernard Marcelly from Python."""
##
### Only works if the according libraries are loaded at start of program
### See http://wiki.services.openoffice.org/wiki/Extensions_development_basic#X-Ray_tool
##
##    sURL = "vnd.sun.star.script:XRayTool._Main.Xray?language=Basic&location=application"
##
##    oMSPF = smgr.createInstanceWithContext(
##    "com.sun.star.script.provider.MasterScriptProviderFactory", ctx)
##    oMSP = oMSPF.createScriptProvider('')
##    oScript = oMSP.getScript(sURL)
##    oScript.invoke((obj,), (), ())
##
##

# ***************************** MAIN PROGRAM ******************************

def exec_fillGnuCashDB():
    """Fill OpenOffice.org database with newest GnuCash data"""
    global crout
    crout = 'exec_fillGnuCashDB'
    filepaths = read_filepaths()
    if not filepaths:
        MessageBox('Reading filepaths not successful.\n' +
            'Please run macro ' + '"' + set_macro + '"', MsgType="errorbox")
        return False
        
    gcfile = filepaths[0]
    dbname = filepaths[1]
    
    answer = MessageBox('Update database ' + dbname +'?', MsgType = "querybox", MsgButtons=YES_NO)
    if not answer == 2:          # 2 = YES, 3 = NO
        return False

    global DB, Connection, Stmt
    # get the database
    DB=Context.getByName(dbname)
    dbhandler = smgr.createInstanceWithContext(
        "com.sun.star.sdb.InteractionHandler", ctx)
    # get connection to database
    Connection=DB.connectWithCompletion(dbhandler)
    # create Statement object
    Stmt=Connection.createStatement()
    
    # create base Tables
    createdelete(create_account, "ACCOUNT")
    createdelete(create_trn, "TRN")
    createdelete(create_split, "SPLIT")
    # drop indices
    Stmt.execute("DROP INDEX ACCOUNT_ID IF EXISTS")
    Stmt.execute("DROP INDEX TRN_ID IF EXISTS")
    Stmt.execute("DROP INDEX SPLIT_ID IF EXISTS")
    Stmt.execute("DROP INDEX S_TRN_ID IF EXISTS")
    Stmt.execute("DROP INDEX S_ACCOUNT_ID IF EXISTS")
    Stmt.execute("DROP INDEX ACCTTREE_ID IF EXISTS")
    # drop derived tables
    Stmt.execute("DROP VIEW ALL_TRANSACTIONS IF EXISTS")
    Stmt.execute("DROP TABLE ACCTTREE IF EXISTS")  

    # read GnuCash Data
    try:
        f = gzip.open(gcfile)
        gcxml = f.read()
    except:
        f = open(gcfile)
        gcxml = f.read()

    global Stmt_ins_account, Stmt_ins_trn, Stmt_ins_split
    # create preparedStatement objects
    Stmt_ins_account = Connection.prepareStatement(insert_account)
    Stmt_ins_trn = Connection.prepareStatement(insert_trn)
    Stmt_ins_split = Connection.prepareStatement(insert_split)

    # parse data and insert into database
    handler = GCContent()
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    parser.feed(gcxml)
    f.close()
    ct_lvl = accounttree()
    view_all_transactions(ct_lvl)
    # write checkpoint so all tables are stored in database
    # (and not only in logfile)
    Stmt.execute("CHECKPOINT")
    DB.DatabaseDocument.store()
    # close connection   
    Connection.close()
    MessageBox('Database ' + dbname + ' has been successfully updated.',
           MsgType="infobox")

def issue_error_messages(args):
    logfile = settings_filepath()
    settings = open(logfile, 'a')
    entrance_line = '\nErrorlogging ' + time.ctime() + '\n'
    settings.write(entrance_line)
    strMsg = "Error! %s %s " % (args.__class__.__name__, args) + '\n'
    settings.write(strMsg)
    current_routine = 'current routine = ' + crout + '\n'
    settings.write(current_routine)
##    input_info = 'last input getDBFilename: ' + last_input_getDBFilename + '\n'
##    settings.write(input_info)
##    input_info = 'last input createDB: ' + last_input_createDB + '\n'
##    settings.write(input_info)
##    input_info = 'last input createdelete: ' + last_input_createdelete + '\n'
##    settings.write(input_info)
##    input_info = 'last input eval_fraction: ' + last_input_eval_fraction + '\n'
##    settings.write(input_info)
##    input_info = 'last input view_all_transactions: ' + last_input_view_all_transactions + '\n'
##    settings.write(input_info)
##    input_info = 'last input __init__: ' + last_input___init__ + '\n'
##    settings.write(input_info)
    input_info = 'last input startElement: ' + last_input_startElement + '\n'
    settings.write(input_info)
    input_info = 'last input endElement: ' + last_input_endElement + '\n'
    settings.write(input_info)
    input_info = 'last input insert_statement: ' + last_input_insert_statement + '\n'
    settings.write(input_info)
##    input_info = 'last input characters: ' + last_input_characters + '\n'
##    settings.write(input_info)
##    input_info = 'last input MessageBox: ' + last_input_MessageBox + '\n'
##    settings.write(input_info)
    strMsg = strMsg + 'For further information look into file\n' + logfile
    MessageBox(strMsg, MsgType="errorbox")
    settings.close()
    return


def fillGnuCashDB():
    global crout
    crout = 'fillGnuCashDB'
    try:
        exec_fillGnuCashDB()
    except Exception, args:
        issue_error_messages(args)
        return
    
def SetGnuCashFilePaths():
    global crout
    crout = 'SetGnuCashFilePaths'
    try:
        exec_SetGnuCashFilePaths()
    except Exception, args:
        issue_error_messages(args)
        return
    
g_exportedScripts = fillGnuCashDB, SetGnuCashFilePaths, 

