# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Authors: Guillaume Emont <guillaume@fluendo.com>

from elisa.core import common
from elisa.core.utils import defer
from elisa.core.utils.i18n import install_translation
from elisa.core.media_uri import MediaUri
from elisa.plugins.base.messages.device import NewDeviceDetected, \
         DeviceRemoved
from elisa.plugins.base.models.device import DeviceModel

from elisa.plugins.dvd.actions import PlayDvdAction, EjectDvdAction, \
         PlayPhysicalDvdAction, PlayVideoTsAction, PlayDvdIsoAction

_ = install_translation('dvd')


class SectionDecorator(object):
    uri = MediaUri("volumes://?filter=dvd")

    def __init__(self, controller):
        super(SectionDecorator, self).__init__()
        self.controller = controller
        self.bus = common.application.bus
        self._count = 0
        self._use_long_names = False
        self._notifier_ids = []

    def initialize(self):
        id = self.controller.model.notifier.connect('items-inserted',
                                                    self.on_items_inserted)
        self._notifier_ids.append(id)
        id = self.controller.model.notifier.connect('items-deleted', 
                                                    self.on_items_deleted)
        self._notifier_ids.append(id)
        self.bus.register(self.on_device_added, NewDeviceDetected)
        self.bus.register(self.on_device_removed, DeviceRemoved)

        self.controller.connect('clean', self.on_clean)

        model, dfr = common.application.resource_manager.get(self.uri, None)
        dfr.addCallback(self.do_list_hardware)
        return dfr

    @classmethod
    def decorate(klass, controller):
        decorator = klass(controller)
        return decorator.initialize()

    def add_entry(self, model):
        """
        Adds an entry for model
        """
        if self._count >= 1 and not self._use_long_names:
            self._use_long_names = 1
            self._rename_dvds()

        model.default_action = PlayPhysicalDvdAction(self.controller)
        model.extra_actions = [EjectDvdAction(self.controller)]
        model.label = self._get_label(model)
        model.icon = "elisa.plugins.poblesec.glyphs.small.disc"
        self.controller.model.append(model)

    def do_list_hardware(self, model):
        devices = sorted(model.devices, key=lambda i: i.name.lower())

        for dev in devices:
            self.add_entry(dev)
        
    def on_device_added(self, message, sender):
        if message.model.protocol == 'dvd':
            self.add_entry(message.model)

    def on_device_removed(self, message, sender):
        for item in self.controller.model:
            if self._is_dvd(item) and item.udi == message.udi:
                self.controller.model.remove(item)
                break

    def on_items_inserted(self, model, index, items):
        old_count = self._count
        new_dvds = [item for item in items if self._is_dvd(item)]
        if not new_dvds:
            return
        self._count += len(new_dvds)

    def on_items_deleted(self, model, index, items):
        old_count = self._count
        removed_dvds = [item for item in items if self._is_dvd(item)]
        if not removed_dvds:
            return
        self._count -= len(removed_dvds)

        if self._count <= 1 and self._use_long_names:
                self._use_long_names = False
                if self._count == 1:
                    self._rename_dvds()

    def on_clean(self, controller):
        self.bus.unregister(self.on_device_added)
        self.bus.unregister(self.on_device_removed)
        for id in self._notifier_ids:
            controller.model.notifier.disconnect(id)
        return defer.succeed(None)

    def _is_dvd(self, item):
        return isinstance(item, DeviceModel) and item.protocol == 'dvd'

    def _rename_dvds(self):
        dvds = (item for item in self.controller.model if self._is_dvd(item))

        for dvd in dvds:
            dvd.label = self._get_label(dvd)
            # trigger a refresh
            index = self.controller.model.index(dvd)
            self.controller.model[index] = dvd

    def _get_label(self, dvd):
        if self._use_long_names:
            return _("DVD Disc: %s") % dvd.name
        else:
            return _("DVD Disc")



def _transform_model(controller, model):
    lower_name = model.name.lower()
    if lower_name.endswith('.iso'):
        model.default_action = PlayDvdIsoAction(controller)
        model.media_type = 'disc'
    if lower_name == 'video_ts':
        model.default_action = PlayVideoTsAction(controller)
        model.media_type = 'disc'
    return model


def _hook_filesystem_controller():
    from elisa.plugins.poblesec.filesystem import FilesystemController
    FilesystemController.model_parsers.append(_transform_model)

def _unhook_filesystem_controller():
    from elisa.plugins.poblesec.filesystem import FilesystemController
    FilesystemController.model_parsers.remove(_transform_model)

def main_decorator(controller):
    """
    Add a pop-up when a dvd is inserted.
    This should be used as a decorator on the main controller
    """
    play_action = PlayDvdAction(controller)

    def new_device_detected_cb(message, sender):
        model = message.model
        if model.protocol != 'dvd':
            return

        def do_play():
            dfr = controller.hide_popup()

            def execute_action(result):
                return play_action.execute(model)
            return dfr.addCallback(execute_action)

        title = _('DVD DISC INSERTED')
        subtitle = _("The DVD Disc Entitled '%(name)s' Is Available") % \
                                                        {'name': model.name}
        text = _("A DVD Disc has been inserted into this computer. You may " \
                 "play this DVD now by selecting 'Play'. Alternatively " \
                 "select 'Cancel' to close this message.\n\n" \
                 "To access this device at a later date you can find it " \
                 "listed via the 'Attached Devices' subsection within the " \
                 "'Devices &amp; Shares' section of the Main Menu." \
                 "\n\n" \
                 "<b>Note: DVD playback in Moovida is extremely experimental "\
                 "and there are known issues with a variety of DVD discs. "\
                 "Therefore, the playback experience may not be perfect.</b>")
        buttons = ((_('Cancel'), controller.hide_popup),
                   (_('Play'), do_play))
        controller.enqueue_popup(title, subtitle, text, buttons)

    bus = common.application.bus
    bus.register(new_device_detected_cb, NewDeviceDetected)

    _hook_filesystem_controller()

    def on_clean(controller):
        bus.unregister(new_device_detected_cb)
        _unhook_filesystem_controller()
        return defer.succeed(None)
    controller.connect('clean', on_clean)

    return defer.succeed(None)
