#!/usr/bin/python

## odf-converter integrator
## Copyright (c) 2008 by Andrew Ziem.  All rights reserved.
## http://katana.oooninja.com/w/odf-converter-integrator

## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
## 
## 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 General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.



import sys
import os
import os.path
#from _winreg import *
import subprocess
if sys.platform=='win32':
	import EasyDialogs
	from ctypes import c_int, WINFUNCTYPE, windll
	from ctypes.wintypes import HWND, LPCSTR, UINT


def running_kde():
	"Detect whether KDE is running"
	#ref: http://techbase.kde.org/index.php?title=KDE_System_Administration/Environment_Variables#KDE_FULL_SESSION
	return 	len(os.getenv("KDE_FULL_SESSION",""))>0

def my_subprocess_call(args):
	"Attempt to run a program.  Convenience function"
	try:
		print "debug: trying ", args
		r = subprocess.call(args)
		if r > 0:
			raise "non-zero exit code: ", r
		return True
	except:
		# exception usually indicates program not found
		return False

def my_subprocess_backtick(args):
	"Attempt to run a program and return any output.  Convenience function"
	try:
		print "debug: trying ", args
		return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
	except:
		return False

def linux_file_open_dialog ():
	zenity_args = ["zenity", "--title=\"Select a Microsoft Office 2007 file to convert and open\"", "--file-selection"]
	kdialog_args = ["kdialog", "--title=\"Select a Microsoft Office 2007 file to convert and open\"", "--getopenfilename", "~"]

	if running_kde():
		all_args = [kdialog_args, zenity_args]	
	else:
		all_args = [zenity_args, kdialog_args]	

	for args in all_args:
		output = my_subprocess_backtick(args)
		if False != output:
			if len(output.strip())==0:
				return None
			return output.replace("\n","")

	handle_fatal_error("No way to ask you a file name because zenity and kdialog not available")


def linux_msgbox (title, body):

	#fixme: zenity: set icon warning vs error
	zenity_args = ["zenity", "--warning", "--text=" + body, "--title=" + title] # GTK
	kdialog_args = ["kdialog", "--msgbox", body]                                # KDE
	
	if running_kde():
		all_args = [kdialog_args, zenity_args]
	else:
		all_args = [zenity_args, kdialog_args]
	
	all_args.append(["xmessage", "-center", body]) # X11

	#fixme: notify-send set icon warning vs error
	all_args.append(["notify-send", "-t", "5000", body])

	for args in all_args:
		if my_subprocess_call(args):
			return

	handle_fatal_error("cannot notify via GUI")


def x_msgbox ( title, body ):
	"""Abstract, cross-platform, GUI message box"""
	if sys.platform=="win32":
		prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
		paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
		MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
		MessageBox(text=body, caption=title + " [odf-converter-integrator]")
	elif sys.platform=="linux2":
		linux_msgbox(title, body)
	else:
		print "fixme x_msgbox"



def linux_open_document ( fn ):
	"""In Linux open a document with attempt to honor user's preferred application"""

	# safe assumption
	if os.getenv("DISPLAY")==None:
		handle_fatal_error ("Cannot display document without a GUI")
		return

	xdg_args = ["xdg-open", fn]		# freedesktop.org
	kde_args = ["kfmclient", "exec", fn]	# KDE, success=0, fail=1
	gnome_args = ["gnome-open", fn]		# GNOME, success=0, fail=1

	if running_kde():
		all_args = [xdg_args, kde_args, gnome_args]
	else:
		all_args = [xdg_args, gnome_args, kde_args]

	x="openoffice.org openoffice ooffice soffice openoffice.org3.0 openoffice.org2.4 openoffice.org2.3 openoffice.org2.2 openoffice.org2.1 openoffice.org2.0 abiword kword"
	for exe in x.split(" "):
		all_args.append([exe,fn])

	for args in all_args:
		if my_subprocess_call(args):
			return
		
	# fixme: prompt user for application path
	handle_fatal_error ("I don't have a way to open the file")


