#!/usr/bin/python



# #########################################################################
# Copyright (C) 2011 Marcelo Hashimoto
#
# This file is part of Polly.
#
# Polly 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.
#
# Polly 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 Polly. If not, see <http://www.gnu.org/licenses/>.
# #########################################################################



# NOTE: The code will be ported to Python 3, GObject Introspection,
# GSettings, and GTK+ 3 when those rise to first-class in distros.



from locale import LC_ALL, setlocale



setlocale(LC_ALL, u'')



import sys


import gtk as Gtk

from dbus import SessionBus, bus, service

from dbus.exceptions import DBusException

from dbus.mainloop.glib import DBusGMainLoop

from dbus.service import BusName



NAME = u'polly'

TITLE = u'Polly'

BUS = u'net.launchpad.polly'

MESSAGE = u'An instance seems to be still running. Please wait a few seconds and try again.'



def exit(secondary_markup):
    dialog = Gtk.MessageDialog(None, Gtk.DIALOG_MODAL, Gtk.MESSAGE_ERROR, Gtk.BUTTONS_CLOSE, u'Could not start the application')

    dialog.format_secondary_markup(secondary_markup)

    dialog.set_title(TITLE)

    dialog.run()

    dialog.destroy()

    sys.exit(1)



class Main(service.Object):
    def __init__(self, bus_path, bus_name):
        super(Main, self).__init__(None, bus_path, bus_name)

        self.window = None


    @service.method(BUS)
    def popup(self):
        if self.window is not None:
            if self.window.running:
                self.window.present()
            else:
                exit(MESSAGE)



Gtk.window_set_default_icon_name(NAME)


DBusGMainLoop(set_as_default=True)

session_bus = SessionBus()

reply = session_bus.request_name(BUS, bus.NAME_FLAG_DO_NOT_QUEUE)

bus_path = u'/{}'.format(BUS.replace(u'.', u'/'))

if reply == bus.REQUEST_NAME_REPLY_EXISTS:
    main = session_bus.get_object(BUS, bus_path)

    try:
        main.popup()
    except DBusException:
        exit(MESSAGE)
    else:
        sys.exit(0)

bus_name = BusName(BUS, session_bus, do_not_queue=True)

main = Main(bus_path, bus_name)



import os, shutil, subprocess

from subprocess import CalledProcessError


from xdg import BaseDirectory



VERSION = u'0.93.10 (pre-alpha 3.10)'

COPYRIGHT = u'Copyright \u00A9 2011 Marcelo Hashimoto'

# KEY = u'XDG_DATA_DIRS'



print TITLE, VERSION

print COPYRIGHT.replace(u'\u00A9', u'(C)')


# NOTE: PyXDG inserts XDG_DATA_HOME in the beginning of XDG_DATA_DIRS.
# This is convenient, but not required by the standard. I leave this
# note as a reminder that such assumption might not be valid forever.

if u'--standalone' in sys.argv:
    script_path = os.path.dirname(os.path.abspath(sys.path[0]))

    sys.path.insert(0, os.path.join(script_path, u'src'))

    script_data_prefix = os.path.join(script_path, u'share')

    if os.getuid() == os.stat(script_path).st_uid:
        cache_path = os.path.join(script_path, u'cache', NAME)

        config_path = os.path.join(script_path, u'config', NAME)

        data_paths = [os.path.join(script_data_prefix, NAME)]

        # writable_data_prefix = script_data_prefix
    else:
        cache_path = os.path.join(BaseDirectory.xdg_cache_home, NAME)

        config_path = os.path.join(BaseDirectory.xdg_config_home, NAME)

        data_paths = [os.path.join(BaseDirectory.xdg_data_home, NAME),
                      os.path.join(script_data_prefix, NAME)]

        # writable_data_prefix = BaseDirectory.xdg_data_home

    desktop_prefixes = [script_data_prefix]

    # NOTE: The following code will be replaced by commented
    # lines after the planned port to GSettings is completed.

    try:
        with open(u'/dev/null', u'w') as file:
            subprocess.check_call([u'gconftool-2', u'--install-schema-file', os.path.join(script_data_prefix, u'gconf', u'schemas', u'polly.schemas')], stdout=file, stderr=file)
    except (IOError, CalledProcessError):
        gconf_prefix = os.path.join(os.environ[u'HOME'], u'.gconf')

        exit(u'Check if <i>gconftool-2</i> is installed and if you have permission to read and write to the folders <i>{}</i> and <i>{}</i>.'.
             format(os.path.join(gconf_prefix, u'schemas', NAME), os.path.join(gconf_prefix, u'apps', NAME)))

    # schema_suffix = os.path.join(u'glib-2.0', u'schemas')
    # 
    # writable_schema_prefix = os.path.join(writable_data_prefix, schema_suffix)
    # 
    # try:
    #     if writable_data_prefix != script_data_prefix:
    #         if not os.path.isdir(writable_schema_prefix):
    #             os.makedirs(writable_schema_prefix)
    # 
    #         shutil.copy(os.path.join(script_data_prefix, schema_suffix, u'net.launchpad.Polly.gschema.xml'), writable_schema_prefix)
    # 
    #     with open(u'/dev/null', u'w') as file:
    #         subprocess.check_call([u'glib-compile-schemas', writable_schema_prefix], stdout=file, stderr=file)
    # except (OSError, IOError, CalledProcessError):
    #     exit(u'Check if <i>glib-compile-schemas</i> is installed and if you have permission to read and write to the folder <i>{}</i>.'.
    #          format(writable_schema_prefix))
    # 
    # os.environ[KEY] = u'{}:{}'.format(writable_data_prefix, os.environ[KEY])
