#!/usr/bin/python
# LADITools - Linux Audio Desktop Integration Tools
# ladi-system-tray - System tray integration for LADI
# Copyright (C) 2011-2012 Alessio Treglia <quadrispro@ubuntu.com>
# Copyright (C) 2007-2010, Marc-Olivier Barre <marco@marcochapeau.org>
# Copyright (C) 2007-2009, Nedko Arnaudov <nedko@arnaudov.name>
#
# This program 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 3 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/>.

import os
import sys
import gettext
import argparse

from laditools import _gettext_domain
gettext.install(_gettext_domain)

from laditools import get_version_string
from laditools import LadiConfiguration
from laditools import LadiManager
from laditools import LadiApp

from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject

try:
    from gi.repository import AppIndicator3
except:
    AppIndicator3 = None

from laditools.gtk import LadiMenu
from laditools.gtk import find_data_file

timeout_add = GObject.timeout_add

class LadiStatusIcon (LadiMenu, LadiApp):

    _appname = 'ladi-system-tray'
    _appname_long = _("LADI System Tray")
    _appid = 'org.linuxaudio.ladi.systemtray'

    # Default configuration
    _default_config = {
        'autostart' : False,
    }

    def on_about(self, *args):
        LadiMenu.on_about(self, version=get_version_string())

    def quit(self, *args, **kwargs):
        # Some default config might need to be injected in the config file,
        # we handle all that before we quit.
        self.global_config.set_config_section (self.appname, self.config_dict)
        self.global_config.save ()
        Gtk.main_quit()

    def set_tooltip_text(self, text): pass

    def __init__ (self, config_filename = None):
        # Handle the configuration
        self.icon_state = ""
        self.last_status_text = ""
        self.diagnose_text = None
        self.status_icons = {'started'  : 'ladi-started',
                             'stopped'  : 'ladi-stopped',
                             'starting' : 'ladi-starting'}
        self.global_config = LadiConfiguration(self.appname,
                                               self._default_config,
                                               config_filename)
        self.config_dict = self.global_config.get_config_section (self.appname)
        autostart = bool(eval(self.config_dict['autostart']))
        # Build the UI
        LadiMenu.__init__(self,
                          autostart,
                          quit = self.quit)
        LadiApp.__init__(self)
        self.connect_signals_quit()

    def menu_activate(self, status_icon, button, activate_time, user_data=None):
        menu = self.create_menu()
        menu.popup (parent_menu_shell=None,
                    parent_menu_item=None,
                    func=self.position_menu,
                    data=self,
                    button=button,
                    activate_time=activate_time)
        menu.reposition ()

    def set_starting_status (self):
        self.set_tooltip_safe ("JACK is starting")
        self.set_icon ("starting")

    def set_tooltip_safe (self, text):
        if text != self.last_status_text:
            self.set_tooltip_text (text)
            self.last_status_text = text

    def run(self):
        Gtk.main ()

class LadiStatusTray(Gtk.StatusIcon, LadiStatusIcon):

    def __init__(self):
        LadiStatusIcon.__init__(self)
        GObject.GObject.__init__ (self)
        self.set_icon ("stopped")
        # Get the initial status
        self.update ()
        # Add the auto update callback
        self.auto_updater = timeout_add (250, self.update, None)
        # Make the menu popup when the icon is right clicked
        self.connect ("popup-menu", self.menu_activate)
        self.set_title(self.appname_long)

    def do_button_press_event(self, event):
        if event.type != Gdk.EventType._2BUTTON_PRESS:
            return False
        self.on_menu_launch_handler(None, "gladish")
        return True

    def update (self, user_data = None):
        try:
            if self.jack_is_started():
                # Get Realtime status
                if self.jack_is_realtime():
                    status_text = "RT | "
                else:
                    status_text = ""
                # Get DSP Load
                status_text += str (round (float (self.jack_get_load()),1)) + "% | "
                # Get Xruns
                status_text += str (self.jack_get_xruns())
                # Set a started status
                self.set_tooltip_safe (status_text)
                self.set_icon ("started")
            else:
                self.set_tooltip_safe ("JACK is stopped")
                self.set_icon ("stopped")
            self.clear_diagnose_text()
        except Exception, e:
            self.set_tooltip_safe ("JACK is sick")
            self.set_diagnose_text(repr(e))
            self.set_icon ("stopped")
            self.clear_jack_proxies()
        finally:
            LadiManager.update(self)
        return True

    def set_icon (self, newstate):
        if self.icon_state == newstate:
            return
        self.icon_state = newstate
        self.set_from_icon_name(self.status_icons[newstate])

