#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Unity Mail, common initialization code
# Authors: Dmitry Shachnev <mitya57@gmail.com>
#          Robert Tari <robert.tari@gmail.com>
# License: GNU GPL 3 or higher; http://www.gnu.org/licenses/gpl.html

import gi

gi.require_version('Gtk', '3.0')

import gettext
import os
import gi
import platform
import psutil
import subprocess
import importlib
import locale
import time
import webbrowser
from babel.dates import format_timedelta
from gi.repository import Gio, Gtk, GLib

try:
    g_oTranslation = gettext.translation('unity-mail')
except IOError:
    g_oTranslation = gettext.NullTranslations()

g_oTranslation.install()

g_dctDefaultURLs = {'Home': 'https://mail.google.com/mail/', 'Compose': 'https://mail.google.com/mail/#compose', 'Inbox': 'https://mail.google.com/mail/#inbox', 'Sent': 'https://mail.google.com/mail/#sent'}
g_oSettings = Gio.Settings.new('in.tari.unity-mail')

def isRunning():

    nCount = 0

    for oProc in psutil.process_iter():

        strName = oProc.name

        if not isinstance(strName, str):
           strName = oProc.name()

        if strName == 'python3':

            lstCmdline = oProc.cmdline

            if not isinstance(lstCmdline, list):
               lstCmdline = oProc.cmdline()

            for strCmd in lstCmdline:

                if strCmd.endswith('unity-mail'):
                    nCount += 1

        elif strName.endswith('unity-mail'):

            nCount += 1

    return nCount

def printNames():

    print('Possible URL names: "Home", "Compose", "Inbox", "Sent"')

def openURLOrCommand(strName, strThread=None):

    if strName in g_dctDefaultURLs:

        strURL = g_oSettings.get_string(strName.lower())

        if strURL.startswith('Exec:'):

            subprocess.Popen(strURL[5:], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)

        else:

            if strThread:

                if not strURL.endswith('/'):
                    strURL += '/'

                strURL += strThread

            #subprocess.Popen(['xdg-open', strURL], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            webbrowser.open_new_tab(strURL)

    else:

        print('Unknown URL name!')
        printNames()

class MenuItemMail(Gtk.MenuItem):

    strId = None

    def __init__(self, strId):

        self.strId = strId

        Gtk.MenuItem.__init__(self)

