#!/usr/bin/env python

# Copyright (C) 2005-2007 INdT - Instituto Nokia de Tecnologia
#
# 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 2 of the License, or
# (at your option) 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

__author__ = "Artur Duque de Souza"
__author_email__ = "artur.souza@openbossa.org"
__license__ = "GPL"

import os
import dbus
import logging

from canolad.mount_table import MountTable

mnt_file = "/etc/mtab"

class Device(object):
    mount_file = mnt_file
    log = logging.getLogger("canola.daemon.gnomevfstab.device")

    def __init__(self, mger_tab, dev_info, cb_unmount_table=None):
        self.mger_tab = mger_tab
        self.gvfs_iface = self.mger_tab.gvfs_iface
        self.cb_unmount_table = cb_unmount_table

        self.uid = dev_info[0]
        self.block_device = dev_info[1]
        self.mount_point = dev_info[2]
        self.volume_fstype = dev_info[3]

        self.gvfs_iface.connect_to_signal("VolumeUnmountedSignal",
                                          self.VolumeUnmountedSignal)

    def VolumeUnmountedSignal(self, uid):
        # device was unmounted
        if self.uid == uid and self.cb_unmount_table:
            self.cb_unmount_table(self.mount_point)
        elif self.uid == -1:
            mtab = open(self.mount_file)
            lines = mtab.readlines()
            for line in lines:
                if line.find(self.mount_point) >= 0:
                    self.cb_unmount_table(self.mount_point)
                    break
        if self.mger_tab.cb_dev_removed:
            sig = self.mger_tab.create_dbus_array(self.mount_point)
            self.mger_tab.cb_dev_removed(sig)
            self.mger_tab.mount_table.check_all_paths(
                [self.mount_point], [self.mount_point], [self.mount_point])
        return True


class GnomeVFSTab(object):
    mount_file = mnt_file
    log = logging.getLogger("canola.daemon.gnomevfstab")

    def __init__(self, cb_dev_added=None, cb_dev_removed=None, cb_db_locked=None, cb_db_unlocked=None):
        self.cb_dev_added = cb_dev_added
        self.cb_dev_removed = cb_dev_removed
        self.bus = dbus.SessionBus()
        self.gvfs_obj = self.bus.get_object("org.gnome.GnomeVFS.Daemon",
                                            "/org/gnome/GnomeVFS/Daemon",
                                            introspect=False)

        self.gvfs_iface = dbus.Interface(self.gvfs_obj,
                                         "org.gnome.GnomeVFS.Daemon")
        self.devs = {}
        self._started_monitor = False
        self.mount_table = MountTable(cb_db_locked, cb_db_unlocked)
        self.log.info("Started Canola-Daemon with GnomeVFS support")

    def start_monitoring(self):
        # take a look on mount_file to discover what is already mounted
        # and start monitoring
        if not self._started_monitor:
            self.gvfs_iface.connect_to_signal("VolumeMountedSignal",
                                              self.VolumeMountedSignal)
            # detect already mounted disks
            self.read_mount_file()
            self._started_monitor = True

    def read_mount_file(self):
        def parse_line(line):
            fields = line.split(" ")
            # dev, mount_point, type
            if fields[1].find("/media") >= 0:
                return (fields[0], fields[1], fields[2])
            return None

        mtab = open(self.mount_file)
        lines = mtab.readlines()
        mtab.close()

        self.log.debug("Reading mount file: %s", self.mount_file)
        for line in lines:
            dev = parse_line(line)
            if dev:
                dev_uri = str(dev[1])
                if not self.mount_table.has_key(dev_uri):
                    self.log.info("Going to add device: %s", dev_uri)
                    dev_info = (-1, dev[0], dev[1], dev[2])
                    device = Device(self, dev_info, self.update_mount_table)
                    self.devs[dev_uri] = device
                    self.mount_table[dev_uri] = dev

        self.log.info("Detected devices: %s", self.mount_table)
        return True

    def create_dbus_array(self, string):
        ret = dbus.Array(string, signature=dbus.Signature("y"))
        return ret

    def VolumeMountedSignal(self, *args):
        # device was mounted
        mount_info = args[0]
        uid = mount_info[0]
        # XXX: dbus' mandatory conversion to utf8 of the path may cause problems
        mount_point = str(mount_info[4].split("file://")[1])
        volume_fstype = mount_info[5]
        block_device = mount_info[11]
        dev_info = (uid, block_device, mount_point, volume_fstype)
        self.mount_table[str(mount_point)] = dev_info
        self.devs[mount_point] = Device(self, dev_info, self.update_mount_table)
        self.log.info("Mounted device: %s", mount_point)
        self.log.debug("Mount table: %s", self.mount_table)

        if self.cb_dev_added is not None:
            sig = self.create_dbus_array(mount_point)
            self.cb_dev_added(sig)

    def update_mount_table(self, key):
        if self.mount_table.has_key(key):
            dev = self.mount_table.pop(key, None)
            self.devs.pop(key, None)
            if dev:
                self.log.info("Removed device: %s", dev[1])
        return True
