#!/usr/bin/python

# LADITools - Linux Audio Desktop Integration Tools
# ladilog - A log viewer for your Linux Audio Desktop
# 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 signal
from subprocess import Popen, PIPE
import pty
from signal import SIGTERM
import termios
import tty
import gettext
import argparse

sig_handler = signal.getsignal(signal.SIGTERM)
signal.signal(signal.SIGINT, sig_handler)

from laditools import _gettext_domain
gettext.install(_gettext_domain)

from laditools import get_version_string
from laditools import LadiConfiguration

from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import Vte

from laditools.gtk import find_data_file

timeout_add = GObject.timeout_add

# Default configuration
max_lines_default = 100

# Output the last <lines> lines
def read_last(lfile, lines):
    chunk_size = lines * 60
    lfile.seek(0, 2)
    endpos = lfile.tell()
    pos = endpos - chunk_size
    if pos < 0:
        pos = 0
    backlog = ''
    backlog_size = 0
    lines += 1
    while pos >= 0 and backlog_size <= lines:
        lfile.seek(pos, 0)
        s = lfile.read(chunk_size)
        pos = pos - chunk_size
        backlog_size += s.count("\n")
        backlog = s + backlog
    backlog = backlog.strip().split("\n")
    if len(backlog) > lines:
        backlog = backlog[-lines:]
    lfile.seek(endpos, 0)
    return backlog

class ladilog(object):
    def __init__ (self):
        self.log_files = [
            {
            'name': 'JACK',
            'config_name': 'jackdbus_log',
            'config_default': os.sep.join([os.environ['HOME'], ".log", "jack", "jackdbus.log"])
            },
            {
            'name': 'LADISH',
            'config_name': 'ladish_log',
            'config_default': os.sep.join([os.environ['HOME'], ".log", "ladish", "ladish.log"])
            },
            {
            'name': 'A2J',
            'config_name': 'a2j_log',
            'config_default': os.sep.join([os.environ['HOME'], ".log", "a2j", "a2j.log"])
            }
            ]
        # Handle the configuration
        self.global_config = LadiConfiguration ()
        self.param_dict = self.global_config.get_config_section ('ladilog')

        for log in self.log_files:
            if self.param_dict != None:
                if log['config_name'] not in self.param_dict:
                    self.param_dict[log['config_name']] = log['config_default']
            else:
                self.param_dict = {}
                self.param_dict[log['config_name']] = log['config_default']

        if 'max_lines' not in self.param_dict:
            self.param_dict['max_lines'] = max_lines_default

        for log in self.log_files[:]:
            log['logfile_path'] = self.param_dict[log['config_name']]
            # skip logfiles that dont exist
            if not os.access(log['logfile_path'], os.R_OK):
                self.log_files.remove(log)
                sys.stderr.write( _("Skipping '%s' because it does not exist\n") % log['logfile_path'])
            else:
                sys.stderr.write( _("Watching %s\n") % log['logfile_path'])
            sys.stderr.flush()

        max_lines_text = self.param_dict['max_lines']
        self.max_lines = int (max_lines_text)
        # Load the glade file
        builder = Gtk.Builder()
        builder.add_from_file(find_data_file("ladilog_ui.ui"))
        sys.stderr.write( _("Loading interface from %s\n") % find_data_file("ladilog_ui.ui"))
        sys.stderr.flush()
        # Get the ui ready for action
        self.event_dict = {"on_ladilog_ui_destroy" : self.on_quit,
            "on_ladilog_ui_delete" : self.on_delete,
            "on_close_button_clicked" : self.on_quit,
            "on_clear_button_clicked" : self.on_clear_text,
            "on_purge_button_clicked" : self.on_purge}
        builder.connect_signals(self.event_dict)

        self.ui = ui = builder.get_object("ladilog_ui")
        self.logview_notebook = builder.get_object ("ladilog_notebook")
        # Create our terminal and display it
        for log in self.log_files:
            log['scrolled_window'] = sw = Gtk.ScrolledWindow()
            log['term'] = term = Vte.Terminal.new ()
            sw.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
                          vscrollbar_policy=Gtk.PolicyType.ALWAYS)
            sw.add(term)
            sw.show()
            term.set_scroll_on_output(True)
            log["tab_label"] = Gtk.Label(label=log["name"])

            self.logview_notebook.append_page(log["scrolled_window"],
                                              log["tab_label"])

        # Make it do something...
        for log in self.log_files:
            try:
                log['log_file'] = open(log['logfile_path'], "rb")
                sys.stderr.write (_("Opening %s...\n") % log['logfile_path'])
                lines = read_last(log['log_file'], self.max_lines)
                for line in lines:
                    line = line.strip('\r\n') + '\r\n'
                    log["term"].feed(line, -1)
            except ValueError:
                sys.stderr.write( _("You called Popen with invalid arguments... dumbass\n") )
            except:
                sys.stderr.write( _("Unexpected error: %s\n") % (sys.exc_info ()[0]))
            finally:
                sys.stderr.flush()

        ui.show_all()
        self.auto_updater = timeout_add(250, self.update, None)

    def update(self, user_data = None):
        # Append latest output to the buffer
        for log in self.log_files:
            line = log['log_file'].readline()
            while line:
                log["term"].feed(line + '\r', -1)
                line = log['log_file'].readline()
            log['log_file'].seek(log['log_file'].tell())
        return True

    def on_delete(self, widget=None, data=None):
        return False

    def on_quit (self, data=None):
        Gtk.main_quit ()

    def on_clear_text (self, data=None):
        current_view = self.logview_notebook.get_current_page ()
        self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)

    def on_purge (self, data=None):
        current_view = self.logview_notebook.get_current_page ()
        # Opens the file in write anew mode thus clearing the file and close it right away
        open (self.log_files[current_view]['logfile_path'], "w+")
        self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)

    def run (self):
        Gtk.main ()
        self.global_config.set_config_section ("ladilog", self.param_dict)
        self.global_config.save ()
        return 0

#try:
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description=_('JACK, ladish and a2jmidid log viewer'),
                                     epilog=_('This program is part of the LADITools suite.'))
    parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())

    parser.parse_args()
    ladilog().run()
    sys.exit(0)
#except Exception, e:
#    error = Gtk.MessageDialog(None,
#                              Gtk.DialogFlags.MODAL,
#                              Gtk.MessageType.ERROR,
#                              Gtk.ButtonsType.OK,
#                              _("Unexpected error\n\n") + repr(e))
#    error.run()
#    sys.exit(1)
