# -*- coding: utf-8 -*-
#
# papyon - a python client library for Msn
#
# Copyright (C) 2005-2006 Ali Sabil <ali.sabil@gmail.com>
# Copyright (C) 2007-2008 Johann Prieur <johann.prieur@gmail.com>
#
# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

"""Profile of the User connecting to the service, as well as the profile of
contacts in his/her contact list.

    @sort: Profile, Contact, Group, ClientCapabilities
    @group Enums: Presence, Membership, Privacy, NetworkID
    @sort: Presence, Membership, Privacy, NetworkID"""

from papyon.util.decorator import rw_property

import gobject
import logging

__all__ = ['Profile', 'Contact', 'Group', 'EndPoint',
        'Presence', 'Membership', 'ContactType', 'Privacy', 'NetworkID', 'ClientCapabilities']

logger = logging.getLogger('papyon.profile')


class ClientCapabilities(gobject.GObject):
    """Capabilities of the client. This allow adverstising what the User Agent
    is capable of, for example being able to receive video stream, and being
    able to receive nudges...

        @ivar is_bot: is the client a bot
        @type is_bot: bool

        @ivar is_mobile_device: is the client running on a mobile device
        @type is_mobile_device: bool

        @ivar is_msn_mobile: is the client an MSN Mobile device
        @type is_msn_mobile: bool

        @ivar is_msn_direct_device: is the client an MSN Direct device
        @type is_msn_direct_device: bool

        @ivar is_media_center_user: is the client running on a Media Center
        @type is_media_center_user: bool

        @ivar is_msn8_user: is the client using WLM 8
        @type is_msn8_user: bool

        @ivar is_web_client: is the client web based
        @type is_web_client: bool

        @ivar is_tgw_client: is the client a gateway
        @type is_tgw_client: bool

        @ivar has_space: does the user has a space account
        @type has_space: bool

        @ivar has_webcam: does the user has a webcam plugged in
        @type has_webcam: bool

        @ivar has_onecare: does the user has the OneCare service
        @type has_onecare: bool

        @ivar renders_gif: can the client render gif (for ink)
        @type renders_gif: bool

        @ivar renders_isf: can the client render ISF (for ink)
        @type renders_isf: bool

        @ivar supports_chunking: does the client supports chunking messages
        @type supports_chunking: bool

        @ivar supports_direct_im: does the client supports direct IM
        @type supports_direct_im: bool

        @ivar supports_winks: does the client supports Winks
        @type supports_winks: bool

        @ivar supports_shared_search: does the client supports Shared Search
        @type supports_shared_search: bool

        @ivar supports_voice_im: does the client supports voice clips
        @type supports_voice_im: bool

        @ivar supports_secure_channel: does the client supports secure channels
        @type supports_secure_channel: bool

        @ivar supports_sip_invite: does the client supports SIP
        @type supports_sip_invite: bool

        @ivar supports_tunneled_sip: does the client supports tunneled SIP
        @type supports_tunneled_sip: bool

        @ivar supports_shared_drive: does the client supports File sharing
        @type supports_shared_drive: bool

        @ivar p2p_supports_turn: does the client supports TURN for p2p transfer
        @type p2p_supports_turn: bool

        @ivar p2p_bootstrap_via_uun: is the client able to use and understand UUN commands
        @type p2p_bootstrap_via_uun: bool

        @undocumented: __getattr__, __setattr__, __str__
        """

    __gsignals__ =  {
            "capability-changed": (gobject.SIGNAL_RUN_FIRST,
                gobject.TYPE_NONE,
                (object, object)),
            }

    MSNC = [0x0,        # MSNC0
            0x10000000, # MSNC1
            0x20000000, # MSNC2
            0x30000000, # MSNC3
            0x40000000, # MSNC4
            0x50000000, # MSNC5
            0x60000000, # MSNC6
            0x70000000, # MSNC7
            0x80000000, # MSNC8
            0x90000000, # MSNC9
            0xA0000000] # MSNC10

    _CAPABILITIES = {
            'is_bot': 0x00020000,
            'is_mobile_device': 0x00000001,
            'is_msn_mobile': 0x00000040,
            'is_msn_direct_device': 0x00000080,

            'is_media_center_user': 0x00002000,
            'is_msn8_user': 0x00000002,

            'is_web_cli
ent': 0x00000200,
            'is_tgw_client': 0x00000800,

            'has_space': 0x00001000,
            'has_webcam': 0x00000010,
            'has_onecare': 0x01000000,

            'renders_gif': 0x00000004,
            'renders_isf': 0x00000008,

            'supports_chunking': 0x00000020,
            'supports_direct_im': 0x00004000,
            'supports_winks': 0x00008000,
            'supports_shared_search': 0x00010000,
            'supports_v
oice_im': 0x00040000,
            'supports_secure_channel': 0x00080000,
            'supports_sip_invite': 0x00100000,
            'supports_tunneled_sip': 0x00200000,
            'supports_shared_drive': 0x00400000,

            'p2p_aware': 0xF0000000,
            'p2p_supports_turn': 0x02000000,
            'p2p_bootstrap_via_uun': 0x04000000
            }

    _EXTRA = {
            'supports_rtc_video': 0x00000010,
            'supports_p2pv2': 0x00000030
            }

    def __init__(self, msnc=0, client_id="0:0"):
        """Initializer

            @param msnc: The MSNC version
            @type msnc: integer < 11 and >= 0

            @param client_id: the full client ID"""
        gobject.GObject.__init__(self)
        caps = client_id.split(":")
        capabilities = int(caps[0])
        if len(caps) > 1:
            extra = int(caps[1])
        else:
            extra = 0
        gobject.GObject.__setattr__(self, 'capabilities', self.MSNC[msnc] | capabilities)
        gobject.GObject.__setattr__(self, 'extra', extra)

    def __getattr__(self, name):
        if name in self._CAPABILITIES:
            mask = self._CAPABILITIES[name]
            id = self.capabilities
        elif name in self._EXTRA:
            mask = self._EXTRA[name]
            id = self.extra
        else:
            raise AttributeError("object 'ClientCapabilities' has no attribute '%s'" % name)
        return (id & mask != 0)

    def __setattr__(self, name, value):
        if name in self._CAPABILITIES:
            mask = self._CAPABILITIES[name]
            old_value = bool(self.capabilities & mask)
            if value:
                gobject.GObject.__setattr__(self, 'capabilities', self.capabilities | mask)
            else:
                gobject.GObject.__setattr__(self, 'capabilities', self.capabilities & ~mask)
            if value != old_value:
                self.emit('capability-changed', name, value)
        elif name in self._EXTRA:
            mask = self._EXTRA[name]
            old_value = bool(self.extra & mask)
            if value:
                gobject.GObject.__setattr__(self, 'extra', self.extra | mask)
            else:
                gobject.GObject.__setattr__(self, 'extra', self.extra & ~mask)
            if value != old_value:
                self.emit('capability-changed', name, value)
        else:
            raise AttributeError("object 'ClientCapabilities' has no attribute '%s'" % name)

    def __str__(self):
        msnc = self.MSNC.index(self.capabilities & 0xF0000000)
        if msnc >= 9:
            client_id = "%s:%s" % (self.capabilities, 