#!/usr/bin/python
# LADITools - Linux Audio Desktop Integration Tools
# laditray - System tray integration for LADI
# Copyright (C) 2012 Alessio Treglia <quadrispro@ubuntu.com>
#
# 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 time
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 LadiApp

from gi.repository import Gtk
from gi.repository import GObject
from laditools import LadiManager
from laditools.gtk import LadiManagerGtk
from laditools.gtk import find_data_file

timeout_add = GObject.timeout_add

class LadiPlayer(LadiManagerGtk, LadiApp):

    _appname = 'ladi-player'
    _appname_long = _("LADI Player")
    _appid = 'org.linuxaudio.ladi.player'

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

    def on_about(self, *args):
        LadiManagerGtk.on_about(self, parent=self.window_main, version=get_version_string())

    def quit(self, *args, **kwargs):
        self.global_config.set_config_section (self.appname,
                                               self.config_dict)
        self.global_config.save()
        Gtk.main_quit()

    def _run_select_studio_dialog(self, title, *args):
        studio_list = self.get_ladish_controller().studio_list()
        if not studio_list:
            dlg = Gtk.MessageDialog(None,Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                        Gtk.MessageType.INFO,
                                        Gtk.ButtonsType.CLOSE,
                                        _('No studio is available.'))
            dlg.set_transient_for(self.window_main)
            dlg.set_title(title)
            dlg.run()
            dlg.destroy()
            return None

        dlg = Gtk.Dialog()
        treeview = Gtk.TreeView()
        model = Gtk.ListStore(GObject.TYPE_STRING)
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn('Available studios', renderer, text=0)

        treeview.set_model(model)
        treeview.append_column(column)
        treeview.set_cursor(Gtk.TreePath(path=0),
                                    focus_column=column,
                                    start_editing=False)

        for studio in studio_list:
            model.append((studio,))

        dlg.set_transient_for(self.window_main)
        dlg.set_modal(True)
        dlg.set_destroy_with_parent(True)
        dlg.set_title(title)
        dlg.get_content_area().pack_start(child=treeview,
                                         expand=True,
                                         fill=True,
                                         padding=10)
        dlg.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
        dlg.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
        dlg.show_all()

        response = dlg.run()
        ret = None
        if response == Gtk.ResponseType.OK:
            path, column = treeview.get_cursor()
            ret = model[path][0]
        dlg.hide()
        return ret

    def _toolbuttons_set_active(self, group, **kwargs):
        buttons = getattr(self, "%s_status_buttons" % group)
        if 'all' in kwargs:
            status = kwargs['all']
            for button in buttons:
                buttons[button].set_sensitive(status)
        else:
            for button in kwargs:
                buttons[button].set_sensitive(kwargs[button])

    def jack_is_started(self, *args, **kwargs):
        while True:
            try:
                return LadiManagerGtk.jack_is_started(self, *args, **kwargs)
            except:
                time.sleep(0.5)
                continue

    def ladish_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('ladish', **kwargs)
    def jack_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('jack', **kwargs)
    def a2j_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('a2j', **kwargs)

    def ladish_status_buttons_update(self):
        buttons = self.ladish_status_buttons

        # Setup ladish controls
        if self.ladish_is_available():
            # Buttons "rename" and "unload"
            if self.studio_is_loaded():
                self.ladish_toolbuttons_set_active(unload=True, rename=True)
                # Buttons "start" and "stop"
                if self.studio_is_started():
                    self.ladish_toolbuttons_set_active(start=False, stop=True, save=True)
                else:
                    self.ladish_toolbuttons_set_active(start=True, stop=False, save=False)
            else:
                self.ladish_toolbuttons_set_active(start=True,
                                             stop=False,
                                             save=False,
                                             unload=False,
                                             rename=False)
        else:
            self.ladish_toolbuttons_set_active(all=False)

    def jack_status_buttons_update(self):
        if not self.jack_is_available():
            return

        buttons = self.jack_status_buttons
        ladish_available = self.ladish_is_available()
        jack_started = self.jack_is_started()

        if jack_started:
            self.jack_toolbuttons_set_active(jack_start=False,
                                             jack_stop=(not ladish_available),
                                             jack_reset_xruns=True,
                                             jack_reactivate=True)
        else:
            self.jack_toolbuttons_set_active(jack_start=True,
                                             jack_stop=False,
                                             jack_reset_xruns=False,
                                             jack_reactivate=True)


    def a2j_status_buttons_update(self):
        if not self.a2j_is_available():
            self.a2j_toolbuttons_set_active(all=False)
            return

        buttons = self.a2j_status_buttons
        ladish_available = self.ladish_is_available()
        a2j_started = self.a2j_is_started()

        if not ladish_available:
            if a2j_started:
                self.a2j_toolbuttons_set_active(a2j_start=False,
                                                a2j_stop=True,
                                                a2j_reactivate=True)
            else:
                self.a2j_toolbuttons_set_active(a2j_start=True,
                                                a2j_stop=False,
                                                a2j_reactivate=True)
        else:
            self.a2j_toolbuttons_set_active(a2j_start=False,
                                            a2j_stop=False,
                                            a2j_reactivate=True)

    def update_status_buttons(self):

        # Update widgets
        self.ladish_status_buttons_update()
        self.jack_status_buttons_update()
        self.a2j_status_buttons_update()

        # Update status label and window icon
        if self.jack_is_started():
            self.window_main.set_icon_name("ladi-started")
            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.status_label.set_label (status_text)
        else:
            self.window_main.set_icon_name("ladi-stopped")
            self.status_label.set_label(_('<i>Stopped</i>'))

    def update(self, *args, **kwargs):
        self.update_status_buttons()
        LadiManagerGtk.update(self, *args, **kwargs)
        return True

    def _set_starting_status(self):
        self.window_main.set_icon_name("ladi-starting")

    def action_ladish_new(self, action, *args):
        self.studio_new()

    def action_ladish_start(self, action, *args):
        if self.studio_is_loaded():
            if not self.studio_is_started():
                self._set_starting_status()
                self.studio_start()
                self.update_status_buttons()
        else:
            self._set_starting_status()
            self.jack_start()
            self.update_status_buttons()

    def action_ladish_save(self, action, *args):
        self.studio_save()

    def action_ladish_stop(self, action, *args):
        if self.jack_is_started() and self.studio_is_started():
            self.studio_stop()
            self.update_status_buttons()

    def action_ladish_rename(self, action, *args):
        self.studio_rename()
        self.update_status_buttons()

    def action_ladish_load(self, action, *args):
        selection = self._run_select_studio_dialog(_('Load studio'))
        if selection:
            self.studio_load(studio=selection)
        return selection

    def action_ladish_delete(self, action, *args):
        selection = self._run_select_studio_dialog(_('Delete studio'))
        if selection:
            LadiManager.studio_delete(self, studio=selection)
        return selection

    def action_ladish_unload(self, action, *args):
        while True:
            try:
                if self.studio_is_loaded():
                    self.studio_unload()
                    self.update_status_buttons()
                    break
            except:
                time.sleep(0.5)
                continue

    def action_ladish_reactivate(self, action, *args):
        self.ladish_reactivate()

    def action_jack_start(self, action, *args):
        self._set_starting_status()
        self.jack_start()
    def action_jack_stop(self, action, *args):
        self.jack_stop()
    def action_jack_reset_xruns(self, action, *args):
        self.jack_reset_xruns()
    def action_jack_reactivate(self, action, *args):
        self.jack_reactivate()

    def action_a2j_start(self, action, *args):
        self.a2j_start()
    def action_a2j_stop(self, action, *args):
        self.a2j_stop()
    def action_a2j_reactivate(self, action, *args):
        self.a2j_reactivate()

    def action_launcher_launch(self, action, *args):
        self.launcher_exec(command=self._launcher_which(action.get_name()))

    def __init__(self):
        # Initialize app
        LadiApp.__init__(self)
        # Handle the configuration
        self.global_config = LadiConfiguration(self.appname, self._default_config)
        self.config_dict = self.global_config.get_config_section (self.appname)
        autostart = bool(eval(self.config_dict['autostart']))

        LadiManagerGtk.__init__(self, autostart)

        # Handle signals
        self.connect_signals_quit()

        # Build the UI
        builder = Gtk.Builder()
        ui_path = find_data_file("ladi-player.ui")
        builder.add_from_file(ui_path)
        sys.stderr.write( _("Loading interface from %s\n") % ui_path)
        sys.stderr.flush()

        # Retrieve objects
        self.window_main = builder.get_object("window_main")
        actiongroup_ladish = builder.get_object("actiongroup_ladish")
        actiongroup_jack = builder.get_object("actiongroup_jack")
        actiongroup_a2j = builder.get_object("actiongroup_a2j")
        actiongroup_launcher = builder.get_object("actiongroup_launcher")
        self.status_label = builder.get_object('toolbutton_label_status')

        # Setup status buttons
        self.ladish_status_buttons = ladish_status_buttons = {}
        self.jack_status_buttons = jack_status_buttons = {}
        self.a2j_status_buttons = a2j_status_buttons = {}
        self.launcher_status_buttons = launcher_status_buttons = {}

        for action in actiongroup_ladish.list_actions():
            ladish_status_buttons[action.get_name()] = action
        for action in actiongroup_jack.list_actions():
            jack_status_buttons[action.get_name()] = action
        for action in actiongroup_a2j.list_actions():
            a2j_status_buttons[action.get_name()] = action
        for action in actiongroup_launcher.list_actions():
            launcher_status_buttons[action.get_name()] = action

        # Remove launchers for unavailable commands
        for command in launcher_status_buttons:
            if not self._launcher_which(command):
                launcher_status_buttons[command].set_active(False)

        # Accelerators
#        accelgroup = builder.get_object("accelgroup1")
#        action = actiongroup_launcher.get_action("gladish")
#        action.set_accel_group(accelgroup)
#        action.set_accel_path("menu_studio")

        # Get the initial status
        self.update ()
        # Add the auto update callback
        self.auto_updater = timeout_add (250, self.update, None)

        builder.connect_signals(self)

    def run(self):
        self.window_main.show_all()
        Gtk.main()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=_('graphical front-end 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('--version', action='version', version="%(prog)s " + get_version_string())
    parser.parse_args()

    Gtk.init(None)

    LadiPlayer().run()

    sys.exit(0)
