#!/usr/bin/env python
#@+leo-ver=4
#@+node:@file leopm_client.py
#@@first #!/usr/bin/env python

"""A client implementing a plug-in manager for Leo

The client is based on an XML server architecture. Methods exist
to query the plug-ins on the server, find version numbers, help information and
to download the actual source. In the future it might be possible to upload
plug-ins as well."""

from Tkinter import *
import os,re,xmlrpclib

__version__ = "0.1"

PORT = 8001 # The port the server is listening on
HOST = "http://localhost:%d" % PORT
ROOTDIR = r"c:\temp" # Where the plugins will end up

#@+others
#@+node:class LeoPMClient
class LeoPMClient:
	
	"""The client to talk to the LeoPM server"""

	#@	@+others
	#@+node:__init__
	def __init__(self, master, server, rootdir):
	    """Initialize the client"""
	    self.server = server
	    self.master = master
	    self.rootdir = rootdir
	    #
	    frame = Frame(master)
	    frame.pack()
	    #
	    l = Label(frame, text="Leo Plugin Manager")
	    l.pack(side=TOP)
	    # Get the list of plugins
	    listbox = Listbox(frame)
	    listbox.pack(side=TOP)
	    self.listbox = listbox
	    self.initListbox()
	    # Detail box for additional information
	    text = Text(frame)
	    text.pack(side=TOP)
	    self.text = text
	    #
	    buttonframe = Frame(frame)
	    buttonframe.pack(side=BOTTOM)
	    #
	    quit = Button(buttonframe, text="QUIT", fg="red", command=master.quit)
	    quit.pack(side=RIGHT)
	    #
	    download = Button(buttonframe, text="Download", command=self.downloadPlugin)
	    download.pack(side=LEFT)
	    # Start polling for changes in selection
	    self.lastselection = None
	    self.poll() 
	#@nonl
	#@-node:__init__
	#@+node:poll
	def poll(self):
	    """Poll and update the detail view if appropriate"""
	    now = self._getSelectedPluginName()
	    if now is not None and now != self.lastselection:
	        self.updateDetail(now)
	        self.lastselection = now
	    self.master.after(250, self.poll)
	#@-node:poll
	#@+node:_getSelectedPluginName
	def _getSelectedPluginName(self):
	    """Return the currently selected plugin name"""
	    sel = self.listbox.curselection()
	    if sel:
	        return self.plugins[int(sel[0])]
	    else:
	        return None
	#@-node:_getSelectedPluginName
	#@+node:updateDetail
	def updateDetail(self, name):
	    """Update the detail view of a plugin"""
	    self.text.delete(1.0, END)
	    self.text.insert(END, self.server.getPluginDescription(name))
	#@-node:updateDetail
	#@+node:downloadPlugin
	def downloadPlugin(self):
	    """Download the selected plugin"""
	    self.text.insert(END, "\n\nInstalling\n")
	    data = self.server.getPlugin(self._getSelectedPluginName())
	    self.text.insert(END, "Got plugin data\n")
	    for filename, text in data:
	        self.text.insert(END, "Copying file '%s' ..." % filename)
	        f = file(os.path.join(self.rootdir, filename), "w")
	        f.write(text)
	        f.close()
	        self.text.insert(END, "Done!\n")
	    self.text.insert(END, "\n\nPlugin installed\n")
	    self.initListbox()
	#@-node:downloadPlugin
	#@+node:getPluginList
	def getPluginList(self):
	    """Return a list of plugins on the server
	    
	    We markup the list to show which plugins are installed etc
	    
	    """
	    ret = []
	    self.plugins = server.getPluginNames()
	    for name in self.plugins:
	        version = server.getPluginVersion(name)
	        files = server.getPluginFilenames(name)
	        #
	        found = 0
	        version = None
	        #
	        for fname in files:
	            # Is file already installed?
	            filename = os.path.join(self.rootdir, fname)
	            if os.path.isfile(filename):
	                found += 1
	                # Check version
	                version = version or self.getVersionOfFile(filename)
	        #
	        if found == len(files):
	            version = version or "Unknown"
	            ret.append("%s - installed (v%s)" % (name, version))
	        elif found:
	            ret.append("%s - partially installed" % name)
	        else:
	            ret.append(name)
	    #
	    return ret
	#@-node:getPluginList
	#@+node:initListbox
	def initListbox(self):
	    """Initialize the listbox"""
	    plugin_list = self.getPluginList()
	    self.listbox.delete(0, END)
	    for item in plugin_list:
	        self.listbox.insert(END, item)
	#@-node:initListbox
	#@+node:getVersionOfFile
	def getVersionOfFile(self, filename):
	    """Check the version of a plugin file"""
	    ver = re.compile('.*__version__\s*=\s"(.*?)".*', re.DOTALL+re.MULTILINE)
	    f = file(filename, "r")
	    text = f.read()
	    f.close()
	    match = ver.match(text)
	    if match:
	        return match.groups()[0]
	    else:
	        return None
	#@-node:getVersionOfFile
	#@-others
#@-node:class LeoPMClient
#@-others

if __name__ == "__main__":
    server = xmlrpclib.ServerProxy(HOST)
    root = Tk()
    client = LeoPMClient(root, server, ROOTDIR)
    root.mainloop()
#@-node:@file leopm_client.py
#@-leo
