#!/usr/bin/env python
# SHR Settings
# by Sebastian Krzyszkowiak, openmoko.pl and SHR teams
# GPLv3+

from time import time

starttime=time()

class logtype:
    HEADER = '\033[95m'
    INFO = '\033[94m'
    OK = '\033[92m'
    DEBUG = '\033[90mDEBUG: \033[0m';
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    RESET = '\033[0m'

def log(text, type=logtype.INFO):
    print type + text + logtype.RESET

log('SHR Settings', logtype.HEADER)

import elementary, ecore
import os.path
from sys import argv, exc_info
from functools import partial
from gettext import Catalog

try:
    cat = Catalog("shr-settings")
    _ = cat.gettext
except IOError:
    _ = lambda x: x

DIRS = [	[_("Phone"),"icon_phone.png",			[ 'shr_gsm.Gsm', 'shr_call.Call', 'shr_phoneutils.Phoneutils', 'shr_simauth.SimAuth', 'shr_sim.Sim' ] ],
		[_("Profiles"),"icon_profiles.png",		[ 'shr_profile.Profile', 'shr_currentprofile.CurrentProfile' ] ],
		[_("Connectivity"),"icon_connectivity.png",	[ 'shr_wifi.Wifi', 'shr_gprs.Gprs', 'shr_usb.Usb', 'shr_bt.Bt' ] ],
		[_("Power"),"icon_power.png",			[ 'shr_battery.Battery', 'shr_display.Display', 'shr_pm.Pm' , 'shr_device_timeouts.Timeouts' ] ],
		[_("Appearance"),"icon_appearance.png",		[ 'shr_elementary.Elementary', 'shr_splash.Splash' ] ],
		[_("Position"), "icon_position.png",		[ 'shr_gps.Gps', 'shr_gpsinfo.GpsInfo' ] ],
		[_("Date/time"),"icon_datetime.png",		[ 'shr_clock.Clock', 'shr_date.Date' ] ],
		[_("Others"), "icon_others.png",		[ 'shr_services.Services', 'shr_backup.Backup', 'shr_imageinfo.ImageInfo', 'shr_sim_manager.SimManager' ] ]
       ]

class CategoryButton(elementary.Button):
    """ extends e.button with list of modules that belong to it """
    def set_modules(self, modules):
        self.modules = modules
    def get_modules(self):
        return self.modules



class ModulesWindow:
    def renderModules(self, modulesList, bus):
        nowtime = time()
        for modname in modulesList[2]:
            thistime = time()
            log("Loading module %s..." % modname, logtype.INFO)
            try:
                # modname: 'shr_gsm.GSM'. Import "shr_settings_modules.shr_gsm"
                # dynamically and instantiate class "GSM"
                (submodname, classname) = modname.split('.',1)
                module   = __import__('shr_settings_modules.' + submodname,
                                      globals(), locals(), classname)
                ModClass = module.__getattribute__(classname)
                mod2 = ModClass(self.win2, bus)
                self.modList.append(mod2)

                if mod2.isEnabled():
                    cont = mod2.createView()

                    frame = elementary.Frame(self.win2)

                    frame.label_set(mod2.getName())
                    self.box12.pack_end(frame)
                    frame.size_hint_align_set(-1.0, 0.0)
                    frame.show()

                    if cont != None:
                        frame.content_set(cont)
                        cont.show()
                        log("Module "+modname+" loaded in %.2f sec" % (time() - thistime), logtype.OK)
                    else:
                        log("error! module %s method createView() return's nothing!" % mod2, logtype.FAIL)
            except:
                import traceback
                log("Module %s can't be loaded!" % modname, logtype.FAIL)
                tr = traceback.format_exc()
                exc_type, exc_value, exc_traceback = exc_info()
                line = exc_traceback.tb_lineno
                msg = tr.splitlines()
                msg = msg[-1]
                err = _("Could not load module: error in line %d\n%s" % (line, msg))
                print tr

                frame = elementary.Frame(self.win2)
                try:
                  frame.label_set(mod2.getName())
                except:
                  frame.label_set(modname)
                self.box12.pack_end(frame)
                frame.size_hint_align_set(-1.0, 0.0)
                frame.show()

                cont = elementary.AnchorBlock(self.win2)
                cont.text_set(err)
                cont.show()

                frame.content_set(cont)
                cont.show()


        self.loading.hide()
        log("Page loaded in %.2f sec" % (time() - nowtime), logtype.OK)
        return None

    def makeGui(self,  modulesList, bus, fromcli = False):

        log( "creating window: " + str(modulesList), logtype.DEBUG)

        self.win2 = elementary.Window("settingsMods", elementary.ELM_WIN_BASIC)
        self.win2.title_set(modulesList[0])
        if fromcli:
            self.win2.callback_destroy_add(self.destroy)
        else:
