#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
Instalador de Guadalinex en memorias USB
Basado en el código del instalador Nanomax de la distribución MAX (Comunidad de Madrid)

Copyright 2008, Mario Izquierdo mariodebian@gmail.com

Changelog
  20080512 - First usable version

"""

import os, sys
import atexit

# import gtk and glade
import pygtk
pygtk.require('2.0')
import gtk
from gettext import gettext as _
import gtk.glade

import gobject
gobject.threads_init()
gtk.gdk.threads_init()

from subprocess import Popen, PIPE, STDOUT
import threading

import dbus
import dbus.service
if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
    import dbus.glib



class GuadalinexInstaladorUsb (object):

    def __init__(self,):
        self.gconf_previous = {}
        self.widgets={}
        self.device={}
        self.mainloop = gobject.MainLoop()
        self.hal=DeviceManager(self.insert_row)
        self.selected=None


    def initgui(self):
        # glade locale init
        #gtk.glade.bindtextdomain("nanomaxinstaller", "./po")
        #gtk.glade.textdomain("nanomaxinstaller")

        # Widgets
        self.ui = gtk.glade.XML('/usr/share/guadalinex-asistente-usb/guadalinex-asistente-usb.glade')

        # load all widgets
        for widget in self.ui.get_widget_prefix(""):
            self.widgets[widget.get_name()]=widget
        
        self.ui.signal_autoconnect(self)
        
        # disable aceptar button
        self.widgets['aceptar_button'].set_sensitive(False)
        

        self._columns = [ 
            ('Dispositivo', gobject.TYPE_STRING),
            ('Tamaño (GiB)', gobject.TYPE_STRING),
            ('Modelo', gobject.TYPE_STRING),
                ]
        _val = [i[1] for i in self._columns]
        self.liststore = gtk.ListStore(*_val)
        
        treeview=self.widgets['devices_list']
        treeview.set_model(self.liststore)
        
        _index = 0
        for (_name,_type) in self._columns:
            _rend = gtk.CellRendererText()
            _column = gtk.TreeViewColumn(_name, _rend, text=_index)
            _column.set_clickable(True)
            treeview.append_column(_column)
            _index += 1
        treeview.columns_autosize()
        treeview.show()
        
        treeview_file = treeview.get_selection()
        treeview_file.connect("changed", self.on_device_click)
        
        self.hal.get_all_devices()

    def on_device_click(self, devices):
        (model, iter) = devices.get_selected()
        if not iter:
            self.widgets['aceptar_button'].set_sensitive(False)
            self.selected=None
            return
        self.device['dev']=model.get_value(iter,0)
        self.device['size']=model.get_value(iter, 1)
        self.device['model']=model.get_value(iter, 2)
        self.selected=self.device
        self.widgets['aceptar_button'].set_sensitive(True)

    def fixed_toggled(self, cell, path, index):
        _iter = self.liststore.get_iter((int(path),))
        _fixed = self.liststore.get_value(_iter, index)
        self.liststore.set(_iter, index, not _fixed)

    def insert_row(self, devices):
        self.clear()
        for dev in devices:
            #print "insert_row, dev=%s" %dev
            row=(dev['device'], "%.02f" %self.size_to_gib(dev['size']) , dev['vendor'] + " " + dev['model'] )
            self.liststore.append(row)
        #return self.liststore.append(row)

    def size_to_gib(self, size):
        gib=(size/1000000000.0)
        print "size_to_gib() size=%s gib=%s"%(size, gib)
        return gib

    def clear(self):
        return self.liststore.clear()

    def on_aceptar_button_clicked(self, *args):
        if not self.selected: return
        if float(self.selected['size']) < 0.8:
            self.error_msg("Necesita una memoria de al menos 1GB para instalar Guadalinex")
            return

        self.widgets['mainwindow'].set_sensitive(False)
        self.widgets['scrolledwindow1'].hide()
        self.widgets['frame1'].hide()
        self.widgets['aceptar_button'].hide()
        self.widgets['scrolledwindow2'].show()
        
        print "on_aceptar_button_clicked() selected device=%s" %self.selected
        cmd="bash /usr/share/guadalinex-asistente-usb/do-install.sh '%s'" %(self.selected['dev'])
        th=threading.Thread(target=self.install, args=(cmd,))
        th.start()


    def install(self, cmd):
        self.installing=True
        p=Popen(cmd, shell=True, bufsize=0, stdout=PIPE, stderr=STDOUT, close_fds=True)
        while self.installing:
            if p.poll() != None: self.installing=False
            line=p.stdout.readline()
            print "do: %s"%line.strip()
            gtk.gdk.threads_enter()
            self.insert_salida(line.strip())
            gtk.gdk.threads_leave()
        self.widgets['mainwindow'].set_sensitive(True)

    def insert_salida(self, txt):
        buffer = self.widgets['salida'].get_buffer()
        iter = buffer.get_end_iter()
        mark = buffer.get_insert()
        txt=str(txt)
        buffer.insert(iter, '\n  ' + txt)
        # scroll window
        self.widgets['salida'].scroll_to_mark(mark, 0.2)
        return

    def error_msg(self, txt):
        d = gtk.MessageDialog(None,
                      gtk.DIALOG_MODAL |
                      gtk.DIALOG_DESTROY_WITH_PARENT,
                      gtk.MESSAGE_WARNING,
                      gtk.BUTTONS_OK,
                      txt)
        d.run()
        d.destroy()


    def run (self):
        try:
            self.mainloop.run()
        except KeyboardInterrupt:
            self.quit()
        
    def quit(self, *args):
        self.mainloop.quit()
        print "saliendo"
        sys.exit(0)



class DBusException(Exception):
    def __init__(self, *args, **kwargs):
        pass
    def __str__(self):
        pass
        
    def get_dbus_name(self):
        return self._dbus_error_name

dbus.exceptions.DBusException=DBusException

# Code based on:
# (c) 2007, Davyd Madeley <davyd@madeley.id.au>
#
# This program serves as an example, and can be freely used, copied, derived
# and redistributed by anyone. No warranty is implied or given.
#


class DeviceManager:
    def __init__(self, update_function=None, event_bus="usb"):
        self.update_function=update_function
        self.event_bus=event_bus
        self.bus = dbus.SystemBus()
        hal_obj = self.bus.get_object ('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
        self.hal = dbus.Interface (hal_obj, 'org.freedesktop.Hal.Manager')
        self.bus.add_signal_receiver(self.get_all_devices,
                        'DeviceAdded',
                        'org.freedesktop.Hal.Manager',
                        'org.freedesktop.Hal',
                        '/org/freedesktop/Hal/Manager')
 
        self.bus.add_signal_receiver(self.remove,
                        'DeviceRemoved',
                        'org.freedesktop.Hal.Manager',
                        'org.freedesktop.Hal',
                        '/org/freedesktop/Hal/Manager')
                        
    def remove(self, udi):
        self.get_all_devices(None)

        
    def get_all_devices(self, event_udi=None):
        #print event_udi
        try:
            if event_udi:
                self.get_udi_data(event_udi)
        except:
            return
        devices=[]
        print "\n\nEVENT at UDI %s"%event_udi
        udis = self.hal.FindDeviceByCapability ('storage')
        for udi in udis:
            tmp=self.get_udi_data(udi)
            if tmp and tmp['bus'] == self.event_bus:
                devices.append(tmp)
        #for dev in devices:
        #    print dev
        if self.update_function:
            self.update_function(devices)

    def get_udi_data(self, udi):
        # get a device object
        dev_obj = self.bus.get_object ('org.freedesktop.Hal', udi)
        

        # get an interface to the device
        dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device')
        if self.event_bus != dev.GetProperty ('storage.bus'):
            return None
        try:
            if not os.path.exists(str(dev.GetProperty ('block.device'))):
                print "device don't exists"
                return None
        except:
            return None
        if int( dev.GetProperty( 'storage.size') ) != 0:
            size=int( dev.GetProperty( 'storage.size') )
        else:
            p = Popen("LC_ALL=C /sbin/fdisk -l %s| awk '/^Disk*.*bytes/ {print $5}'"%str(dev.GetProperty ('block.device')), shell=True, bufsize=0, stdout=PIPE, stderr=STDOUT, close_fds=True)
            size=int(p.stdout.readline().strip())
        return{
                "udi": str(udi),
                "device": str(dev.GetProperty ('block.device')),
                "bus": str(dev.GetProperty ('storage.bus')),
                "model": str(dev.GetProperty ('storage.model')),
                "vendor": str(dev.GetProperty ('storage.vendor')),
                "removable": bool(dev.GetProperty ('storage.removable')),
                "size": size
              }


if __name__ == '__main__':
    app = GuadalinexInstaladorUsb()
    # Run app
    app.initgui()
    #print app.widgets
    app.run()
