#!/usr/bin/python3
# coding: utf-8
#
# A simple indicator applet displaying cpu and memory information
#
# Author: Alex Eftimie <alex@eftimie.ro>
# Fork Author: fossfreedom <foss.freedom@gmail.com>
# Original Homepage: http://launchpad.net/indicator-sysmonitor
# Fork Homepage: https://github.com/fossfreedom/indicator-sysmonitor
# License: GPL v3
#
import logging
import os
import sys
import json
import tempfile
from argparse import ArgumentParser
from gettext import gettext as _
from gettext import bindtextdomain, textdomain
from threading import Event

import gi
try:
    gi.require_version('AyatanaAppIndicator3', '0.1')
    from gi.repository import AyatanaAppIndicator3 as appindicator
except ValueError:
    gi.require_version('AppIndicator3', '0.1')
    from gi.repository import AppIndicator3 as appindicator

from gi.repository import GLib, Gtk

from preferences import __version__, Preferences
from sensors import SensorManager

textdomain("indicator-sysmonitor")
bindtextdomain("indicator-sysmonitor", "./lang")

logging.basicConfig(level=logging.INFO)

HELP_MSG = """<span underline="single" size="x-large">{title}</span>

{introduction}

{basic}
• cpu: {cpu_desc}
• mem: {mem_desc}
• bat<i>%d</i>: {bat_desc}
• net: {net_desc}
• upordown: {upordown_desc}
• publicip: {publicip_desc}

{compose}
• fs//<i>mount-point</i> : {fs_desc}

<big>{example}</big>
CPU {{cpu}} | MEM {{mem}} | root {{fs///}}
""".format(
    title=_("Help Page"),
    introduction=_("The sensors are the names of the devices from which you want to retrive information. They must be placed between brackets."),
    basic=_("The basics are:"),
    cpu_desc=_("It shows the average of CPU usage."),
    mem_desc=_("It shows the physical memory in use."),
    bat_desc=_("It shows the available battery which id is %d."),
    net_desc=_("It shows the amount of data you are downloading and uploading through your network."),
    upordown_desc=_("It shows whether your internet connection is up or down (the sensor is refreshed every 10 seconds)."),
    publicip_desc=_("It shows your public IP address (the sensor is refreshed every 10 minutes)."),
    compose=_("Also there are the following sensors that are composed with two parts divided by two slashes."),
    fs_desc=_("Show available space in the file system."),
    example=_("Example:"))

indicator_icon = '<?xml version="1.0" encoding="UTF-8"?> \
<svg width="800px" height="800px" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"> \
<defs><style>.a{fill:none;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;}</style></defs> \
<path class="a" d="m40.5 5.5h-33a2 2 0 0 0-2 2v33a2 2 0 0 0 2 2h33a2 2 0 0 0 2-2v-33a2 2 0 0 0-2-2z" stroke="#fff"/> \
<polyline class="a" points="9.5 23.717 17.98 23.717 19.393 25.922 20.919 22.7 23.463 37.624 25.385 10.376 27.307 24.509 28.551 23.717 38.5 23.717" stroke="#fff"/></svg>'

empty_icon = '<?xml version="1.0" encoding="UTF-8" \
                        standalone="no"?><svg id="empty" xmlns="http://www.w3.org/2000/svg" \
                        height="22" width="1" version="1.0" \
                        xmlns:xlink="http://www.w3.org/1999/xlink"></svg>'
