#! /usr/bin/python
# -*- coding: UTF-8 -*-
#    TcosMonitor version 0.2.49
#
# Copyright (c) 2006-2011 Mario Izquierdo <mariodebian@gmail.com>
#
# This package 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 package 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


import sys
import os
import glob

import pygtk
pygtk.require('2.0')
import gtk

from tcosmonitor import shared


from time import time
import getopt
from gettext import gettext as _

import gobject
import grp


debug_name="tcospersonalize"

PXELINUX_CFG=[
    "default __TCOS_METHOD__",
    "prompt 0",
    "timeout 50",
    "label default",
    "  kernel vmlinuz-__TCOS_KERNEL__",
    "  append ramdisk_size=65536 boot=tcos root=/dev/ram0 initrd=initramfs-__TCOS_KERNEL__ __TCOS_CMDLINE__",
    "label nfs",
    "  kernel vmlinuz-__TCOS_KERNEL__",
    "  append ramdisk_size=32768 boot=tcos root=/dev/ram0 initrd=initramfs-__TCOS_KERNEL__-nfs forcenfs __TCOS_CMDLINE__",
    "",
    "#kernel=__TCOS_KERNEL__",
    "#method=__TCOS_METHOD__",
    "#cmdline='__TCOS_CMDLINE__'",
]

PXE_METHODS=[
"default",
"nfs"
]

PXELINUX_CMDLINE="quiet splash"

def print_debug(txt):
    if shared.debug:
        print >> sys.stderr, "%s::%s" % (debug_name, txt)
        #print("%s::%s" % (debug_name, txt), file=sys.stderr)

    return

def crono(start, txt):
    print_debug ("crono(), %s get %f seconds" %(txt, (time() - float(start))) )
    return

def usage():
    print ("TcosPersonalize help:")
    print ("")
    print ("   tcospersonalize [--host=XXX.XXX.XXX.XXX]   (host to personalize)")
    print ("   tcospersonalize -d [--debug]  (write debug data to stdout)")
    print ("   tcospersonalize -h [--help]   (this help)")


try:
    opts, args = getopt.getopt(sys.argv[1:], ":hd", ["help", "debug", "host="])
except getopt.error, msg:
    print (msg)
    print ("for command line options use tcosconfig --help")
    sys.exit(2)

# process options
for o, a in opts:
    if o in ("-d", "--debug"):
        print ("DEBUG ACTIVE")
        shared.debug = True
    if o == "--host":
        print ("HOST %s" % a)
        shared.remotehost = a
    if o in ("-h", "--help"):
        usage()
        sys.exit()


