import gtk, gtk.glade, os.path
import backends.rdatabase, gglobals, optionTable

class PreferencesGui:
    """The glue between our glade preferences dialog and our prefs modules."""
    
    INDEX_PAGE = 0
    CARD_PAGE = 1
    SHOP_PAGE = 2

    def __init__ (
        self,
        prefs,
        glade=os.path.join(gglobals.gladebase,
                           'preferenceDialog.glade'),
        radio_options={'shop_handle_optional':{'optional_ask':0,
                                               'optional_add':1,
                                               'optional_dont_add':-1
                                               }
                       },
        toggle_options={'remember_optionals_by_default':'remember_optionals_by_default',
                        'readableUnits':'toggle_readable_units',
                        'email_include_body':'email_body_checkbutton',
                        'email_include_html':'email_html_checkbutton',
                        'emailer_dont_ask':'remember_email_checkbutton',
                        },
        buttons = {}
        #buttons = {'clear_remembered_optional_button':
        ):
        """Set up our PreferencesGui

        glade points us to our gladefile
        
        radio_options is a dictionary of preferences controlled by radio buttons.
                      {preference_name: {radio_widget: value,
                                         radio_widget: value, ...}
                                         }

        toggle_options is a dictionary of preferences controlled by toggle buttons.
                      {preference_name: toggle_widget_name}
        buttons = {button_name : callback}
                      
        """
        
        self.prefs = prefs
        self.glade = gtk.glade.XML(glade)
        self.notebook = self.glade.get_widget('notebook')
        # pref name: {'buttonName':VALUE,...}
        self.radio_options = radio_options
        self.connect_radio_buttons()
        self.toggle_options = toggle_options
        self.apply_prefs_dic = {}
        self.widget_sensitivity_dic = {
            # pref : {'value':('widget':True,'widget':False,'widget':True...)}
            'shop_handle_optional':{0:{'remember_optionals_by_default':True,
                                       'clear_remembered_optional_button':True},
                                    1:{'remember_optionals_by_default':False,
                                       'clear_remembered_optional_button':False},
                                    -1:{'remember_optionals_by_default':False,
                                       'clear_remembered_optional_button':False}
                                    }
            }
        self.connect_toggle_buttons()
        self.buttons=buttons
        self.connect_buttons()
        self.build_pref_dictionary()
        self.set_widgets_from_prefs()
        self.prefs.set_hooks.append(self.update_pref)
        self.pref_tables={}
        self.glade.get_widget('close_button').connect('clicked',lambda *args: self.hide_dialog())

    def build_pref_dictionary (self):
        """Build our preferences dictionary pref_dic

        preference: BOOLEAN_WIDGET|{VALUE:RADIO_WIDGET,VALUE:RADIO_WIDGET...}
                    METHOD_TO_BE_HANDED_PREF_VALUE

        pref_dic will be used to e.g. set default values and watch
        changing preferences.
        """
        self.pref_dic = {}
        for pref,widget in self.toggle_options.items():
            self.pref_dic[pref]=('TOGGLE',widget)
        for pref,widgdic in self.radio_options.items():
            self.pref_dic[pref]={}
            # create a dictionary by value (reversed dictionary)...
            for widg,val in widgdic.items(): self.pref_dic[pref][val]=widg
        self.d=self.glade.get_widget('dialog')
        self.d.connect('delete-event',self.hide_dialog)


    def set_widgets_from_prefs (self):
        for k in self.pref_dic.keys():
            if self.prefs.has_key(k): self.update_pref(k,self.prefs[k])

    def update_pref (self, pref, value):
        """Update GUI to reflect value 'value' of preference 'pref'."""
        if self.pref_dic.has_key(pref):
            action=self.pref_dic[pref]
            if type(action)== dict :
                # we fail if action is no
                widg=action[value]
                act,act_args=('set_active',True)
            elif action[0]=='TOGGLE':
                act,act_args=('set_active',value)
                widg=action[1]
            # in the future, we can handle Entries, etc...
            if type(widg)==str:
                widg=self.glade.get_widget(widg)
            getattr(widg,act)(act_args)
            self.update_sensitivity_for_pref(pref,value)
            
    def show_dialog (self, page=None):
        """present our dialog."""        
        self.d.present()
        if page:
            self.notebook.set_current_page(page)

    def hide_dialog (self,*args):
        self.d.hide()
        return True

    def connect_buttons (self):
        for b,cb in self.buttons.items():
            self.glade.get_widget(b).connect('clicked',cb)

    def connect_toggle_buttons (self):
        """Connect signals for toggle buttons in self.toggle_options."""
        for pref,widget in self.toggle_options.items():
            self.glade.get_widget(widget).connect('toggled',self.toggle_callback,pref)

    def toggle_callback (self, button, pref_name):
        """Set preference 'pref_name' in response to toggle event on button."""
        self.set_pref(pref_name, button.get_active())
        
    def connect_radio_buttons (self):
        """Connect radio button signals to properly set preferences on toggle."""
        for pref_name,pref_dic in self.radio_options.items():
            for button,val in pref_dic.items():
                self.glade.get_widget(button).connect(
                    'toggled',
                    self.radio_callback,
                    pref_name,
                    val)

    def radio_callback (self, button, pref_name, true_val=True):
        """Call back for radio button: if we are on, we set the pref to true_val."""
        if button.get_active():
            self.set_pref(pref_name,true_val)

    def set_pref (self, name, value):
        """Set preference 'name' to value 'value'

        Possibly apply the preference using callback looked up in
        apply_prefs_dic (callback must take name and value of pref as
        arguments.
        """
        self.prefs[name]=value
        if self.apply_prefs_dic.has_key(name):
            self.apply_prefs_dic[name](name,value)

    def update_sensitivity_for_pref (self, name, value):
        try:
            for k,v in self.widget_sensitivity_dic[name][value].items():
                self.glade.get_widget(k).set_sensitive(v)
        except KeyError: pass
            

    def add_widget (self, target_widget, child_widget):
        """Add child_widget to target_widget"""
        if type(target_widget)==str: target_widget=self.glade.get_widget(target_widget)
        if type(child_widget)==str: child_widget=self.glade.get_widget(child_widget)
        target_widget.add(child_widget)
        target_widget.show_all()

    def add_pref_table (self, options, target_widget, callback=None):
        """Add a preference table based on an option list 'options' to the
        target_widget 'target_widget' (either a widget or a glade-reference)

        The options need to be appropriate for an OptionTable.

        The callback will be handed the options (as returned by
        OptionTable) each time OptionTable is changed.
        """
        table=optionTable.OptionTable(options=options, changedcb=self.preftable_callback)
        self.pref_tables[table]=callback
        self.add_widget(target_widget,table)

    def preftable_callback (self, widget):
        for table,cb in self.pref_tables.items():
            if widget in table.get_children():
                # then we know who's preferences we care about...
                table.apply()
                if cb: cb(table.options)
                return
        print "Oops: we couldn't handle widget %s"%widget
        
if __name__ == '__main__':
    class FauxPrefs (dict):
        def __init__ (self,*args,**kwargs):
            self.set_hooks = []
            dict.__init__(self,*args,**kwargs)

        def __setitem__ (self,k,v):
            print 'k:',k
            print 'v:',v
            dict.__setitem__(self,k,v)
            for h in self.set_hooks:
                print 'runnnig hook'
                h(k,v)
            
    gf='/home/tom/Projects/grm-0.8/glade/preferenceDialog.glade'
    import sys
    p=PreferencesGui(FauxPrefs(),gf)
    def printstuff (*args): print args
    p.add_pref_table([["Toggle Option",True],
                      ["String Option","Hello"],
                      ["Integer Option",1],
                      ["Float Option",float(3)]],
                     'cardViewVBox',
                     printstuff
                     )
    p.show_dialog()
    gtk.main()
