#! /usr/bin/env python
#
# Copyright (C) 2005 Thomas Sonne Olesen
# Email : tpso@bigfoot.com
# 	   
# 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 2 
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#

import gtk
import gtk.glade
import gobject
import string
import re
import ConfigParser
import os
import os.path
import sys


version  = "0.4.3"
progname = "pyblink"
                                                                                
pyblio = "no"

pyblinkdir = "/usr/share/pyblink"
gladedir = pyblinkdir + "/glade"

sys.path.insert (0, pyblinkdir)

clip_data = ""
CURRENT_TIME = 0L
allRefs = {}
bibfile = ""
config = ConfigParser.ConfigParser()


# Handle input from pybliographer
#
def newReference(a,b):
    global clip_data
    global allRefs
    buf = os.read(pybinput,100)
    buf = string.rstrip(buf)
    m = re.search('LYXCMD:pyblio:citation-insert:(.*)$', buf)
    if m:
        ref = m.group(1)
        clip_data = ref
        mainWid['wPyblink'].selection_owner_set("PRIMARY", CURRENT_TIME)
        mainWid['wPyblink'].selection_owner_set("CLIPBOARD", CURRENT_TIME)

        mainWid['entryReference'].set_text(buf)

	ckeys = string.split (ref, ', ')
        for sk in ckeys:
            if ( not allRefs.get(sk,False) ):
	        reflist.addRef(sk)
                reflist.save()
    
    return gtk.TRUE    # requeue for more input


class reflistStore(gtk.ListStore):

    myFilename = "unknown.rl"

    def __init__(self):
 	gtk.ListStore.__init__(self,gobject.TYPE_STRING)
	self.data = []
	self.setFilename('unknown.rl')

    def loadfile(self,filename):
	global allRefs, bibfile
	fd = open(filename,"r")
	allRefs = {}
	content = fd.readlines()
	for ref in content:
	    ref = string.rstrip(ref)
    	    m = re.match( '^---bibfile=(.*)$', ref)
	    if m:
		bibfile = m.group(1)
	    else:
		self.addRef(ref)
	fd.close()
	self.setFilename(filename)

    def addRef(self, ref):
	iter = self.append ()
	self.set (iter, 0, ref)
	allRefs[ref] = True

    def setFilename(self, fn):
	self.myFilename = fn
        mainWid['lblHeader'].set_text('Current references in %s' % os.path.basename(fn))

    def save(self):
	global allRefs, bibfile
	fd = open(self.myFilename,"w")
        config.set("files","last",self.myFilename)
	fd.write("---bibfile=%s\n" % bibfile)

	SaveBasedOnListStore = False
	if (SaveBasedOnListStore):
	    # This should work, but fails on some pygtk versions
	    iter = reflist.get_iter_first() 
	    while ( iter ):
	        r = reflist.get_value(iter,0)
	        fd.write("%s\n" % r)
	        iter = reflist.iter_next(iter) 
	else:
	    # Simple list based on keys from the allRef dictionary
	    a = allRefs.keys()
	    a.sort()
	    # for r in allRefs.keys().sort():
	    for r in a:
	        fd.write("%s\n" % r)
	
		
	fd.close()

	
def cleanup():
    gtk.mainquit()
    fd = open(os.path.expanduser('~/.pyblink'),"w")
    config.write(fd)
    fd.close()


# The WidgetWrapper class, that handles the glade based widgets
#
class WidgetsWrapper:

    def __init__(self, gladefile,windowname,handlers):
        self.widgets = gtk.glade.XML (gladefile,windowname)
        self.widgets.signal_autoconnect(handlers.__dict__)
	self.data = []

    # Gives us the ability to do: widgets['widget_name'].action()
    def __getitem__(self, key):
        return self.widgets.get_widget(key)


# Handlers for the File selection
#
class savefileHandler:

    def setFilename(self,fn):
        global reflist
        reflist.setFilename(fn)
        reflist.save()
        return True


class openfileHandler:

    def setFilename(self,fn):		# Callback for open file dialog
        global reflist
        reflist = reflistStore()
        reflist.loadfile(fn)
        mainWid['lstReferences'].set_model(reflist)
	return True