class LadiStatusIndicator(LadiStatusIcon):

    def update (self, user_data = None):
        try:
            if self.jack_is_started():
                # Get Realtime status
                if self.jack_is_realtime():
                    status_text = "RT | "
                else:
                    status_text = ""
                # Get DSP Load
                status_text += str (round (float (self.jack_get_load()),1)) + "% | "
                # Get Xruns
                status_text += str (self.jack_get_xruns())
                # Set a started status
                self.set_tooltip_safe (status_text)
                self.set_icon ("started")
            else:
                self.set_tooltip_safe ("JACK is stopped")
                self.set_icon ("stopped")
            self.clear_diagnose_text()
        except Exception, e:
            self.set_tooltip_safe ("JACK is sick")
            self.set_diagnose_text(repr(e))
            self.set_icon ("stopped")
            self.clear_jack_proxies()
        finally:
            LadiManager.update(self)
        return True

    def set_icon (self, newstate):
        if self.icon_state == newstate:
            return
        self.icon_state = newstate
        self.indicator.set_icon(self.status_icons[newstate])

    def create_menu(self):
        menu_items = []

        ladish_available = self.ladish_is_available()

        menu_items.append((Gtk.ImageMenuItem(_("LADI Player")), self.on_menu_launch_handler, "ladi-player"))
        if ladish_available:
            menu_items.append((Gtk.ImageMenuItem(_("Session editor")), self.on_menu_launch_handler, "gladish"))

        menu_items.append((Gtk.SeparatorMenuItem.new(),))
        menu_items.append((Gtk.ImageMenuItem(_("Settings")), self.on_menu_launch_handler, "ladi-control-center"))
        menu_items.append((Gtk.ImageMenuItem(_("Log Viewer")), self.on_menu_launch_handler, "ladi-system-log"))

        menu_items.append((Gtk.SeparatorMenuItem.new(),))
        if hasattr(self, 'on_about'):
            menu_items.append((Gtk.ImageMenuItem(_("About")), self.on_about, None))
        menu_items.append((Gtk.ImageMenuItem(_("Quit")), self.on_menu_command, self.quit))

        menu = Gtk.Menu()
        for menu_tuple in menu_items:
            item = menu_tuple[0]
            if len(menu_tuple) > 1:
                callback = menu_tuple[1]
                exec_path = menu_tuple[2]
            menu.append(item)
            if type(item) is not Gtk.SeparatorMenuItem:
                if callback in (self.studio_list_fill, self.configure_list_fill):
                    item.set_submenu(Gtk.Menu())
                item.connect("activate", callback, exec_path)
        menu.show_all()
        return menu


    def __init__(self):
        LadiStatusIcon.__init__(self)
        self.indicator = indicator = AppIndicator3.Indicator.new('ladi-indicator',
                                                             find_data_file('scalable/apps/laditools.svg'),
                                                             AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
        self.menu = menu = self.create_menu()

        indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
        indicator.set_menu(menu)
        menu.show()
        # Get the initial status
        self.update ()
        # Add the auto update callback
        self.auto_updater = timeout_add (250, self.update, None)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=_('system tray icon that allows users to start, stop and '
                                                    'monitor JACK, as well as start some JACK related applications'),
                                     epilog=_('This program is part of the LADITools suite.'))
    parser.add_argument('--no-appindicator',
                        action='store_true',
                        help=_('Force fallback to system tray.'))
    parser.add_argument('--version',
                        action='version',
                        version="%(prog)s " + get_version_string())
    args = parser.parse_args()

    Gtk.init(None)

    if (not args.no_appindicator) and AppIndicator3:
        LadiStatusIndicator().run()
    else:
        LadiStatusTray().run()

    sys.exit(0)
