#!/usr/bin/python
#
#  Copyright Andrew Hunter, Luis de Bethencourt Guimera 2008
#
#    This program is free software; you may 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 program 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, see <http://www.gnu.org/licenses/>.

#Error message dialoge lifted from Terminator. http://launchpad.net/terminator
try:
  import gtk, meminfo_total, sys, os, cPickle
  from changesettings import ChangeSettings
except:
  import_error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, ('You need to install python bindings for gtk ("python-gtk2" in debian/ubuntu)'))
  import_error.run()
  sys.exit(1)

class Uscontrols:
  def __init__(self):

    #get the gtkbuilderfile
    self.gtkbuilderfile = "/usr/share/ubuntustudio-controls/gui.xml" #Remove /usr/share/ubuntustudio-controls/ to run from src dir
    self.builder = gtk.Builder()
    self.builder.add_from_file(self.gtkbuilderfile)

    #Get the Main Window, and connect the "destroy" event
    self.window = self.builder.get_object("mainWindow")
    self.aboutWidget = self.builder.get_object("about")
    self.raw1394Warning = self.builder.get_object("raw_dialog")

    #Create our dictionary and connect it
    dic = { "on_closeButton_clicked" : self.close_window,
            "on_mainWindow_destroy" : self.close_window,
            "on_about_button_clicked" : self.about,
            "on_apply_button_clicked" : self.apply_settings,
            "on_memlock_spinbutton_value_changed" : self.update_memlock_amount,
            "on_memlock_checkButton_toggled" : self.set_memlock_enable,
            "on_raw1394_checkbutton_toggled" : self.check_raw1394_enabled,
            "on_EnableNice_toggled" : self.set_nice_enable,
            "on_nicePercentageAmount_value_changed" : self.set_nice_amount,
            }

    self.builder.connect_signals(dic)

  #Determine how much memory is on the system
  memtotal = meminfo_total.meminfo_total()

  #Subclass ChangeSettings so that it reverts instead of removes
  #This subclass is obsoleted with latest changes for raw1394 permissions
  class ChangeRaw1394(ChangeSettings):
    def rm_setting(self):
      self.line_check = self.regex_search()
      if self.line_check:
        print 'Match found, returning to \"disk\"'
        self.newlines = [self.regex.sub('KERNEL==\"raw1394\",\t\t\tGROUP=\"disk\"', item) for item in self._open_file()]
        self._seek_write(self.newlines)
  
  #For each setting to change, create an instance
  memlock = ChangeSettings("/etc/security/limits.conf", "@audio\s-\smemlock (\d*)", "")
  raw1394 = ChangeSettings("/etc/udev/rules.d/60-raw1394.rules", r"KERNEL==\"raw1394\",\t\tGROUP=\"audio\"", "KERNEL==\"raw1394\",\t\tGROUP=\"audio\"")
  load_raw1394_module = ChangeSettings("/etc/modules", r"raw1394", "raw1394")
  nice = ChangeSettings("/etc/security/limits.conf", "@audio\s-\snice\s(.*)", "")
  
    
  def close_window(self, widget):
    os.remove('/var/lock/ubuntustudio-controls')
    gtk.main_quit()

  def about(self, widget):
    print 'showing widget'
    self.aboutWidget.run()
    self.aboutWidget.hide()

  def apply_settings(self, apply_button):
    #Get all the widgets and add those widgets to a diction in the format {widget : self.instance}
    self.active_settings = { self.builder.get_object('memlock_checkButton') : [self.memlock], 
                             self.builder.get_object('raw1394_checkbutton') : [self.raw1394, self.load_raw1394_module], 
                             self.builder.get_object('EnableNice') : [self.nice]
                             }
    #Apply those settings
    for widget, instanceArray in self.active_settings.items():
      for instanceName in instanceArray:
        if widget.get_active():
          print 'Applying settings'
          instanceName.ch_setting()
          apply_button.set_sensitive(False)
          print instanceName.line_replacement
        elif not widget.get_active():
          print 'Removing settings'
          instanceName.rm_setting()

  def update_memlock_amount(self, spin_object):   
    #Check to make sure that the value entered is an interger, then convert it to a string
    memlock_entry_amount = str(int(self.memtotal*(spin_object.get_value()/100)))
    self.memlock.line_replacement = "@audio - memlock " + memlock_entry_amount
    print self.memlock.line_replacement
    apply_button = self.builder.get_object('apply_button')
    apply_button.set_sensitive(True)

  def set_memlock_enable(self, memlock_checkButton):
    self.memlock_enabled = memlock_checkButton.get_active()
    memlock_spinbutton = self.builder.get_object('memlock_spinbutton')
    memlock_spinbutton.set_sensitive(memlock_checkButton.get_active())
    print self.memlock_enabled

  def check_raw1394_enabled(self, toggled_button):
    print self.settings_value['raw1394']
    first = self.settings_value['raw1394']['raw1394_checkbutton']
    if not first and toggled_button.get_active():
      self.show_raw1394_warning(toggled_button)
      first = True
    else:
      print 'Toggle button active, not running warning'
    self.set_apply_sensitive()

  def show_raw1394_warning(self, toggled_button):
      print 'Showing warning'
      self.raw1394Warning.run()
      self.raw1394Warning.hide()

  def set_apply_sensitive(self):
      apply_button = self.builder.get_object('apply_button')
      apply_button.set_sensitive(True)

  def set_nice_amount(self, spin_button):
    nice_amount = str(int(spin_button.get_value()))
    self.nice.line_replacement = '@audio - nice ' + nice_amount
    self.set_apply_sensitive()
    print self.nice.line_replacement

  def set_nice_enable(self, check_button):
    self.nice_spin_button = self.builder.get_object('nicePercentageAmount')
    self.nice_spin_button.set_sensitive(check_button.get_active())
    print 'Nice toggled'

  def serialize_settings(self):
    self.settings_value = {}
    self.settings_value['memlock'] = { 'memlock_checkButton' : self.builder.get_object('memlock_checkButton').get_active(), 'memlock_spinbutton' : self.builder.get_object('memlock_spinbutton').get_value() }
    self.settings_value['raw1394'] = { 'raw1394_checkbutton' : self.builder.get_object('raw1394_checkbutton').get_active() } 
    self.settings_value['nice'] = { 'EnableNice' : self.builder.get_object('EnableNice').get_active(), 'nicePercentageAmount' : self.builder.get_object('nicePercentageAmount').get_value() }
    us_config = open(os.path.expanduser('~/.us-controls'), 'w')
    cPickle.dump(self.settings_value, us_config)
    us_config.close()

  def load_settings(self):
    us_config = open(os.path.expanduser('~/.us-controls'), 'r')
    self.settings_value = cPickle.load(us_config)
    for key, value in self.settings_value.items():
      for widget, value in value.items():
        try:
          self.builder.get_object(widget).set_value(value)
        except:
          self.builder.get_object(widget).set_active(value)
    us_config.close()

print __name__
if __name__ == "__main__":
  #Make sure two instances are not running!
  if not os.path.exists('/var/lock/ubuntustudio-controls'):
    lockFile = open('/var/lock/ubuntustudio-controls', 'w')
  else:
    lock_error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, ('Only one instance of Ubuntu Studio Controls can be run at a time'))
    lock_error.run()
    sys.exit(1)
 
  # Bring up error if not root.
  if not os.geteuid()==0:  
    root_error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, ('You need to have admistrator privilages to run Ubuntu Studio Controls'))
    root_error.run()
    os.remove('/var/lock/ubuntustudio-controls')
    sys.exit(1)

  else:
    uscontrols = Uscontrols()
    try:
      uscontrols.load_settings()
    except IOError:
      #Initialize settings, even if empty...
      uscontrols.serialize_settings()
    gtk.main()
    uscontrols.serialize_settings()