class MessagingMenu(object):

    oUnity = None
    oMessagingMenu = None
    oAppIndicator = None

    def __init__(self, fnActivate, fnSettings, fnUpdateMessageAges):

        self.fnActivate = fnActivate
        self.launcher = None
        self.nMenuItems = 0
        self.nMessageAgeTimer = None
        self.oMenuItemClear = None
        self.oMailIcon = Gio.Icon.new_for_string('mail-unread')

        strDesktop = os.environ.get('XDG_CURRENT_DESKTOP').lower()
        nVersion = int(platform.linux_distribution()[1].replace('.', ''))

        if 'unity' in strDesktop or ('mate' in strDesktop and nVersion >= 1704):

            gi.require_version('Unity', '7.0')
            self.oUnity = importlib.import_module('gi.repository.Unity')

            strDesktopId = 'unity-mail.desktop'

            for strId in self.oUnity.LauncherFavorites.get_default().enumerate_ids():

                if 'unity-mail' in strId:

                    strDesktopId = strId
                    break

            self.oLauncher = self.oUnity.LauncherEntry.get_for_desktop_id(strDesktopId)

        if 'unity' in strDesktop or 'xfce' in strDesktop or ('mate' in strDesktop and nVersion >= 1610):

            gi.require_version('MessagingMenu', '1.0')
            self.oMessagingMenu = importlib.import_module('gi.repository.MessagingMenu')

            self.oIndicator = self.oMessagingMenu.App(desktop_id='unity-mail.desktop')
            self.oIndicator.register()
            self.oIndicator.connect('activate-source', lambda a, i: self.onMenuItemClicked(i))

        else:

            gi.require_version('AppIndicator3', '0.1')
            self.oAppIndicator = importlib.import_module('gi.repository.AppIndicator3')

            self.oIndicator = self.oAppIndicator.Indicator.new('unity-mail', 'indicator-messages', self.oAppIndicator.IndicatorCategory.APPLICATION_STATUS)
            self.oIndicator.set_attention_icon('indicator-messages-new')
            self.oIndicator.set_status(self.oAppIndicator.IndicatorStatus.ACTIVE)
            oMenu = Gtk.Menu()
            oMenu.append(Gtk.SeparatorMenuItem())
            oMenuItemInbox = Gtk.MenuItem()
            oMenuItemInbox.connect('activate', lambda w: openURLOrCommand('Home'))
            oBoxInbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6)
            oBoxInbox.pack_start(Gtk.Image.new_from_stock(Gtk.STOCK_HOME, Gtk.IconSize.MENU), False, False, 0)
            oBoxInbox.pack_start(Gtk.Label(_('Open webmail home page'), xalign=0), True, True, 0)
            oMenuItemInbox.add(oBoxInbox)
            oMenu.append(oMenuItemInbox)
            self.oMenuItemClear = Gtk.MenuItem(sensitive=False)
            self.oMenuItemClear.connect('activate', self.onClear)
            oBoxClear = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6)
            oBoxClear.pack_start(Gtk.Image.new_from_icon_name('gtk-clear', Gtk.IconSize.MENU), False, False, 0)
            oBoxClear.pack_start(Gtk.Label(_('Clear'), xalign=0), True, True, 0)
            self.oMenuItemClear.add(oBoxClear)
            oMenu.append(self.oMenuItemClear)
            oMenuItemConfig = Gtk.MenuItem()
            oMenuItemConfig.connect('activate', lambda w: fnSettings())
            oBoxConfig = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6)
            oBoxConfig.pack_start(Gtk.Image.new_from_stock(Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU), False, False, 0)
            oBoxConfig.pack_start(Gtk.Label(_('Settings'), xalign=0), True, True, 0)
            oMenuItemConfig.add(oBoxConfig)
            oMenu.append(oMenuItemConfig)
            oMenu.show_all()
            self.oIndicator.set_menu(oMenu)
            self.nMenuItems = len(self.oIndicator.get_menu().get_children())
            self.nMessageAgeTimer = GLib.timeout_add_seconds(60, fnUpdateMessageAges)

    def getMessageAge(self, nTimestamp):

        nTimeDelta = int(time.time() - nTimestamp / 1000000)
        strGranularity = 'minute'

        if nTimeDelta > (7 * 24 * 60 * 60):
            strGranularity = 'week'
        elif nTimeDelta > (24 * 60 * 60):
            strGranularity = 'day'
        elif nTimeDelta > (60 * 60):
            strGranularity = 'hour'
        elif nTimeDelta < 60:
            nTimeDelta = 61

        return ' (' + format_timedelta(nTimeDelta, granularity=strGranularity, format='short', locale=locale.getlocale()[0]) + ')'

    def onMenuItemClicked(self, strId):

        if self.fnActivate(strId):

            self.setCount(-1, True)

            if not self.oMessagingMenu:
                self.remove(strId)

    def append(self, strId, strTitle, nTimestamp, bDrawAttention):

        if self.oMessagingMenu:

            self.oIndicator.append_source_with_time(strId, self.oMailIcon, strTitle, nTimestamp)

            if bDrawAttention:
                self.oIndicator.draw_attention(strId)

        else:

            oMenu = self.oIndicator.get_menu()
            oMenuItemMail = MenuItemMail(strId)
            oMenuItemMail.connect('activate', lambda w: self.onMenuItemClicked(w.strId))
            oBox = Gtk.Box(Gtk.Orientation.HORIZONTAL, 6)
            oBox.pack_start(Gtk.Image.new_from_icon_name('mail-unread', Gtk.IconSize.MENU), False, False, 0)
            oBox.pack_start(Gtk.Label(strTitle + self.getMessageAge(nTimestamp), xalign=0), True, True, 0)
            oMenuItemMail.add(oBox)
            oMenu.insert(oMenuItemMail, len(oMenu.get_children()) - self.nMenuItems)
            oMenu.show_all()

            if bDrawAttention:
                self.oIndicator.set_status(self.oAppIndicator.IndicatorStatus.ATTENTION)

            self.oMenuItemClear.set_sensitive(True)

    def remove(self, strId):

        if self.oMessagingMenu:

            if self.oIndicator.has_source(strId):
                self.oIndicator.remove_source(strId)

        else:

            oMenu = self.oIndicator.get_menu()

            for oItem in oMenu.get_children()[0:-self.nMenuItems]:

                if oItem.strId == strId:
                    oMenu.remove(oItem)

            if len(oMenu.get_children()) - self.nMenuItems == 0:

                self.oIndicator.set_status(self.oAppIndicator.IndicatorStatus.ACTIVE)
                self.oMenuItemClear.set_sensitive(False)

    def hasSource(self, strId):

        if self.oMessagingMenu:

            return self.oIndicator.has_source(strId)

        else:

            for oItem in self.oIndicator.get_menu().get_children()[0:-self.nMenuItems]:

                if oItem.strId == strId:
                    return True

        return False

    def close(self):

        if not self.oMessagingMenu:
            GLib.source_remove(self.nMessageAgeTimer)

    def update(self, strId, nTimestamp):

        for oItem in self.oIndicator.get_menu().get_children()[0:-self.nMenuItems]:

            if oItem.strId == strId:

                oLabel = oItem.get_children()[0].get_children()[1]
                GLib.idle_add(oLabel.set_text, oLabel.get_text().rpartition(' (')[0] + self.getMessageAge(nTimestamp))

    def onClear(self, oWidget):

        oMenu = self.oIndicator.get_menu()

        for oItem in oMenu.get_children()[0:-self.nMenuItems]:
            oMenu.remove(oItem)

        if len(oMenu.get_children()) - self.nMenuItems == 0:

            self.oIndicator.set_status(self.oAppIndicator.IndicatorStatus.ACTIVE)
            self.oMenuItemClear.set_sensitive(False)

        self.setCount(0, True)

    def setCount(self, nCount, bVisible):

        if nCount == -1:

            if self.oUnity:
                nCount = self.oLauncher.get_property('count') - 1
            elif not self.oMessagingMenu:
                nCount = int(self.oIndicator.get_label()) - 1

        bVisible = bVisible and ((nCount > 0) or not g_oSettings.get_boolean('hide-messages-count'))

        if self.oUnity:

            GLib.idle_add(self.oLauncher.set_property, 'count', nCount)
            GLib.idle_add(self.oLauncher.set_property, 'count_visible', bVisible)

        elif not self.oMessagingMenu:
            GLib.idle_add(self.oIndicator.set_label, str(nCount) if bVisible else '', '')