else:
    cache_path = os.path.join(BaseDirectory.xdg_cache_home, NAME)

    config_path = os.path.join(BaseDirectory.xdg_config_home, NAME)

    data_paths = []

    desktop_prefixes = []

    for xdg_data_prefix in BaseDirectory.xdg_data_dirs:
        data_paths.append(os.path.join(xdg_data_prefix, NAME))

        desktop_prefixes.append(xdg_data_prefix)


print u'cache path: {}'.format(cache_path)

print u'config path: {}'.format(config_path)

print u'data home: {}'.format(data_paths[0])



import socket

from threading import Lock


import glib as GLib

import pynotify

from gtk import gdk as Gdk


from polly import setting, gui

from polly.gui.stream.manager import StreamManager

if u'--statusicon' in sys.argv:
    import polly.gui.indicator.statusicon as indicator
else:
    try:
        import polly.gui.indicator.libindicate as indicator
    except ImportError:
        import polly.gui.indicator.statusicon as indicator



WEBSITE = u'https://launchpad.net/polly'



print u'initializing...',

sys.stdout.flush()

cache_path_lock = Lock()

config_path_lock = Lock()

socket.setdefaulttimeout(5.0)

gtk_settings = Gtk.settings_get_default()

pynotify.init(NAME)

setting_factory = setting.Factory()

proxy_controller = gui.frontend.proxy.Controller(setting_factory)

shortener_controller = gui.frontend.shortener.Controller(setting_factory)

iconset_controller = gui.frontend.iconset.Controller(cache_path, data_paths, cache_path_lock, setting_factory)

color_scheme = gui.color.Scheme(gtk_settings, u'--windowcolor' in sys.argv)

font_scheme = gui.font.Scheme(gtk_settings)

theme_scheme = gui.theme.Scheme(gtk_settings)

connection_pool = gui.basic.ConnectionPool()

emblem_factory = gui.basic.frontend.emblem.Factory(iconset_controller, font_scheme)

button_factory = gui.basic.frontend.button.Factory(iconset_controller, font_scheme)

stamp_factory = gui.basic.frontend.stamp.Factory(cache_path, cache_path_lock, font_scheme, connection_pool)

avatar_factory = gui.basic.frontend.avatar.Factory(cache_path, cache_path_lock, font_scheme, connection_pool)

identifier_factory = gui.basic.frontend.identifier.Factory(cache_path, cache_path_lock, font_scheme, connection_pool)

preview_factory = gui.basic.frontend.preview.Factory(cache_path, cache_path_lock, font_scheme, connection_pool)

status_bar = gui.status.Bar(cache_path, cache_path_lock)

account_manager = gui.twitter.account.Manager(NAME, config_path, config_path_lock, setting_factory, proxy_controller, font_scheme, identifier_factory, status_bar)

media_runner = gui.header.media.Runner(setting_factory, proxy_controller)

main_panel = gui.header.main.Panel(setting_factory, shortener_controller, font_scheme, theme_scheme, button_factory, status_bar, account_manager, media_runner)

indicator_server = indicator.Server(NAME, desktop_prefixes)

stream_manager = StreamManager(config_path, config_path_lock, setting_factory, color_scheme, font_scheme, emblem_factory, button_factory, stamp_factory, avatar_factory, preview_factory, status_bar, account_manager, main_panel, indicator_server)

setting_window = gui.shell.setting.Window(proxy_controller, shortener_controller, iconset_controller, account_manager, main_panel, stream_manager)

about_runner = gui.shell.about.Runner(TITLE, VERSION, COPYRIGHT, WEBSITE, NAME)

main.window = gui.shell.main.Window(TITLE, u'--minimized' in sys.argv, u'--compose' in sys.argv, setting_factory, status_bar, account_manager, main_panel, indicator_server, stream_manager, setting_window, about_runner)

print u'done'


GLib.threads_init()

Gdk.threads_init()

Gdk.threads_enter()

account_manager.start_all()

stream_manager.start_all()

Gtk.main()

Gdk.threads_leave()

stream_manager.stop_all()

account_manager.stop_all()


print u'finalizing...',

sys.stdout.flush()

stream_manager.isolate()

indicator_server.isolate()

main_panel.isolate()

media_runner.isolate()

account_manager.isolate()

status_bar.isolate()

main.window.destroy()

button_factory.clear()

emblem_factory.clear()

iconset_controller.isolate()

shortener_controller.isolate()

proxy_controller.isolate()

setting_window.destroy()

theme_scheme.isolate()

font_scheme.isolate()

color_scheme.isolate()

pynotify.uninit()

print u'done'


print u'clearing...',

sys.stdout.flush()

maximum = setting_factory.get_fast(u'cache')

if maximum >= 0:
    maximum = min(maximum, 1024) * 1048576

    paths = []

    for dirpath, _, filenames in os.walk(cache_path):
        for filename in filenames:
            paths.append(os.path.join(dirpath, filename))

    paths.sort(key=(lambda path: os.stat(path).st_atime))

    size = 0

    index = 1

    while index < len(paths) + 1:
        size += os.stat(paths[-index]).st_size

        if size > maximum:
            break

        index += 1

    for path in paths[:-index]:
        try:
            os.remove(path)
        except OSError:
            pass

setting_factory.isolate()

print u'done'


print u'Thank you for using {}!'.format(TITLE)

print u'To contribute please visit {}.'.format(WEBSITE)
