#!python
#
# An xconsole-like syslog monitor on X11.
# Copyright (c) 2018-2019, Hiroyuki Ohsaki.
# All rights reserved.
#
# $Id: xpylog,v 1.10 2019/07/03 13:53:20 ohsaki Exp $
#

# 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
# 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 <https://www.gnu.org/licenses/>.

import re
import time

from Xlib import X, display
import x11util

COLOR_TABLE = {
    'normal': [None, 'aquamarine1'], 'alert':
    [r'(warning|notice|sudo|ssh)', 'orange'], 'critical': [
        r'(error|unable|invalid|illegal|failed|failure|critical|refused)',
        'OrangeRed'
    ]
}
NLINES = 64
MAX_FPS = 10

def find_color(line):
    """Pick the appropriate color according to the content of LINE."""
    for categ in ['alert', 'critical']:
        regexp, color = COLOR_TABLE[categ]
        if re.search(regexp, line):
            return color
    return COLOR_TABLE['normal'][1]

def main_loop(disp, screen, window, width, height, gcs):
    # main loop
    f = open('/dev/xconsole', encoding='ascii', errors='backslashreplace')
    log_lines = []
    last_update = 0
    while True:
        line = f.readline().rstrip()
        # remove T between date and time
        line = re.sub(r'(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d)', r'\1 \2', line)
        # delete subseconds and time zone
        line = re.sub(r'(\d\d:\d\d:\d\d)\.\d+\+\d\d:\d\d', r'\1', line)

        # record the last N_LINES messages
        log_lines.insert(0, line)
        log_lines = log_lines[0:NLINES]

        # limit the frame rate to MAX_FPS after the screen is well populated
        if len(log_lines) >= NLINES:
            if time.time() - last_update < 1 / MAX_FPS:
                continue

        # display log messages in the window
        x11util.clear(window)
        for i, line in enumerate(log_lines):
            color = find_color(line)
            level = 100 - int(50 * i / NLINES)
            x11util.draw_str(disp,
                             screen,
                             window,
                             gcs,
                             line,
                             0,
                             i,
                             color=color,
                             level=level)
        x11util.flush(disp, screen)
        window.configure(stack_mode=X.Below)
        last_update = time.time()

def main():
    disp = display.Display()
    font = x11util.load_font(disp)
    screen = disp.screen()
    xoffset, yoffset = 0, x11util.FONT_HEIGHT
    width, height = screen.width_in_pixels, screen.height_in_pixels - yoffset
    window = x11util.create_window(disp,
                                   screen,
                                   width=width,
                                   height=height,
                                   x=xoffset,
                                   y=yoffset)
    window.configure(stack_mode=X.Below)
    gcs = x11util.create_gcs(disp, screen, window, font)
    main_loop(disp, screen, window, width, height, gcs)

if __name__ == "__main__":
    main()