class newfileHandler:

    def setFilename(self,fn):		# Callback for new file dialog
        global reflist, allRefs
        if os.access(fn,os.F_OK):
            MessageBox('Warning','    File already exists    ')
	    return False
	else:
            reflist = reflistStore()
	    allRefs = {}
	    reflist.setFilename(fn)
            mainWid['lstReferences'].set_model(reflist)
            return True


class fileDialog:

    def __init__(self,title,callback):
        global gladefile
        self.widgets = gtk.glade.XML (gladefile,'openfileselection')
        self.widgets.signal_connect('on_ok_button_clicked',self.on_ok_button_clicked)
        self.widgets.signal_connect('on_cancel_button_clicked',self.on_cancel_button_clicked)
        self.callback = callback
        self['openfileselection'].set_title(title)

    def on_ok_button_clicked(self,event):
        if self.callback.setFilename( self['openfileselection'].get_filename() ):
            self['openfileselection'].destroy()

    def on_cancel_button_clicked(self,event):
        self['openfileselection'].destroy()

    def __getitem__(self, key):
        return self.widgets.get_widget(key)


class MessageBox:

    def __init__(self, mtype, txt, txt2=''):
        global gladefile
        self.widgets = gtk.glade.XML (gladefile,'MessageBox')
        self.widgets.signal_connect('on_ok_button_clicked',self.on_ok_button_clicked)
        self['MessageType'].set_text(mtype)
        self['MessageText'].set_text(txt)

    def on_ok_button_clicked(self,event):
        self['MessageBox'].destroy()

    # Gives us the ability to do: widgets['widget_name'].action()
    def __getitem__(self, key):
        return self.widgets.get_widget(key)


class AboutBox:

    def __init__(self):
	global gladefile
        self.widgets = gtk.glade.XML (gladefile,'AboutBox')
        self.widgets.signal_connect('on_ok_button_clicked',self.on_ok_button_clicked)
        self['AboutBox'].set_title('About Pyblink ' + version)
	self.data = []

    def on_ok_button_clicked(self,event):
        self['AboutBox'].destroy()

    # Gives us the ability to do: widgets['widget_name'].action()
    def __getitem__(self, key):
        return self.widgets.get_widget(key)


class GenerateDialog:

    def __init__(self):
        global gladefile
        self.widgets = gtk.glade.XML (gladefile,'GenerateDialog')
        self.widgets.signal_connect('on_ok_button_clicked',self.on_ok_button_clicked)
        self.widgets.signal_connect('on_cancel_button_clicked',self.on_cancel_button_clicked)
        self.widgets.signal_connect('on_GenerateBrowse_clicked',self.on_GenerateBrowse_clicked)
        self.data = []
	if config.has_option("generate","bibfile"):
            self['GenerateDB'].set_text(config.get("generate","bibfile"))
	else:
            self['GenerateDB'].set_text('')
        if config.has_option("generate","format"):
            self['optmFormat'].set_history( string.atoi(config.get("generate","format")) )
        else:
            self['optmFormat'].set_history( 1 )
        if config.has_option("generate","format"):
            self['optmStyle'].set_history( string.atoi(config.get("generate","style")) )
        else:
            self['optmStyle'].set_history( 1 )

    def on_ok_button_clicked(self,event):
        global reflist, bibfile
        bibfile = self['GenerateDB'].get_text()
        style = self['optmStyle'].get_history()
        format = self['optmFormat'].get_history()

        config.set("generate","bibfile",bibfile)
        config.set("generate","format","%d" % format)
        config.set("generate","style","%d" % style)

        format_str = ['HTML', 'LaTex', 'Raw', 'Text', 'Textnum', 'Textau'][format]
	style_str = ["Abbrev", "Alpha", "apa4e", "abbrvbib", "abbrvnum", "abbrvau"][style]

        pyblinkformat = pyblinkdir + "/pyblinkformat.py"
        outputfile = os.path.splitext(reflist.myFilename)[0]
        outputfile = outputfile + "." + string.lower(format_str)
        os.system(pyblio + " --quiet " + pyblinkformat + " -s " + style_str + " -f " + format_str + " -o " + outputfile + " -i " + reflist.myFilename + " " + bibfile)
        self['GenerateDialog'].destroy()

    def on_GenerateBrowse_clicked(self,event):
        fileDialog("Select bibliography database file",self)

    def on_cancel_button_clicked(self,event):
        self['GenerateDialog'].destroy()

    def setFilename(self,fn):
        self['GenerateDB'].set_text(fn)
        return True

    # Gives us the ability to do: widgets['widget_name'].action()
    def __getitem__(self, key):
        return self.widgets.get_widget(key)


