#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import sys
import string
import gtk
import gobject
import gtk.glade
try:
  import gnomecanvas 
except:
  import gnome.canvas as gnomecanvas
from gtk import RcStyle
from time import localtime, strftime

# make the path below a link to the theme you want
# example: sudo ln -s /usr/share/ldm/themes/Ubuntu /usr/share/ldm/themes/default
themedir = "/usr/share/ldm/themes/default"

class GTKGreeter:
	def run(self):
	    self.ok = False
	    self.flag = 0

	    # set default gtk theme
	    try:
	        gtk.rc_parse ('/usr/lib/ltsp/greeters/gtkrc')
	    except:
	        gtk.rc_parse ('/usr/share/themes/Clearlooks/gtk-2.0/gtkrc')
	   
	    # default settings for lang and session
	    self.language = ["Default", "None"]
	    self.session = ["Default", "None", "NOIP"]

	    # get glade widget tree
	    try:
	        self.wTree = gtk.glade.XML('/usr/lib/ltsp/greeters/greeter.glade')
	    except:
		self.wTree = gtk.glade.XML('greeter.glade')

	    # care for look and feel
	    self.set_cursor()
	    self.theme_engine()
	    self.draw_login_window()

	    # configurable options
	    # self.draw_buttons() # session and lang, should be wrapped by a config option
	    self.draw_bottom_bar(False) # set to True if you want a clock
	    self.draw_shutdown_button()

	    self.win.show_all()

	    # the entry field has focus by default
	    self.entry.grab_focus()

	    gtk.main()

	    if self.ok == True:
		print self.username
		print self.password
		#print self.session
		#print self.language
		return True
	    return False

	def draw_login_window(self):
	    # get the username/password entry from the glade tree
            self.entry = self.wTree.get_widget("entry")
            self.entry.unparent()
	    self.entry.connect("activate", lambda w: self.switch_entry(self.flag))

	    self.sq_width=250
	    self.sq_height=80
	    self.sub_height=40
	    self.root.add(gnomecanvas.CanvasRect, x1 = -(self.sq_width/2)+self.diff, 
	    		  y1 = +(self.sq_height), x2 = +(self.sq_width/2)+self.diff,
	                  y2 = +(self.sq_height*2), fill_color = self.loginwin_color)
	    self.entrylabel = self.root.add(gnomecanvas.CanvasText,
	                  markup = '<span size="10000"><b>Username:</b></span>', 
			  fill_color = self.foreground_color, x = -33+self.diff, y = 100)
	    # entry with small frame
	    self.root.add(gnomecanvas.CanvasRect, x1 = -71+self.diff, 
	    		  y1 = 114, x2 = 71+self.diff,
	                  y2 = 138, fill_color = self.frame_color)
	    self.root.add(gnomecanvas.CanvasWidget, x = -70+self.diff, y = 115, 
	     		  widget = self.entry,
	                  width = 140, height = 22)
	    self.entry.hide()

	def draw_buttons(self):
	    # get the buttons for lang and session selector from the glade tree
            lang_butt = self.wTree.get_widget("lang_button")
	    lang_butt.unparent()
            sess_butt = self.wTree.get_widget("sess_button")
	    sess_butt.unparent()
	    
	    # define the button actions
	    sess_butt.connect("clicked", lambda w: self.select_session())
	    lang_butt.connect("clicked", lambda w: self.select_language())

	    # draw the lang and session selector
	    self.root.add(gnomecanvas.CanvasRect, x1 = -(self.sq_width/2)+self.diff, 
	    		  y1 = +(self.sub_height)+125, x2 = +(self.sq_width/2)+self.diff,
	                  y2 = +(self.sub_height*2)+125, fill_color = self.loginwin_color)
	    self.root.add(gnomecanvas.CanvasWidget, x = -(self.sq_width/2)+5+self.diff, y = +(self.sub_height)+130, 
	     		  widget = lang_butt,
	                  width = 110, height = 32)
    	    self.root.add(gnomecanvas.CanvasWidget, x = -(self.sq_width/2)+135+self.diff, y = +(self.sub_height)+130, 
	     		  widget = sess_butt,
	                  width = 110, height = 32)
	    
	    # get some additional glade entrys for session and lang selector
            self.sess_box = self.wTree.get_widget("sess_vbox")
	    self.sess_box.unparent()

            self.lang_box = self.wTree.get_widget("lang_vbox")
	    self.lang_box.unparent()

	def draw_shutdown_button(self):
	    poweroff = gtk.Button('')
	    poweroff.connect("clicked", lambda w: self.shutdown())
	    try:
	        bg = gtk.gdk.pixbuf_new_from_file(themedir+'/shutdown.png')
	        img = gtk.Image()
	        img.set_from_pixbuf(bg)
	        poweroff.set_image(img)
	        poweroff.set_relief('GTK_RELIEF_NONE')
	    except:
	        poweroff.set_label('I/O')

	    self.root.add(gnomecanvas.CanvasWidget, x = -((self.width/2)-50), y = (self.height/2)+8,
                          widget = poweroff,
                          width = 46, height = 46)

	def shutdown(self):
	    os.system('poweroff -fp')

	def draw_bottom_bar(self, show_timer):
	    # draw the bottom bar, sysname and timer
	    sysname = os.uname()
	    timew = 0 
	    timeh = 0
	    
	    # get the labels from the glade tree
            self.sysname = self.wTree.get_widget("host_label")
            self.sysname.unparent()
            self.timelabel = self.wTree.get_widget("time_label")
            self.timelabel.unparent()

	    self.sysname.set_markup('<span size="12000" color="'+self.clockforeground_color+
	    			    '"><b>'+str(sysname[1])+' //</b></span>')

	    # show timer if wanted
	    if show_timer == True:
	    	    timew, timeh = self.timelabel.size_request()
		    self.timelabel.set_markup(strftime('<span size="12000" color="'+self.clockforeground_color+
	        		    '">%a %b %d, <b>%H:%M</b></span>', localtime()))
	    	    self.timer = self.root.add(gnomecanvas.CanvasWidget, x = ((self.orig_width/2)-timew), y = (self.height/2)+timeh,
	    	                  widget = self.timelabel, 
	    	                  width = timew, height = timeh)
	    	    # refresh the clock all 30 sec
	    	    gobject.timeout_add(30000, lambda: self.update_time())

	    # get label sizes for drawing
	    namew, nameh = self.sysname.size_request()

	    self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2), 
	    		  y1 = (self.height/2)+10, x2 = self.width,
			  y2 = self.height, fill_color = self.foreground_color)
	    self.root.add(gnomecanvas.CanvasWidget, x = ((self.orig_width/2)-namew-timew-10), y = (self.height/2)+nameh,
	                  widget = self.sysname, 
	                  width = namew, height = nameh)

	def theme_engine(self):
	    # draw the window with canvas
            canvas = self.wTree.get_widget("canvas")
            self.win = self.wTree.get_widget("window")
	    self.root = canvas.root().add(gnomecanvas.CanvasGroup)

	    # get screensize
	    width, self.height = gtk.gdk.get_default_root_window().get_size()
	    self.orig_width = width
	    self.width = int(float(width+(width*0.04))) # lets overlap a bit :)
	    self.diff = (self.width-self.orig_width)/2 	# to make sure the canvas
	    					   	# has no grey border

	    # Theme Engine with sane fallback values 
	    # for potentially broken themes
	    try:
	        # get the background pixmap and scale it to screenwidth
	        bg = gtk.gdk.pixbuf_new_from_file(themedir+'/background.png')
		# read colors from theme file
		colors = open(themedir+'/colors')
		colorlist = colors.readlines()

		# parse colorlist
		for color in colorlist:
			if string.find(color, "=") > 0 and not color.startswith('#'):
				val = color.split(' ')[2].rstrip().strip('"')
				if color.startswith('frame_color'):
					self.frame_color = val				
				elif color.startswith('foreground'):
					self.foreground_color = val
				elif color.startswith('background'):
					self.background_color = val
				elif color.startswith('clockforeground'):
					self.clockforeground_color = val
				elif color.startswith('loginwin_color'):
					self.loginwin_color = val
		# put background color up
		self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2),
		     	      y1 = -(self.height/2), x2 = (self.width/2),
		              y2 = (self.height/2)+self.diff, fill_color = self.background_color)
	        # put the image on the canvas
	        self.root.add(gnomecanvas.CanvasPixbuf, pixbuf = bg,
	                      x = -(bg.get_width()/2), 
			      y = -(bg.get_height()/2+40), anchor = "nw")
	    except:
		# fallback if no theme is available
		self.frame_color = "#000000"
		self.foreground_color = "#101010"
		self.clockforeground_color = "#ffffff"
		self.loginwin_color = "#606060"

		self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2),
		     	      y1 = -(self.height/2), x2 = (self.width/2),
		              y2 = (self.height/2)+self.diff, fill_color = "#303030")
		self.root.add(gnomecanvas.CanvasText,
		     	      markup = '<span size="36000"><b>No Theme Found !</b></span>\n'+
			      '<span size="10000">      Make sure the theme directorys in /usr/share/ldm/themes exist.\n'+
			      '      /usr/share/ldm/themes/default must be a symlink to the\n'+
			      '      directory containing the default theme. Please contact your\n'+
			      '      administrator to fix the ldm installation on the LTSP server.</span>',
		              fill_color = "#606060", x = self.diff, y = -50)

	    # make sure the window sits correctly on the root
	    self.win.set_size_request((self.width), (self.height))
	    self.win.set_decorated(False)

	def set_cursor(self):
	    # set cursor
	    self.rootwin = gtk.gdk.get_default_root_window()
	    self.rootwin.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))

	def update_time(self):
	    # refresh the date/time string
	    self.timelabel.set_markup(strftime('<span size="12000" color="'+self.clockforeground_color+
	    				       '">%a %b %d, <b>%H:%M</b></span>', localtime()))
	    return True
	
	def switch_entry(self, flag):
	    # switch between username and password entry, make sure neither of them is empty
	    # and exit after the password was entered.
	    if len(self.entry.get_text()) == 0:
		    return
	    self.entrylabel.destroy()
	    if flag > 0:
	    	    self.password = self.entry.get_text()
		    session = self.session[1]
		    language = self.language[1]
		    self.rootwin.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
		    self.ok = True
		    gtk.main_quit()
	    else:
	    	    self.username = self.entry.get_text()
	    self.entry.set_text('')
	    self.entrylabel = self.root.add(gnomecanvas.CanvasText,
	                  markup = '<span size="10000"><b>Password:</b></span>', 
			  fill_color = self.foreground_color, x = -33+self.diff, y = 100)
	    self.entry.set_visibility(False)
	    #self.entry.set_invisible_char('●'.e)
	    self.flag = 1

	def select_session(self):
	    # session selector - sessions should be read from a config file i.e. /etc/ldm/sessions.conf
	    # a Session entry should define the visible name (for the selector) the session manager 
	    # command that gets executed on the remote server and optionally a server ip (that gives
	    # us xdmcp functionallity for free) which falls back to the bootserver if not set.
	    # (indeed there needs to be a entry in known_hosts for a potential other server)

	    okbutton =  self.wTree.get_widget("sess_ok_button")
	    okbutton.connect("clicked", lambda w: destroy_all())

	    try: 
		self.selwin.show()
		self.sess_box.show()
	    except:
	    	self.selwin = self.root.add(gnomecanvas.CanvasWidget, x = -(100), y = 40, 
	     		  widget = self.sess_box,
	                  width = 250, height = 200)
		self.selwin.show()

	        listview =  self.wTree.get_widget("sess_treeview")
                liststore = gtk.ListStore(str, str, str)
	        listview.set_model(liststore)
	        text = gtk.CellRendererText()
	        text1 = gtk.CellRendererText()
	        text2 = gtk.CellRendererText()

	        treeselection = listview.get_selection()
	        treeselection.set_mode(gtk.SELECTION_SINGLE)

	        column = gtk.TreeViewColumn("Sessions available")

	        column.pack_start(text, False)
	        column.pack_start(text1, False)
	        column.pack_start(text2, False)
	        column.set_attributes(text, markup=1)

	        listview.append_column(column)
	        
	        liststore.append([self.session[1], self.session[0], self.session[2]])
	        # call populate function here to fill the list with:
	        # liststore.append(["Visible name", "session command to be executed", "server ip"])
		self.sess_box.show()
		listview.grab_focus()

	    def destroy_all():
		    try:
		        list,paths = treeselection.get_selected_rows()[0], treeselection.get_selected_rows()[1:]
		        name =  list[paths[0][0]][1].split('\n')
		        command =  list[paths[0][0]][0].split('\n')
		        host =  list[paths[0][0]][2].split('\n')
	    		self.session = [name, command, host]
		        self.sess_box.hide()
	    	        self.entry.grab_focus()
		    except:
			return
		    

	def select_language(self):
	    # the selection of available languages must be server dependent, we should have a file that lists 
	    # available languages for every session, what this selector shows should directly depend on the selection
	    # made in the session selector above 
	    
	    okbutton =  self.wTree.get_widget("lang_ok_button")
	    okbutton.connect("clicked", lambda w: destroy_all())
	    try: 
		self.langwin.show()
		self.lang_box.show()
	    except:
	    	self.langwin = self.root.add(gnomecanvas.CanvasWidget, x = -(100), y = -80, 
	     		  widget = self.lang_box,
	                  width = 250, height = 400)
		self.langwin.show()

	        listview =  self.wTree.get_widget("lang_treeview")
                liststore = gtk.ListStore(str, str)
	        listview.set_model(liststore)
	        text = gtk.CellRendererText()
	        text1 = gtk.CellRendererText()

	        treeselection = listview.get_selection()
	        treeselection.set_mode(gtk.SELECTION_SINGLE)

	        column = gtk.TreeViewColumn("Languages available")

	        column.pack_start(text, False)
	        column.pack_start(text1, False)
	        column.set_attributes(text, markup=1)

	        listview.append_column(column)
	        
	        liststore.append([self.language[1], self.language[0]])
		self.populate_langlist(liststore)
		self.lang_box.show()
		listview.grab_focus()
	    def destroy_all():
		    try:
		        list,paths = treeselection.get_selected_rows()[0], treeselection.get_selected_rows()[1:]
		        name =  list[paths[0][0]][1].split('\n')
		        language =  list[paths[0][0]][0].split('\n')
			self.language = [name, language]
		        self.lang_box.hide()
	    	        self.entry.grab_focus()
		    except:
			return
	
	def populate_langlist(self, liststore):
		try:
	            languages = open('/etc/locale.alias')
	            langlist = languages.readlines()
	            for language in langlist:
	    	        if not language.startswith('#'):
	    	            if string.find(language, "\t"):
            	                lang = language.split('\t')
	    	            else:
            	                lang = language.split(' ')
	    	        
	    	            if len(lang) < 2:
	    	                tmp = lang[0].split(' ')
	    	                lang = tmp
			    if len(lang[0]) > 1:
			        try:
			            if lang[0].find("_") == -1:
					nat, encoding = lang[-1].rstrip().split('.')
					if encoding.startswith('ISO'):
					    encoding = nat
					else:
					    encoding = nat+'.'+encoding
					# add a check for langs supported by the selected session
					liststore.append([encoding, lang[0].capitalize().encode()])
			        except:
				    # do nothing
				    failed_langs = []
				    failed_langs.append(lang[0])
		except:
		   return

if not GTKGreeter().run():
	    sys.exit(1)