class TcosPersonalize:
    def __init__(self):
        print_debug ( "__init__()" )
        self.name="TcosPersonalize"
        # exit if no host
        if shared.remotehost == None:
            usage()
            shared.error_msg ( _("Need a host to configure!!!\nTry exec:\n tcospersonalize --host=XXX.XXX.XXX.XXX") )
            sys.exit(1)
        
        nogroup=True
        for group in os.getgroups():
            if grp.getgrgid(group)[0] == "tcos":
                nogroup=False
        
        if nogroup and os.getuid() != 0:
            shared.error_msg( "You must be root to exec tcospersonalize." )
            sys.exit(1)
        
        self.remotehost_config = os.path.join ("/var/lib/tcos/tftp/conf/", shared.remotehost + ".conf" )
        
        # Widgets
        import gettext
        gettext.bindtextdomain(shared.PACKAGE, shared.LOCALE_DIR)
        gettext.textdomain(shared.PACKAGE)
        
        print_debug("loading %s" %(shared.GLADE_DIR + 'tcospersonalize.ui'))
        
        self.ui = gtk.Builder()
        self.ui.set_translation_domain(shared.PACKAGE)
        
        self.ui.add_from_file(shared.GLADE_DIR + 'tcospersonalize.ui')
        
        
        self.main = self.ui.get_object('mainwindow')

        # close windows signals
        self.main.connect('destroy', self.quitapp )
        
        # buttons
        self.buttonok=self.ui.get_object('ok_button')
        self.buttoncancel=self.ui.get_object('cancel_button')
        self.buttondelete=self.ui.get_object('delete_button')
        self.buttongetavalaible=self.ui.get_object('getavalaible_button')
        
        # signals on buttons
        self.buttonok.connect('clicked', self.on_buttonok_click )
        self.buttoncancel.connect('clicked', self.on_buttoncancel_click )
        self.buttondelete.connect('clicked', self.on_buttondelete_click )
        self.buttongetavalaible.connect('clicked', self.on_buttongetavalaible_click )
        
        # get combos
        self.combo_xsession=self.ui.get_object('combo_xsession')
        self.combo_xdriver=self.ui.get_object('combo_xdriver')
        self.combo_xres=self.ui.get_object('combo_xres')
        self.combo_xdepth=self.ui.get_object('combo_xdepth')
        
        # get checkboxes
        self.ck_xmousewheel=self.ui.get_object('ck_xmousewheel')
        self.ck_xdontzap=self.ui.get_object('ck_xdontzap')
        self.ck_xdpms=self.ui.get_object('ck_xdpms')
        
        # get textboxes
        #self.text_extramodules=self.ui.get_object('txt_extramodules')
        self.text_xhorizsync=self.ui.get_object('txt_xhorizsync')
        self.text_xvertsync=self.ui.get_object('txt_xvertsync')
        
        # boot options
        self.combo_kernel=self.ui.get_object('combo_kernel')
        self.combo_method=self.ui.get_object('combo_method')
        self.text_cmdline=self.ui.get_object('txt_cmdline')
        self.buttonapply=self.ui.get_object('apply_button')
        self.buttonapply.connect('clicked', self.on_buttonapply_click )
        
        self.deleteboot=self.ui.get_object('delete_boot_button')
        self.deleteboot.connect('clicked', self.on_deleteboot_click )
        
        # host label
        self.hostlabel=self.ui.get_object('label_host')
        self.hostlabel.set_markup ( "<b>" + _("host: ") + shared.remotehost + "</b>" )
        
        # get conf file
        self.vars=[]
        self.OpenFile()
        
        found=False
        for var in self.vars:
            if var[0] == "xdisablesync":
                found=True
        if not found:
            print_debug("adding xdisablesync....")
            self.vars.append(["xdisablesync", ""])
        
        # populate combos
        self.populate_select(self.combo_xsession, shared.xsession_values )
        self.set_active_in_select(self.combo_xsession, self.GetVar("xsession") )
        
        self.populate_select(self.combo_xdriver, shared.xdriver_values )
        self.set_active_in_select(self.combo_xdriver, self.GetVar("xdriver") )
        
        #self.populate_select(self.combo_xdriver, ['auto'] )
        #self.set_active_in_select(self.combo_xdriver, "\"auto\"" )
        
        self.populate_select(self.combo_xres, shared.xres_values )
        self.set_active_in_select(self.combo_xres, self.GetVar("xres")  )
        
        self.populate_select(self.combo_xdepth, shared.xdepth_values )
        self.set_active_in_select(self.combo_xdepth, self.GetVar("xdepth") )
        
        # populate checkbox
        #self.populate_checkboxes( self.ck_xmousewheel, 1)
        #self.populate_checkboxes( self.ck_xdontzap, 1)
        #self.populate_checkboxes( self.ck_xdpms, 1)
        
        self.populate_checkboxes( self.ck_xmousewheel, self.GetVar("xmousewheel") )
        self.populate_checkboxes( self.ck_xdontzap, self.GetVar("xdontzap") )
        self.populate_checkboxes( self.ck_xdpms, self.GetVar("xdpms") )
        
        self.populate_textboxes( self.text_xhorizsync, self.GetVar("xhorizsync") )
        self.populate_textboxes( self.text_xvertsync, self.GetVar("xvertsync") )
        
        kernels=self.getkernels()
        
        self.bootfilename=self.get_hexfilename(shared.remotehost)
        self.bootparams={'kernel':'', 'method':'default', 'cmdline':'quiet splash'}
        
        if os.path.isfile(self.bootfilename):
            f=open(self.bootfilename, 'r')
            for line in f.readlines():
                if line.startswith("#kernel"):
                    self.bootparams['kernel']=line.split('=')[1].strip()
                if line.startswith("#method"):
                    self.bootparams['method']=line.split('=')[1].strip()
                if line.startswith("#cmeline"):
                    self.bootparams['cmdline']=line.split('=')[1].strip()
            f.close()
            self.deleteboot.set_sensitive(True)
        else:
            if len(kernels) == 1:
                self.bootparams['kernel']=kernels[0]
            else:
                self.buttonapply.set_sensitive(False)
                self.combo_kernel.connect('changed', self.on_combo_kernel_change)
            self.deleteboot.set_sensitive(False)
        
        self.populate_select(self.combo_kernel, kernels )
        self.set_active_in_select(self.combo_kernel, self.bootparams['kernel']  )
            
        
        self.populate_select(self.combo_method, PXE_METHODS )
        self.set_active_in_select(self.combo_method, self.bootparams['method']  )
        self.text_cmdline.set_text(PXELINUX_CMDLINE)
        
        # populate textboxes
        # NOTHING
        
        self.issaved=False
        # end init process
        
    def CheckConfFile(self):
        self.isnew=False
        if not os.path.isfile(self.remotehost_config):
            print_debug ( "CheckConfFile() %s not exists" %(self.remotehost_config) )
            self.isnew=True
            self.CreateConfFile()
            
    def CreateConfFile(self):
        print_debug ( "CreateConfFile()" )
        # save this into file
        fd=file(self.remotehost_config, 'w')
        for item in shared.PersonalizeConfig:
            key=item[0]
            value=item[1]
            print_debug ("key=%s value=%s" %(key, value))
            fd.write("%s=\"%s\"\n" %(key, value) )
        fd.close()
        self.FirstRunning=True
            
    def OpenFile(self):
        self.CheckConfFile()
        conf=None
        conf=[]
        print_debug("open_file() reading data from \"%s\"..."\
                                     %(self.remotehost_config) )
        fd=file(self.remotehost_config, 'r')
        self.data=fd.readlines()
        fd.close()
        for line in self.data:
            if line != '\n':
                line=line.replace('\n', '')
                conf.append(line)
        print_debug ( "OpenFile() Found %d vars" %( len(conf)) )
        if len(conf) <1:
            print_debug ( "OpenFile() FILE IS EMPTY!!!" )
            return
        for i in range( len(conf) ):
            if conf[i].find("#") != 0:
                #print_debug ( "OpenFile() conf=" + conf[i] )
                (var, value)=conf[i].split("=", 1)
                self.vars.append([var, value])

    def GetVar(self, varname):
        for i in range( len(self.vars) ):
            if self.vars[i][0].find(varname) == 0:
                print_debug ( "GetVar() found, %s=%s" \
                                %(self.vars[i][0], self.vars[i][1]) )
                return self.vars[i][1]
        print_debug ( "GetVar() not found, %s, returning \"\"" %(varname) )
        return ""
    
    def SetVar(self, varname, value):
        print_debug ( "SetVar(%s)=\"%s\"" %(varname, value) )
        for i in range(len(self.vars)):
            if varname == self.vars[i][0]:
                print_debug ( "changing %s value %s to \"%s\" of %s"\
                         %(self.vars[i][0], self.vars[i][1], value, varname) )
                self.vars[i][1]="\"%s\"" %(value)
    
    def SaveToFile(self):
        self.issaved=True
        print_debug ( "SaveToFile() len(self.vars)=%d" %( len(self.vars) ) )
        if len(self.vars) < 1:
            print_debug ( "SaveToFile() self.vars is empty" )
            return
        
        try:
            fd=file(self.remotehost_config, 'w')
        except IOError:
            shared.error_msg( "Can't write into %s file.\n\nRun as root?" %(self.remotehost_config) )
            return
        for i in range(len(self.vars)):
            fd.write("%s=%s\n" %(self.vars[i][0], self.vars[i][1]))
        fd.close()
        print_debug ( "SaveToFile() new settings SAVED!!!")   
        return
    
    def SaveSettings(self):
        """
        save settings
        """
        print_debug ( "SaveSettings() INIT" )
        
        # read combos
        self.SetVar("xsession", self.read_select_value(self.combo_xsession, "xsession") )
        self.SetVar("xdriver", self.read_select_value(self.combo_xdriver, "xdriver") )
        self.SetVar("xres", self.read_select_value(self.combo_xres, "xres") )
        self.SetVar("xdepth", self.read_select_value(self.combo_xdepth, "xdepth") )
        
        self.SetVar("xhorizsync", self.read_textbox(self.text_xhorizsync, "xhorizsync"))
        self.SetVar("xvertsync", self.read_textbox(self.text_xvertsync, "xvertsync") )
        
        if self.GetVar("xhorizsync") == "\"disable\"" or self.GetVar("xvertsync") == "\"disable\"":
            self.SetVar("xdisablesync", "disable")
        else:
            self.SetVar("xdisablesync", "")
        
        # read checkboxes
        self.read_checkbox(self.ck_xmousewheel, "xmousewheel")
        self.read_checkbox(self.ck_xdontzap, "xdontzap")
        self.read_checkbox(self.ck_xdpms, "xdpms")
        
        # save to file
        self.SaveToFile()
    
    def populate_select(self, widget, values, set_text_column=True):
        valuelist = gtk.ListStore(str)
        for value in values:
            #print_debug ( "populate_select() appending %s" %([value.split('_')[0]]) ) 
            valuelist.append( [value.split('_')[0]] )
        widget.set_model(valuelist)
        if set_text_column:
            widget.set_text_column(0)
        model=widget.get_model()
        return
    
    def set_active_in_select(self, widget, default):
        model=widget.get_model()
        for i in range(len(model)):
            #print (model[i][0] + default)
            if "\"%s\"" % (model[i][0]) == default or model[i][0] == default:
                print_debug ("set_active_in_select(%s) default is %s, index %d"\
                                     %(widget.name, model[i][0] , i ) )
                widget.set_active(i)
                return
        print_debug ( "set_active_in_select(%s) NOT HAVE DEFAULT" %(widget.name) )  
    
    def populate_checkboxes(self, widget, value):
        if value == "\"1\"" or value == "1":
            value=1
        elif value== "\"0\"" or value == "0":
            value=0
        else:
            print_debug ( "populate_checkboxes() unknow value=\"%s\"" %(value) )
            return
        checked=int(value)
        if checked == 1:
            widget.set_active(1)
        else:
            widget.set_active(0)
        return

    def populate_textboxes(self, widget, value):
        if value:
            widget.set_text(value.replace('"','') )
        
    def read_select_value(self, widget, varname):
        selected=-1
        try:
            selected=widget.get_active()
        except Exception, err:
            print_debug ( "read_select() ERROR reading %s, error=%s" %(varname, err) )
        model=widget.get_model()
        value=model[selected][0]
        print_debug ( "read_select() reading %s=%s" %(varname, value) )
        return value
    
    def read_checkbox(self, widget, varname):
        if widget.get_active() == 1:
            print_debug ( "read_checkbox(%s) CHECKED" %(widget.name) )
            self.SetVar(varname, 1)
        else:
            print_debug ( "read_checkbox(%s) UNCHECKED" %(widget.name) )
            self.SetVar(varname, 0)
            
    def read_textbox(self, widget, varname):
        if widget.get_text():
            print_debug ( "read_textbox(%s) value=%s" %(widget.name, widget.get_text() ) )
            return widget.get_text()
        else:
            print_debug ( "read_textbox(%s) can't read textbox" %(widget.name) )
            return ""
        
    def on_buttongetavalaible_click(self, widget):
        print_debug( "on_button_getavalaible_click()" )
        import tcosmonitor.TcosXauth
        self.xauth=tcosmonitor.TcosXauth.TcosXauth(self)
        import tcosmonitor.TcosConf
        self.config=tcosmonitor.TcosConf.TcosConf(self)
        import tcosmonitor.TcosXmlRpc
        self.xmlrpc=tcosmonitor.TcosXmlRpc.TcosXmlRpc(self)
        self.xmlrpc.newhost(shared.remotehost)
        if not self.xmlrpc.connected:
            shared.error_msg ( _("Host down, can't connect to tcosxmlrpc.") )
            print_debug ( "on_buttongetavalaible_click() host down!!" )
            return
        #alldrivers=self.xmlrpc.GetDevicesInfo("", "--getxdrivers").split('|')[0:-1]
        alldrivers=self.xmlrpc.GetDevicesInfo("", "--getxdrivers")
        print_debug ( "on_buttongetavalaible_click() alldrivers=%s" %(alldrivers) )
        alldrivers=alldrivers.split('|')[0:-1]
        self.populate_select(self.combo_xdriver, shared.xdriver_values + alldrivers, set_text_column=False)
        shared.info_msg ( _("New %d drivers loaded from terminal.") %(len(alldrivers)) )
    
    def on_buttonok_click(self, widget):
        print_debug ( "on_buttonok_click()" )
        self.SaveSettings()
        self.quitapp()

    def on_combo_kernel_change(self, widget):
        if self.read_select_value(widget, 'kernel') != '':
            self.buttonapply.set_sensitive(True)
    
    def get_hexfilename(self, ip):
        name=""
        for a in ip.split('.'):
            hexn="%X" %int(a)
            if len(hexn) == 1:
                hexn="0%s"%hexn
            name="%s%s"%(name, hexn )
        return os.path.join("/var/lib/tcos/tftp/pxelinux.cfg" , name )
    
    def on_buttonapply_click(self, widget):
        print_debug("on_buttonapply_click()")
        kernel=self.read_select_value(self.combo_kernel, 'kernel')
        method=self.read_select_value(self.combo_method, 'method')
        cmdline=self.text_cmdline.get_text()
        
        try:
            f=open(self.bootfilename, 'w')
        except Exception, err:
            print_debug("Error opening %s, error=%s"%(self.bootfilename, err) )
            return
        
        for line in PXELINUX_CFG:
            out=line.replace('__TCOS_KERNEL__', kernel)
            out=out.replace('__TCOS_METHOD__', method)
            out=out.replace('__TCOS_CMDLINE__', cmdline)
            f.write(out + '\n')
        f.close()
        self.deleteboot.set_sensitive(True)
    
    def on_deleteboot_click(self, widget):
        print_debug("on_deleteboot_click() ")
        try:
            os.unlink(self.bootfilename)
            self.deleteboot.set_sensitive(False)
        except Exception, err:
            print_debug("on_deleteboot_click() Exception deleting: %s"%err)
    
    def on_buttoncancel_click(self, widget):
        print_debug ( "on_buttoncancel_click()" )
        if not self.issaved and self.isnew:
            # delete file
            print_debug ( "on_buttoncancel_click() deleting file" )
            os.remove(self.remotehost_config)
        self.quitapp()    

    def on_buttondelete_click(self, widget):
        print_debug ( "on_buttondelete_click()" )
        # ask for delete
        if shared.ask_msg ( _("Really delete config of %s?") %(shared.remotehost) ):
            print_debug ( "on_buttondelete_click() deleting file" )
            os.remove(self.remotehost_config)
        shared.info_msg ( _("Deleted!") )
        self.quitapp()

    def getkernels(self):
        # valid kernel >= 2.6.12
        # perpahps we can try to build initrd image instead of initramfs
        # in kernel < 2.6.12, this require a lot of work in gentcos and init scripts
        kernels=[]
        #print_debug ("getkernels() read all vmlinuz in /boot/")
        #for _file in os.listdir(shared.chroot + '/boot'):
        # FIXME need to detect chroot kernels
        #for _file in os.listdir('/var/lib/tcos/tftp'):
        for _file in glob.glob('/var/lib/tcos/tftp/vmlinuz*'):
            try:
                os.stat(_file)
            except Exception, err:
                print_debug("getkernels() link %s broken, error=%s" %(_file, err) )
                continue
            kernel=os.path.basename(_file).replace('vmlinuz-','')
            print_debug("getkernels() found %s"%kernel)
            # split only 3 times
            try:
                (kmay, kmed, kmin) = kernel.split('.', 2)
            except Exception, err:
                print_debug("getkernels() exception spliting kernel '%s' version, %s"%(kernel, err))
                continue
            import re
            pattern = re.compile ('[-_.+]')
            (kmin, kextra) = pattern.split(kmin, 1)
            # need kernel >= 2.6.12
            if int(kmay)==2 and int(kmed)==6 and int(kmin)>=12:
                #print_debug( "getkernels() VALID kernel %s" %(kernel) )
                kernels.append(kernel)
            else:
                print_debug( "getkernels() INVALID OLD kernel %s" %(kernel) )
        return kernels

    def quitapp(self, *args):
        print_debug ( _("Exiting") )
        gtk.main_quit()

    def run (self):
        try:
            gtk.main()
        except KeyboardInterrupt:
            self.quitapp()


if __name__ == '__main__':
    #gtk.gdk.threads_init()
    gobject.threads_init()
    app = TcosPersonalize ()
    # Run app
    app.run ()