# Handlers for the main window
#
class mainGladeHandlers:

    def on_btnQuit_clicked(event):
        cleanup()

    def on_wPyblink_destroy(a,b):
        cleanup()

    def on_wPyblink_delete(a,b):
        cleanup()

    def on_btnSetSel_clicked(event):
        if mainWid['wPyblink'].selection_owner_set("PRIMARY", CURRENT_TIME):
            print "got the selection ownership"
        else:
            print "ownership failed"

    def on_wPyblink_selection_get(w, data, *args):
        global clip_data
        data.set("STRING"
             , 8
             , '[%s]' % clip_data
             )

    def on_newFile_activate(self, mi=None):
        fileDialog("Enter a new filename ...",newfileHandler())

    def on_openFile_activate(self, mi=None):
        fileDialog("Select reference file to open ...",openfileHandler())

    def on_saveFile_activate(self, mi=None):
        global reflist
        reflist.save()

    def on_saveAsFile_activate(self, mi=None):
        fileDialog("Select new file to save in ...",savefileHandler())

    def on_generate_referencelist_activate(self, mi=None):
        GenerateDialog()

    def on_about_activate(self, mi=None):
        AboutBox()


# Initialization
#
config.read (os.path.expanduser('~/.pyblink'))
if not config.has_section ("config"):
    config.add_section ("config")
if not config.has_section ("files"):
    config.add_section ("files")
if not config.has_section ("generate"):
    config.add_section ("generate")
if not config.has_option ("config","lyxpipe"):
    config.set ("config","lyxpipe",os.path.expanduser('~/.lyx/lyxpipe'))

# checking lyxpipe
lyxdir = os.path.expanduser('~/.lyx')
if not os.path.exists(lyxdir):
    os.mkdir(lyxdir, 0755)
    os.mkfifo(lyxdir + "/lyxpipe.in", 0644)
    os.mkfifo(lyxdir + "/lyxpipe.out", 0644)
else:
    if os.path.isfile(lyxdir):
        os.mkdir(lyxdir, 0755)
        os.mkfifo(lyxdir + "/lyxpipe.in", 0644)
        os.mkfifo(lyxdir + "/lyxpipe.out", 0644)
    else:
        if not os.path.exists(lyxdir + "/lyxpipe.in"):
              os.mkfifo(lyxdir + "/lyxpipe.in", 0644)

        if not os.path.exists(lyxdir + "/lyxpipe.out"):
              os.mkfifo(lyxdir + "/lyxpipe.out", 0644)

        
gladefile = gladedir + "/pyblink.glade"

mainWid = WidgetsWrapper(gladefile,'wPyblink',mainGladeHandlers)
mainWid['wPyblink'].selection_add_target("PRIMARY", "STRING", 1)
mainWid['wPyblink'].selection_add_target("CLIPBOARD", "STRING", 1)

pybinput = os.open (config.get('config','lyxpipe') + '.in', os.O_RDWR|os.O_NONBLOCK)
pyboutput = os.open (config.get('config','lyxpipe') + '.out', os.O_RDWR|os.O_NONBLOCK|os.O_NDELAY)
gtk.input_add(pybinput,gtk.gdk.INPUT_READ, newReference)

# Prepare list view for all references
reflist = reflistStore()
if len(sys.argv) > 1:
    reflist.loadfile(sys.argv[1])
else:
    if (config.has_option("files","last") and os.path.exists(config.get("files", "last"))):
        try:
            reflist.loadfile(config.get("files","last"))
        except IOError, err:
            sys.stderr.write ("Warning: cannot load last file: %s\n" % err)


mainWid['lstReferences'].set_model(reflist)
renderer = gtk.CellRendererText ()
column = gtk.TreeViewColumn ('ref', renderer, text=0)
mainWid['lstReferences'].append_column (column)
fsWid = None


gtk.mainloop ()