#            self.win2.autodel_set(True)
            self.win2.callback_destroy_add(partial(self.destroy2, self.win2))

        #add background to module window
        bg = elementary.Background(self.win2)
        bg.size_hint_min_set(200,300)
        self.win2.resize_object_add(bg)
        bg.size_hint_weight_set(1.0, 1.0)
        bg.show()

        box02 = elementary.Box(self.win2)
        box02.size_hint_weight_set(1.0, 1.0)
        self.win2.resize_object_add(box02)
        box02.show()



    #    toolbar = elementary.Toolbar(win)
    #    box0.pack_start(toolbar)
    #    toolbar.show()

        sc2 = elementary.Scroller(self.win2)
        sc2.bounce_set(0, 0)
        sc2.size_hint_weight_set(1.0, 1.0)
        sc2.size_hint_align_set(-1.0, -1.0)
        box02.pack_end(sc2)
        sc2.show()

        quitbt2 = elementary.Button(self.win2)
        if fromcli:
            quitbt2._callback_add('clicked', self.destroy)
        else:
            quitbt2._callback_add('clicked', partial(self.destroy2, self.win2))
        quitbt2.label_set(_("Quit"))
        quitbt2.size_hint_align_set(-1.0, 0.0)
        ic = elementary.Icon(quitbt2)
        ic.file_set( "/usr/share/pixmaps/shr-settings/icon_quit.png" )
        ic.scale_set(1,1)
        ic.smooth_set(1)
        quitbt2.icon_set(ic)
        quitbt2.show()
        box02.pack_end(quitbt2)


        self.box12 = elementary.Box(self.win2)
        self.box12.size_hint_weight_set(1.0, -1.0)
        sc2.content_set(self.box12)
        self.box12.show()

        self.loading = elementary.Box(self.win2)
        loadingframe = elementary.Frame(self.win2)
        loadingframe.style_set("outdent_bottom")
        loadingframe2 = elementary.Frame(self.win2)
        loadingframe2.style_set("outdent_top")
        loadingframe2.size_hint_weight_set(0.0, 0.0)
        loadingframe2.size_hint_align_set(0.5, 0.5)
        loadinglabel = elementary.Label(self.win2)
        modulescount = len(modulesList[2])
        loadinglabel.label_set(_("Please wait...<br>Loading %d modules...") % modulescount)

        loadingframe.content_set(loadingframe2)
        loadingframe2.content_set(loadinglabel)
        self.win2.resize_object_add(self.loading)
        self.loading.pack_start(loadingframe)
        loadinglabel.show()
        loadingframe.show()
        loadingframe2.show()
        self.loading.show()

        self.modList = []
        #DEBUG
        #for mod in modulesList[2]:
        #
        #    print "debug loading %s" % mod
        #    debugmod=mod(self.win2, bus)
        #    if debugmod.isEnabled():
        #        debugmod.createView()
        #END OF DEBUG
        #from shr_settings_modules import shr_display
        #debugmod=shr_display.Display(self.win2, bus)
        #if debugmod.isEnabled():
        #    debugmod.createView()
        #END OF SECOND DEBUG
        ecore.idler_add(self.renderModules, modulesList, bus)
        self.win2.show()

    def destroy2(self, win, obj, *args, **kargs):
        log ( "closing modules window...", logtype.DEBUG)
        win.hide()
        for m in self.modList:
            log ("deleting module \"" + m.getName() + "\"" , logtype.DEBUG)
            try:
                m.stopUpdate()
            except:
                log(m.getName()+": stopUpdate failed!", logtype.FAIL)
            del m
        log ("deleting window object", logtype.DEBUG)
        win.delete()
        del win
        del self

    def destroy(self, obj, *args, **kargs):
        log( "window destroy callback called! kabum!", logtype.DEBUG)
        elementary.exit()