def x_file_open_dialog():
	"""Abstract, cross-platform file open dialog"""
	if sys.platform=="win32":
		return EasyDialogs.AskFileForOpen()
	elif sys.platform=="linux2":
		return linux_file_open_dialog()
	raise "Unknown platform"

def x_open_document(fn):
	"""Abstract, cross-platform method for opening documents using preferred application"""
	if sys.platform=="win32":
		try:
			os.startfile(fn)
			# fixme: startfile does not check results??
		except WindowsError, e:
			handle_fatal_error("Could not open with preferred application open document. "+str(e))
	elif sys.platform=="linux2":
		linux_open_document(fn)
	else:
		raise "Unknown platform"

def handle_fatal_error ( msg ):
	print "odf-converter-integrator: error: " + msg
	x_msgbox ("Fatal error", msg)
	#raise msg
	sys.exit(1)

def handle_warning ( msg ):
	print "odf-converter-integrator: warning: " + msg
	x_msgbox ("Warning", msg)
	print msg

def convert_filename(old_doc):
	(root, old_ext) = os.path.splitext(old_doc)
	old_ext = old_ext[1:] # remove the period
	ext_map = {'docm': 'odt', 'docx': 'odt', 'dotm': 'odt', 'dotx': 'odt', 'potm': 'odp', 'potx': 'odp', 'ppam': 'odp', 'ppsm': 'odp', 'ppsx': 'odp', 'pptm': 'odp', 'pptx': 'odp', 'xlam': 'ods', 'xlsb': 'ods', 'xlsm': 'ods', 'xlsx': 'ods', 'xltm': 'ods', 'xltx': 'ods'}
	try:
		new_ext = ext_map[old_ext]	
	except:
		handle_fatal_error("Invalid extension: " + old_ext)
	print "debug: new_ext ="+new_ext
	new_doc = root + "." + new_ext
	return new_doc

def find_odfconverter():
	short_exe=None
	if sys.platform=="linux2":
		short_exe="OdfConverter"
	elif sys.platform=="win32":
		short_exe="OdfConverter.exe"
	else:
		raise "Unknown operating system"
	print "debug me path="+sys.argv[0]
	print "debug path="+os.path.dirname(sys.argv[0])
	# first, guess the Python script's directory
	full_exe = os.path.join(os.path.dirname(sys.argv[0]), short_exe)
	if os.path.exists(full_exe):
		return full_exe
	# the standard install for Windows
	full_exe = "c:\\program files\\odf-converter-integrator\\odfconverter.exe"
	if os.path.exists(full_exe):
		return full_exe
	# standard install for Linux
	if sys.platform=="linux2":
		# this passes on Wine!?
		full_exe = "/usr/bin/OdfConverter"
		if os.path.exists(full_exe):
			return full_exe
	# maybe the OS can find it in the path
	return short_exe
	

def convert(old_doc):
	if not os.path.exists(old_doc):
		handle_fatal_error("Source document does not exist: " + old_doc+">")
	new_doc = convert_filename(old_doc)
	if os.path.exists(new_doc):
		handle_warning("New document already exists: '" + new_doc+"'")
	else:
		exe = find_odfconverter() 
		print "debug: convert: exe = " + exe
		try:
			rc = subprocess.call([exe, "/I", old_doc, "/O", new_doc, "/LEVEL","3"])
			if rc != 0:
				handle_warning( "convert: OdfConverter returned rc = " + str(rc))
		except WindowsError, e:
			handle_fatal_error("OdfConverter failed probably because it could not be found." + str(e))
		if not os.path.exists(new_doc):
			handle_fatal_error("Converted file did not materialize: " + new_doc)
	#FIXME check results of conversion
	x_open_document(new_doc)

def oci_main():
	if len(sys.argv[1:])==0:
		old_doc=x_file_open_dialog()
		if None==old_doc:
			print "Aborted by user"
			return
		convert(old_doc)
	elif len(sys.argv[1:]) > 1:
		# FIXME: iterate
		handle_fatal_error("You passed too many command line parameters")
	else:
		convert(sys.argv[1])


oci_main()
