class PeerClient(dict):
    """dictionary of all dowloads: {id(transport): }"""
    
    def __init__(self, peer, connect_method):
        dict.__init__(self)
        self.peer = peer
        self.connect = connect_method
        self.download_dlg = None
        # [ [split path], size]
        self.files = []
        self.files_deferred = None

    def __setitem__(self, transport, download_msg):
        dict.__setitem__(self, id(transport), download_msg)

    def __getitem__(self, transport):
        try:
            return dict.__getitem__(self, id(transport))
        except KeyError:
            raise SecurityAlert(transport.getPeer().host,
                                _("Corrupted client"))
            
        
    # high level API #
    def auto_load(self):
        """download profile when meeting peer for the first time"""
        return self._connect(MESSAGE_HELLO)
    
    def get_profile(self):
        """download peer profile using self.get_file. Automatically
        called on client creation"""
        if self.peer.server.current_state == self.peer.server.new_state:
            SecurityAlert(self.peer.peer_id,
                          "Can't get profile: peer's server not known yet")
        else:
            return self._connect(MESSAGE_PROFILE)
            
    def get_blog_file(self):
        """donload blog file using self.get_file"""
        if self.peer.server.current_state == self.peer.server.new_state:
            SecurityAlert(self.peer.peer_id,
                          "Can't get blog: peer's server not known yet")
        else:
            return self._connect(MESSAGE_BLOG)
            
    def get_shared_files(self):
        """donload blog file using self.get_file"""
        if self.peer.server.current_state == self.peer.server.new_state:
            SecurityAlert(self.peer.peer_id,
                          "Can't get list: peer's server not known yet")
        else:
            return self._connect(MESSAGE_SHARED)
            
    def get_files(self, file_descriptors):
        """download given list of file

        file_descriptor is a list: [ [split path], size ]"""
        if self.peer.server.current_state == self.peer.server.new_state:
            SecurityAlert(self.peer.peer_id,
                          "Can't get files: peer's server not known yet")
        else:
            # display downlaod dialog if necessary
            if get_prefs("display_dl") \
                   and "wx" in sys.modules:
                print "xxx using wx"
                from solipsis.util.uiproxy import UIProxy
                from solipsis.services.profile.gui.DownloadDialog \
                     import DownloadDialog
                self.download_dlg = UIProxy(DownloadDialog(
                    get_prefs("display_dl"), None, -1))
                self.download_dlg.init()
                self.download_dlg.Show()
            # launch first download
            self.files = file_descriptors
            if self.files:
                split_path, size = self.files.pop()
                self.update_file(split_path[-1], size)
                self._connect(MESSAGE_FILES,
                                     format_data_file(split_path, size))
                # create deferred to be called when all files downloaded
                deferred = defer.Deferred()
                self.files_deferred = deferred
                return self.files_deferred
            else:
                display_warning(_("Empty List"),
                                _("No file selected to download"))

    # connection management #
    def _connect(self, command, data=None):
        # set download information
        message = self.peer.wrap_message(command, data)
        connector =  self.connect(self.peer)
        deferred = defer.Deferred()
        download = DownloadMessage(connector.transport,
                                   deferred,
                                   message)
        self[connector.transport] = download
        # set callback
        if command == MESSAGE_HELLO:
            deferred.addCallback(self._on_hello)
        elif command == MESSAGE_PROFILE:
            deferred.addCallback(self._on_complete_profile)
        elif command == MESSAGE_BLOG:
            deferred.addCallback(self._on_complete_pickle)
        elif command == MESSAGE_SHARED:
            deferred.addCallback(self._on_complete_pickle)
        elif command == MESSAGE_FILES:
            deferred.addCallback(self._on_complete_file)
        else:
            raise ValueError("ERROR in _connect: %s not valid"% command)
        return deferred
    
    def rawDataReceived(self, transport, data):
        self[transport].write_data(data)
        self.update_download(self[transport].size)
        
    def _fail_client(self, transport, reason):
        display_warning("Action [%s] failed: %s"\
                        % (str(self[transport].message), reason))
        self[transport].close(reason)

    def _on_connected(self, transport):
        self[transport].send_message()
        self[transport].setup_download()

    def _on_disconnected(self, transport, reason):
        self[transport].teardown_download()
        self[transport].close(reason)

    # callbacks #
    def _on_hello(self, donwload_msg):
        """callback when autoloading of profile successful"""
        document = read_document(donwload_msg.file)
        get_facade().set_data(self.peer.peer_id, document, flag_update=False)
        get_filter_facade().fill_data(self.peer.peer_id, document)
        
    def _on_complete_profile(self, donwload_msg):
        """callback when finished downloading profile"""
        return read_document(donwload_msg.file)

    def _on_complete_pickle(self, donwload_msg):
        """callback when finished downloading blog"""
        try:
            return pickle.load(donwload_msg.file)
        except Exception, err:
            display_error(_("Your version of Solipsis is not compatible "
                            "with the peer'sone you wish to download from "
                            "Make sure you both use the latest (%s)"\
                            % VERSION),
                          title="Download error", error=err)