class MainWindow:

    def destroy(self, obj, *args, **kargs):
        log("window destroy callback called! kabum!", logtype.DEBUG)
        elementary.exit()

    def displayModulesWin(self, obj, *args, **kargs):
        #print "displayModulesWin 1"
        if self.dbus_system == None:
           log( "idler had not inited dbus yet, do it now", logtype.WARNING)
           self.init_dbus_idler()
        ModulesWindow().makeGui(  obj.get_modules(), self.dbus_system )
        #print "displayModulesWin 2"

    def start_ophonekitd(self, obj, *args, **kargs):
        os.system( "/etc/init.d/phonefsod start" )
        self.opkinwin.delete()

    def destroyDebug(self, obj, *args, **kargs):
        self.windeb.hide()
        self.windeb.delete()

    def clean_ophonekitd_log(self, obj, *args, **kargs):
        os.system("echo \"\" >  /var/log/phonefsod.log")
        self.destroyDebug(self, obj, *args, **kargs)

    def view_ophonekitd_log(self, obj, *args, **kargs):
        #print "ophonekitd log"
        self.windeb = elementary.Window("ophonekitdLog", elementary.ELM_WIN_BASIC )
        self.windeb.title_set(_("phonefsod log"))
        self.windeb.autodel_set(True)
        self.bgdeb = elementary.Background(self.windeb)
        self.windeb.resize_object_add(self.bgdeb)
        self.bgdeb.size_hint_weight_set(1.0, 1.0)
        self.bgdeb.size_hint_min_set(200,300)
        self.bgdeb.show()

        box0 = elementary.Box(self.windeb)
        box0.size_hint_weight_set(1.0, 1.0)
        self.windeb.resize_object_add(box0)
        box0.show()

        fr = elementary.Frame(self.windeb)
        fr.label_set(_("phonefsod log"))
        fr.size_hint_align_set(-1.0, 0.0)
        box0.pack_end(fr)
        fr.show()

        sc = elementary.Scroller(self.windeb)
        sc.size_hint_weight_set(1.0, 1.0)
        sc.size_hint_align_set(-1.0, -1.0)
        box0.pack_end(sc)
        sc.show()

        cleanbt = elementary.Button(self.windeb)
        cleanbt._callback_add('clicked', self.clean_ophonekitd_log)
        cleanbt.label_set(_("Clean"))
        cleanbt.size_hint_align_set(-1.0, 0.0)
        cleanbt.show()
        box0.pack_end(cleanbt)

        cancelbt = elementary.Button(self.windeb)
        cancelbt._callback_add('clicked', self.destroyDebug)
        cancelbt.label_set(_("Close"))
        cancelbt.size_hint_align_set(-1.0, 0.0)
        cancelbt.show()
        box0.pack_end(cancelbt)

        box1 = elementary.Box(self.windeb)
        box1.size_hint_weight_set(1.0, -1.0)
        sc.content_set(box1)
        box1.show()

        self.windeb.show()


        c = open( "/var/log/phonefsod.log", "r" )
        while 1:
            line = c.readline().replace("\n","")
            if not line:
                break
            #print "line ["+line+"]"
            lb = elementary.Label(self.windeb)
            lb.label_set(line)
            lb.size_hint_align_set(-1.0, 0.0)
            box1.pack_end(lb)
            lb.show()


    def opk_hide(self, obj, *args, **kargs):
        self.opkinwin.delete()

    def init_dbus_idler(self):
        # dbus init if not done before:
        if self.dbus_system == None:
            import dbus, e_dbus
            mainloop = e_dbus.DBusEcoreMainLoop()
            #self.dbus_session = dbus.SessionBus(mainloop=self.mainloop) - we don't need atm
            self.dbus_system = dbus.SystemBus(mainloop=mainloop)
            log('dbus inited successfully', logtype.DEBUG)
            log('GUI loaded in %.2f sec' % (time() - starttime), logtype.OK)
            return False  #don't call idler again

    def __init__(self):
        self.dbus_system = None
        self.win = elementary.Window("settings", elementary.ELM_WIN_BASIC)
        self.win.title_set(_("Settings"))
        self.win.callback_destroy_add(self.destroy)

        #self.m = ModulesWindow()

        #add background to main window
        bg = elementary.Background(self.win)
        self.win.resize_object_add(bg)
        bg.size_hint_weight_set(1.0, 1.0)
        bg.size_hint_min_set(200,300)
        bg.show()

        # main container contains a scroller and the Quit button
        mainbox = elementary.Box(self.win)
        mainbox.size_hint_weight_set(1.0, 1.0)
        self.win.resize_object_add(mainbox)
        mainbox.show()

        # scroller that contains the table with buttons
        #sc = elementary.Scroller(mainbox)
        #sc.size_hint_weight_set(1.0, 1.0)
        #sc.size_hint_align_set(-1.0, -1.0)
        #mainbox.pack_end(sc)
        #sc.show()

        # quit button
        quitbt = elementary.Button(mainbox)
        quitbt._callback_add('clicked', self.destroy)
        quitbt.label_set(_("Quit"))
        quitbt.size_hint_align_set(-1.0, 0.0)
        ic = elementary.Icon(quitbt)
        ic.file_set( "/usr/share/pixmaps/shr-settings/icon_quit.png" )
        ic.smooth_set(1)
        ic.scale_set(1, 1)
        quitbt.icon_set(ic)
        quitbt.show()
        mainbox.pack_end(quitbt)

        # table containing category buttons
        cat_table = elementary.Table(mainbox)
        cat_table.size_hint_weight_set(1.0, 1.0)
        cat_table.size_hint_align_set(-1.0, -1.0)
        mainbox.pack_start(cat_table)
        cat_table.show()

        #loading modules

        for (i,d) in enumerate(DIRS):
            bt = CategoryButton(cat_table)
            bt.set_modules( d )

            bt._callback_add('clicked', self.displayModulesWin)
            bt.size_hint_weight_set(1.0, 1.0)
            bt.size_hint_align_set(-1.0, -1.0)
            bt.label_set( d[0] )
            bt.show()

            icon_paths = [ "/usr/share/pixmaps/shr-settings/"+str(d[1]), "data/icons/"+str(d[1])]
            for i_path in icon_paths:
                if os.path.exists(i_path):
                    ic = elementary.Icon(bt)
                    ic.file_set( i_path )
                    ic.scale_set(1, 1)
                    bt.icon_set(ic)
                    break

            (row, col) = divmod(i,2)
            cat_table.pack(bt,col,row,1,1)

        #ophonekitd or phonefsod not running?
        if os.popen("ps -A | grep 'ophonekitd\|phonefsod'").read() == "":
            log('neither ophonekitd nor phonefsod is running!', logtype.FAIL)

            self.opkframe = elementary.Frame(self.win)

            opkbox = elementary.Box(self.win)
            opklabbox = elementary.Box(opkbox)
            opkbox.horizontal_set(1)
            opklab1 = elementary.Label(opklabbox)
            opklab1.label_set(_("phonefsod"))
            opklab1.show()
            opklabbox.pack_start(opklab1)

            opklab2 = elementary.Label(opklabbox)
            opklab2.label_set(_("is not running!"))
            opklab2.show()
            opklabbox.pack_end(opklab2)

            opkstart = elementary.Button(opkbox)
            opkstart.label_set(_("Start"))
            opkstart.show()
            opkstart._callback_add('clicked', self.start_ophonekitd)
            opkbox.pack_end(opkstart)

            opklog = elementary.Button(opkbox)
            opklog.label_set(_("View log"))
            opklog._callback_add('clicked', self.view_ophonekitd_log)
            opklog.show()
            opkbox.pack_end(opklog)


            opklabbox.show()
            opkbox.show()
            opkbox.pack_start(opklabbox)

            opkoutbox = elementary.Box(self.win)
            opkoutbox.pack_start(opkbox)
            opkoutbox.show()

            self.opkframe.content_set(opkoutbox)
            self.opkframe.show()

            self.opkmainbox = elementary.Box(self.win)
            self.opkmainbox.pack_start(self.opkframe)
            self.opkframe.label_set(_("Information"))
            self.opkmainbox.show()

            opkhide = elementary.Button(self.opkmainbox)
            opkhide.label_set(_("Close"))
            opkhide.size_hint_align_set(-1.0, 0.0)
            opkhide._callback_add('clicked', self.opk_hide)
            opkhide.show()
            opkoutbox.pack_end(opkhide)

            self.opkinwin = elementary.InnerWindow(self.win)
            self.opkinwin.scale_set(1.0)
            self.opkinwin.show()
            self.opkinwin.content_set(self.opkmainbox)
            self.opkinwin.style_set("minimal")
            self.win.resize_object_add(self.opkinwin)
            self.opkinwin.activate()
#            mainbox.pack_start(opkbox)

        #let's go!
        self.win.show()
        ecore.idler_add(self.init_dbus_idler)


if __name__ == "__main__":
    elementary.init()

    if len(argv[1:])>0:
        modlista = [];
        if argv[1] in ("-h", "--help"):
                print "SHR Settings"
                print "Settings for SHR based Openmoko phone."
                print "--------------------------------------"
                print "Call it without any argument to open"
                print "main menu with categories."
                print "Call it with modules names, to open"
                print "only typed modules in one window."
                print "First argument is window title."
                print "--------------------------------------"
                print "http://shr-project.org/"
                exit(0)
        else:
            modlista.append(argv[1]) # title
            modlista.append('') # TODO: icon
            modlista.append(argv[2:]) # list of modules
        modwin = ModulesWindow()
        import dbus, e_dbus
        mainloop = e_dbus.DBusEcoreMainLoop()
        dbus_system = dbus.SystemBus(mainloop=mainloop)
        modwin.makeGui(modlista, dbus_system, True)
    else:
        MainWindow()
    log('Launcher loaded in %.2f sec' % (time() - starttime), logtype.OK)
    elementary.run()
    elementary.shutdown()
    log('Bye bye!', logtype.INFO)