class IndicatorSysmonitor(object):
    SENSORS_DISABLED = False

    def __init__(self):
        self._preferences_dialog = None
        self._help_dialog = None

        fn, self.tindicator = tempfile.mkstemp(suffix=".svg")
        svg = empty_icon
        desktop_environment = os.environ.get('DESKTOP_SESSION')
        if desktop_environment:
            if desktop_environment.lower()[:8] == 'cinnamon':
                svg = indicator_icon
            if desktop_environment.lower()[:7] == 'xubuntu':
                svg = indicator_icon
            if desktop_environment.lower()[:4] == 'xfce':
                svg = indicator_icon

        with open(self.tindicator, "w") as f:
            f.write(svg)
            f.close()

        self.ind = appindicator.Indicator.new("indicator-sysmonitor", self.tindicator, \
                                              appindicator.IndicatorCategory.SYSTEM_SERVICES)
        self.ind.set_ordering_index(0)

        self.ind.set_status(appindicator.IndicatorStatus.ACTIVE)
        self.ind.set_label("Init...", "")

        self._create_menu()

        self.alive = Event()
        self.alive.set()

        self.sensor_mgr = SensorManager()
        self.load_settings()

    def _create_menu(self):
        """Creates the main menu and shows it."""
        # create menu {{{
        menu = Gtk.Menu()
        # add System Monitor menu item
        full_sysmon = Gtk.MenuItem(label='System Monitor')
        full_sysmon.connect('activate', self.on_full_sysmon_activated)
        menu.add(full_sysmon)
        menu.add(Gtk.SeparatorMenuItem())

        # add preferences menu item
        pref_menu = Gtk.MenuItem(label='Preferences')
        pref_menu.connect('activate', self.on_preferences_activated)
        menu.add(pref_menu)

        # add help menu item
        help_menu = Gtk.MenuItem(label='Help')
        help_menu.connect('activate', self._on_help)
        menu.add(help_menu)

        # add preference menu item
        exit_menu = Gtk.MenuItem(label='Quit')
        exit_menu.connect('activate', self.on_exit)
        menu.add(exit_menu)

        menu.show_all()
        self.ind.set_menu(menu)
        logging.info("Menu shown")
        # }}} menu done!

    def update_indicator_guide(self):
        return
        guide = self.sensor_mgr.get_guide()

        self.ind.set_property("label-guide", guide)

    def update(self, data):
        # data is the dict of all sensors and their values
        # { name, label }

        # look through data and find out if there are any icons to be set
        for sensor in data:
            test_str = data[sensor].lower()
            if "use_icon" in test_str:
                path = data[sensor].split(":")[1]
                self.ind.set_icon_full(path, "")
                # now strip the icon output from data so that it is not displayed
                remaining = test_str.split("use_icon")[0].strip()
                if not remaining:
                    remaining = " "

                data[sensor] = remaining

            if "clear_icon" in test_str:
                self.ind.set_icon_full(self.tindicator, "")

                remaining = test_str.split("clear_icon")[0].strip()
                if not remaining:
                    remaining = " "

                data[sensor] = remaining

        label = self.sensor_mgr.get_label(data)

        self.ind.set_label(label.strip(), "")
        self.ind.set_title(label.strip())

    def load_settings(self):

        self.sensor_mgr.load_settings()
        self.sensor_mgr.initiate_fetcher(self)
        self.update_indicator_guide()

    # @staticmethod
    def save_settings(self):
        self.sensor_mgr.save_settings()

    def update_settings(self):
        self.sensor_mgr.initiate_fetcher(self)

    # actions raised from menu
    def on_preferences_activated(self, event=None):
        """Raises the preferences dialog. If it's already open, it's
        focused"""
        if self._preferences_dialog is not None:
            self._preferences_dialog.present()
            return

        self._preferences_dialog = Preferences(self)
        self._preferences_dialog.run()
        self._preferences_dialog = None

    def on_full_sysmon_activated(self, event=None):
        if GLib.find_program_in_path('mate-system-monitor') is not None:
            os.system('mate-system-monitor &')
            return

        if GLib.find_program_in_path('gnome-system-monitor') is not None:
            os.system('gnome-system-monitor &')

    def on_exit(self, event=None, data=None):
        """Action call when the main programs is closed."""
        # cleanup temporary indicator icon
        os.remove(self.tindicator)
        # close the open dialogs
        if self._help_dialog is not None:
            self._help_dialog.destroy()

        if self._preferences_dialog is not None:
            self._preferences_dialog.destroy()

        logging.info("Terminated")
        self.alive.clear()  # DM: why bother with Event() ???

        try:
            Gtk.main_quit()
        except RuntimeError:
            pass

    def _on_help(self, event=None, data=None):
        """Raise a dialog with info about the app."""
        if self._help_dialog is not None:
            self._help_dialog.present()
            return

        self._help_dialog = Gtk.MessageDialog(
            parent=None, destroy_with_parent=True, text=Gtk.MessageType.INFO,
            buttons=Gtk.ButtonsType.OK)

        self._help_dialog.set_title(_("Help"))
        self._help_dialog.set_markup(HELP_MSG)
        self._help_dialog.run()
        self._help_dialog.destroy()
        self._help_dialog = None

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument(
        "--config",
        default=None,
        help="Use custom config file."
        )
    parser.add_argument(
        "--version",
        default=False,
        action='store_true',
        help='Show version and exit.'
        )

    options = parser.parse_args()

    if options.version:
        print(__version__)
        exit(0)

    logging.info("start")
    if options.config:
        if not os.path.exists(options.config):
            logging.error(_("{} does not exist!").format(options.config))
            sys.exit(-1)
        logging.info(_("Using config file: {}").format(options.config))
        SensorManager.SETTINGS_FILE = options.config

    if not os.path.exists(SensorManager.SETTINGS_FILE):
        sensor_mgr = SensorManager()
        sensor_mgr.save_settings()
    else:
        try:
            with open(SensorManager.SETTINGS_FILE,"r") as f:
                cfg = json.load(f)
            f.close()
        except:
            settings = {
                'custom_text': 'cpu: {cpu} mem: {mem}',
                'interval': 2,
                'on_startup': False,
                'sensors': {
                }
            }
            with open(SensorManager.SETTINGS_FILE,"w") as f:
                f.write(json.dumps(settings, indent=4, ensure_ascii=False))
            f.close()

    # setup an instance with config
    app = IndicatorSysmonitor()
    try:
        Gtk.main()
    except KeyboardInterrupt:
        app.on_exit()
