#! /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 os, sys
import gobject
import getopt
from gettext import gettext as _

import pygtk
pygtk.require('2.0')
import gtk
from tcosmonitor import shared

# load conf file and exit if not active
if not shared.test_start("tcos-volume-manager") :
    print >> sys.stderr, "tcos-volume-manager disabled at %s" % (shared.module_conf_file)
    #print("tcos-volume-manager disabled at %s" % (shared.module_conf_file), file=sys.stderr)
    sys.exit(1)


import pwd

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

def get_username():
    return pwd.getpwuid(os.getuid())[0]


def usage():
    print ("tcos-volume-manager help:")
    print ("")
    print ("   tcos-volume-manager [--host=XXX.XXX.XXX.XXX] ")
    print ("                 (force host to connect to change volumes, default is DISPLAY)")
    print ("   tcos-volume-manager -d [--debug]  (write debug data to stdout)")
    print ("   tcos-volume-manager -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)

shared.remotehost=str(shared.parseIPAddress(os.environ["DISPLAY"]))

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

if shared.remotehost == "":
    print ("tcos-volume-manager: Not allowed to run in local DISPLAY")
    #shared.error_msg ( _("tcos-volume-manager isn't allowed to run in local DISPLAY\nForce with --host=xx.xx.xx.xx") )
    sys.exit(0)



class TcosVolumeManager:
    def __init__(self, host):
        self.host=host
        self.name="TcosVolumeManager"
        self.visible=False
        
        if hasattr(gtk, 'status_icon_new_from_file'):
            # use gtk.status_icon
            icon = gtk.status_icon_new_from_file(shared.IMG_DIR + "tcos-volume-32x32.png")
            icon.set_tooltip( _("Tcos Sound levels on:\n%s") %(self.host) )
            icon.connect("activate", self.on_tray_icon_press_event)
        else:
            shared.error_msg( _("ERROR: No tray icon support") )
            sys.exit(1)
        
        
        from tcosmonitor.ping import PingPort
        if PingPort(self.host, shared.xmlremote_port, 0.5).get_status() != "OPEN":
            shared.error_msg( _("ERROR: It appears that TcosXmlRpc is not running on %s.") %(self.host) )
            sys.exit(1)
            
        
        import tcosmonitor.TcosXauth
        self.xauth=tcosmonitor.TcosXauth.TcosXauth(self)
        self.xauth.init_standalone()
        
        # get all channels
        import tcosmonitor.TcosXmlRpc
        import tcosmonitor.TcosConf
        self.config=tcosmonitor.TcosConf.TcosConf(self, openfile=False)
        self.xmlrpc=tcosmonitor.TcosXmlRpc.TcosXmlRpc(self)
        
        nossl=True
        # make a test and exit if no cookie match
        if not self.xauth.test_auth(nossl):
            print ("tcos-volume-manager: ERROR: Xauth cookie don't match")
            #sys.exit(1)
        
        self.xmlrpc.newhost(self.host,nossl)
        if not self.xmlrpc.connected:
            shared.error_msg( _("Error connecting with TcosXmlRpc in %s.") %(self.host) )
            sys.exit(1)
        
        # check for enabled sound
        have_sound=self.xmlrpc.IsEnabled("TCOS_SOUND")
        if not have_sound:
            print ("tcos-volume-manager: TCOS_SOUND is disabled")
            sys.exit(0)

        self.allchannels=self.xmlrpc.GetSoundChannelsContents()
        print_debug ("__init__() %s" %( self.allchannels ) )
        
        self.ui = gtk.Builder()
        self.ui.set_translation_domain(shared.PACKAGE)
        
        # Widgets
        self.ui.add_from_file(shared.GLADE_DIR + 'tcos-volume-manager.ui')
        self.mainwindow = self.ui.get_object('mainwindow')
        
        # close windows signals
        #self.mainwindow.connect('destroy', self.quitapp )
        self.mainwindow.connect('delete-event', self.mainwindow_close )
        
        self.mainlabel=self.ui.get_object('mainlabel')
        
        self.scrolledwindow=self.ui.get_object('scrolledwindow')
        self.scrolledwindow2=self.ui.get_object('scrolledwindow2')
        
        self.quitbutton=self.ui.get_object('quitbutton')
        self.quitbutton.connect('clicked', self.quitapp )
        
        self.statusbar=self.ui.get_object('statusbar')
        self.refreshbutton=self.ui.get_object('refreshbutton')
        self.refreshbutton.connect('clicked', self.on_refresh_button )
        
        self.restartbutton=self.ui.get_object('restartbutton')
        self.restartbutton.connect('clicked', self.on_restart_button )
        
        # only show if we found this file in $HOME dir
        allowfile=os.path.expanduser("~/.tcos-volume-manager.allow.restartpulse")
        if os.path.isfile(allowfile):
            self.restartbutton.show()
        
        # restart on start
        restartfile=os.path.expanduser("~/.tcos-volume-manager.start.restartpulse")
        if os.path.isfile(restartfile):
            self.xmlrpc.RestartSoundDaemon()
        
        # FIXME try to not focus on quitbutton
        self.refreshbutton.grab_focus()
        
        self.get_channel_info()
        
    def on_refresh_button(self, widget):
        self.allchannels=self.xmlrpc.GetSoundChannelsContents()
        self.scrolledwindow.foreach( self.delete_child, self.scrolledwindow )
        self.scrolledwindow2.foreach( self.delete_child, self.scrolledwindow2 )
        self.get_channel_info()

    def on_restart_button(self, widget):
        self.xmlrpc.RestartSoundDaemon()
        self.on_refresh_button(None)

    def delete_child(self, widget, scrolled):
        scrolled.remove(widget)

    def get_channel_info(self):
        # retry cookie auth
        nossl=True
        self.xauth.test_auth(nossl)
        
        primary_channels=[]
        secondary_channels=[]
        if self.allchannels != None and len(self.allchannels) > 0:
            gobject.timeout_add( 50, self.write_into_statusbar, _("Loading channels info...") )
            for channel in self.allchannels:
                #if not channel in shared.sound_only_channels:
                if not channel['name'] in shared.sound_only_channels:
                    secondary_channels.append(channel)
                    continue
                primary_channels.append(channel)
            gobject.timeout_add( 500, self.populate_mixer, primary_channels, self.scrolledwindow)
            gobject.timeout_add( 1500, self.populate_mixer, secondary_channels, self.scrolledwindow2)
            #gobject.timeout_add( 4000, self.write_into_statusbar, _("Ready") )
            
        else:
            print_debug ( "ERROR: No auth" )
            gobject.timeout_add( 2000, self.write_into_statusbar, _("Error loading channels info (xauth error)") )
        
        self.mainwindow.set_icon_from_file(shared.IMG_DIR + 'tcos-icon-32x32.png')
        self.mainwindow.set_title( _("Tcos Volume Manager")  )
        self.mainlabel.set_markup( _("<span size='large'><b>Sound mixer of %s host</b></span>") %(self.host) )
        
        #self.mainwindow.show()
        
        #self.populate_mixer(primary_channels, self.scrolledwindow)
        #self.populate_mixer(secondary_channels, self.scrolledwindow2)
        
    
    def populate_mixer(self, all_channels, scrollwindow):
        box1 = gtk.HBox(False, 0)
        box1.set_border_width(0)
        box1.show()
        scrollwindow.add_with_viewport(box1)
        
        for channel in all_channels:
            #frame = gtk.Frame(channel)
            frame = gtk.Frame(channel['name'])
            #frame.show()
            box2 = gtk.VBox(True, 0)
            box2.set_border_width(0)
            
            ###########################################################
            #value=self.xmlrpc.GetSoundInfo(channel, mode="--getlevel")
            #value=value.replace('%','')
            value=channel['level']
            try:
                value=float(value)
            except Exception, err:
                print_debug("Exception, can't get float value, error=%s"%err)
                value=0.0
            ctype=channel['type']
            #ismute=self.xmlrpc.GetSoundInfo(channel, mode="--getmute")
            ismute=channel['mute']
            if ismute == "off":
                ismute = True
            else:
                ismute = False
            #print_debug ( "populate_mixer() channel=%s ismute=%s volume level=%s" %(channel, ismute, value) )
            print_debug ( "populate_mixer() channel=%s ismute=%s volume level=%s ctype=%s" %(channel['name'], ismute, value, ctype) )
            #############################################################
            adjustment = gtk.Adjustment(value=0,
                                         lower=0,
                                         upper=100,
                                         step_incr=1,
                                         page_incr=1)
            volume_slider = None
            volume_slider = gtk.VScale(adjustment)
            volume_slider.set_digits(0)
            volume_slider.set_inverted(True)
            
            volume_slider.set_size_request(30, 100)
            volume_slider.set_value_pos(gtk.POS_TOP)     
            volume_slider.set_value( value )
            #volume_slider.connect("button_release_event", self.slider_value_changed, adjustment, channel, self.host)
            #volume_slider.connect("scroll_event", self.slider_value_changed, adjustment, channel, self.host)
            volume_slider.connect("button_release_event", self.slider_value_changed, adjustment, channel['name'], self.host)
            volume_slider.connect("scroll_event", self.slider_value_changed, adjustment, channel['name'], self.host)
            if "volume" in ctype:
                volume_slider.show()
            else:
                volume_slider.hide()
            
            box2.pack_start(volume_slider, False, True, 0)
            
            
            
            volume_checkbox=gtk.CheckButton(label=_("Mute"), use_underline=True)
            volume_checkbox.set_active(ismute)
            #volume_checkbox.connect("toggled", self.checkbox_value_changed, channel, self.host)
            volume_checkbox.connect("toggled", self.checkbox_value_changed, channel['name'], self.host)
            if "switch" in ctype:
                volume_checkbox.show()
            else:
                volume_checkbox.hide()
            
            
            box2.pack_start(volume_checkbox, False, True, 0)
            box2.show()
            frame.add(box2)
            
            frame.show()
            box1.pack_start(frame, True, True, 0)
        
        # write in statusbar if populating primary controls
        if scrollwindow == self.scrolledwindow:
            self.write_into_statusbar( _("Main controls ready") )
        
        # write in statusbar if populating secondary controls
        if scrollwindow == self.scrolledwindow2:
            self.write_into_statusbar( _("All remote controls loaded.") )
        return False
        

    def slider_value_changed(self, widget, event, adj, channel, ip):
        value=widget.get_value()
        print_debug ( "slider_value_changed() ip=%s channel=%s value=%s" %(ip, channel, value) )
        
        self.write_into_statusbar( \
        _("Changing value of %(channel)s channel, to %(value)s%%..." )\
         %{"channel":channel, "value":value} )
        
        tmp=self.xmlrpc.SetSound(ip, channel, str(value)+"%")
        newvalue="%2d%%"%int(tmp['level'])
        
        self.write_into_statusbar( \
        _("Changed value of %(channel)s channel, to %(value)s" ) \
        %{"channel":channel, "value":newvalue} )
    
    def checkbox_value_changed(self, widget, channel, ip):
        value=widget.get_active()
        if not value:
            value="off"
            self.write_into_statusbar( _("Unmuting %s channel..."  ) %(channel) )
            tmp=self.xmlrpc.SetSound(ip, channel, value="", mode="--setunmute")
            newvalue=tmp['mute']
        else:
            value="on"
            self.write_into_statusbar( _("Muting %s channel..."  ) %(channel) )
            tmp=self.xmlrpc.SetSound(ip, channel, value="", mode="--setmute")
            newvalue=tmp['mute']
        self.write_into_statusbar( _("Status of %(channel)s channel, is \"%(newvalue)s\""  )\
         %{"channel":channel, "newvalue":newvalue} ) 

    def write_into_statusbar(self, msg, *args):
        context_id=self.statusbar.get_context_id("status")
        self.statusbar.pop(context_id)
        self.statusbar.push(context_id, msg)
        return False

    def on_tray_icon_press_event(self, *args):
        if self.visible:
            self.mainwindow.hide()
        else:
            self.mainwindow.show()
        self.visible = not self.visible
        return
    
    def mainwindow_close(self, widget, event):
        print_debug ( "mainwindow_close() closing mainwindow to systray" )
        self.visible=False
        self.mainwindow.hide()
        return True

    def quitapp(self, *args):
        print_debug ( _("Exiting") )
        self.mainloop.quit()
        

    def run (self):
        self.mainloop = gobject.MainLoop()
        try:
            self.mainloop.run()
        except KeyboardInterrupt: # Ctrl+C Event
            self.quitapp()

if __name__ == "__main__":
    app=TcosVolumeManager(shared.remotehost)
    app.run()
