Tidy up syncjob references
[hermes] / package / src / org / maemo / hermes / engine / hermes.py
index 8f8c571..9d569d8 100644 (file)
+from org.maemo.hermes.engine.friend import Friend
+from org.maemo.hermes.engine.contact import Contact
+import evolution
+
 class Hermes:
     """Encapsulate the process of syncing online friends' information with the
-       Evolution contacts' database. This should be used as follows:
+       Evolution contacts' database.
        
-         * Initialise, passing in a GUI callback.
-         * Call Syncjob.
-         * Retrieve information on changes effected.
-         * Call update_contact to enact manual mapping.
-         
        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
        Released under the Artistic Licence."""
 
     
     # -----------------------------------------------------------------------
-    def __init__(self, services, gui_progress):
-        """Constructor. Passed a list of services, and a callback method
-           which must implement the following API.
-                              
-             progress(i, j) - the application is currently processing friend 'i' of
-                              'j'. Should be used to provide the user a progress bar.
-        """
+    def __init__(self, services, gui_progress=None):
+        """Constructor. Passed a list of services, and a            
+           method which will be invoked with three arguments:
+                str    Name of current step
+                int    Current position
+                int    Maximum value of position."""
+
         
         # -- These fields are currently part of the API...
         #
-        self.updated   = []
-        self.matched   = []
+        self.updated = []
+        self.matched = []
         self.unmatched = []
-        self.friends   = {}
-        self.addresses = None
+        self.friends = {}
+        self.address_book = None
         
         # -- Other initialisation...
         #
         self._services = services
-        self._progress = gui_progress
+        self._progress = gui_progress or (lambda msg, i, j: None)
     
     
     # -----------------------------------------------------------------------
-    def run(self, resync = False):
-        """Load information on the authenticated user's friends. Synchronise Facebook
-           profiles to contact database. If resync is false, no existing information
-           will be overwritten."""
+    def run(self, overwrite_existing_fields=False):
+        self._progress("Reading contacts...", 1, 10000)
+        
+        contacts = []
+        self.address_book = self._get_address_book()
+        for econtact in self.address_book.get_all_contacts():
+            contacts.append(self._create_contact_wrapper(econtact))
 
-        class FakeContact():
-            def get_name(self):
-                return "Fredrik Wendt"
-            def get_emails(self):
-                return ["fredrik@wendt.se","maemohermes@wendt.se"]
-            def get_photo(self):
-                return None
-            def get_mapped_to(self):
-                return set(["facebook", "gravatar"])
-        self.matched = [FakeContact()]
-#        self._sync_job = SyncJob(services, [FakeContact()], self.progress)
-#        self._sync_job.run()
-#        self._sync_job.get_unmatched_friends()
-#        self._sync_job.get_updated_contacts()
-#        self._sync_job.get_matched_contacts()
-        pass
+        # work out progress bar info
+        total_contacts = len(contacts) * len(self._services)
+        total_ticks    = 6 * total_contacts # Number of distinct loops below
 
+        # warm up
+        current_tick = 1
+        for service in self._services:
+            print "pre-process:", service.get_id()
+            for contact in contacts:
+                self._progress("Pre-processing contacts...", current_tick, total_ticks)
+                current_tick += 1
+                service.pre_process_contact(contact)
+                
+        # fetch data
+        for service in self._services:
+            print "process_friends:", service.get_id()
+            self._progress("Reading friends...", current_tick, total_ticks)
+            current_tick += len(contacts)
+            service.process_friends()
+        
+        # combine results into one friend
+        for contact in contacts:
+            result = Friend()
+            for service in self._services:
+                print "process_contact:", service.get_id()
+                self._progress("Processing contacts...", current_tick, total_ticks)
+                current_tick += 1
+                friend = service.process_contact(contact)
+                if friend:
+                    contact.add_mapping(service.get_id())
+                    result.update_from_friend(friend)
+            
+            if result.get_name() is not None:
+                self.update_contact(contact, result, overwrite_existing_fields)
+            else:
+                self.unmatched.append(contact)
+            
+        # give services a chance to create new contacts
+        for service in self._services:
+            print "create_contacts:", service.get_id()
+            to_create = service.get_friends_to_create_contacts_for()
+            tick_increment = len(contacts) / (len(to_create) or 1)
+            print tick_increment, to_create
+            for friend in to_create:
+                friend.set_source(service.get_id())
+                self._progress("Creating contacts...", current_tick, total_ticks)
+                current_tick += tick_increment
+                self.create_contact_from_friend(friend)
+                
+        # finalisation
+        for service in self._services:
+            print "finalize:", service.get_id()
+            self._progress("Finalising...", current_tick, total_ticks)
+            current_tick += len(contacts)
+            service.finalise(self.updated, overwrite_existing_fields)
+            for friend in service.get_unmatched_friends():
+                friend.set_source(service.get_id())
+                key = unicode(friend.get_name()).encode('trans') + "_" + service.get_id()
+                self.friends[key] = friend
+            
+        # commit changes
+        tick_increment = total_contacts / (len(self.updated) or 1)
+        print tick_increment, self.updated
+        for contact in self.updated:
+            print "committing changes to:", contact.get_name(), contact
+            self._progress("Saving changes...", current_tick, total_ticks)
+            current_tick += tick_increment
+            self.address_book.commit_contact(contact.get_econtact())
+            
+        self._progress('Finished', 1, -1)
+        
 
     # -----------------------------------------------------------------------
-    def update_contact(self, contact, friend, resync = False):
+    def update_contact(self, contact, friend, resync=False, commit=False):
         """Update the given contact with information from the given friend."""
         
-        friend.update_contact(contact, resync)
-    
-"""        
- friends = ()
- for service in services:
-   for friend in service.get_friends():
-     friends.add(friend)
+        print "updating contact ", contact, " with friend ", friend
+        if friend.update_contact(contact, resync):
+            self.updated.append(contact)
+            if commit:
+                self.address_book.commit_contact(contact.get_econtact())
 
- all_contacts = get_contacts_as_set()
- contacts = set()
- updated_contacts = set()
- for econtact in addressbook.get_all_contacts():
-   contact = Contact(addressbook, econtact)
-   contacts.add(contact)
-   for service in something.get_services_by_prioritisation():
-     if service.process_contact(contact):
-       updated_contacts.add(contact)
+        self.matched.append(contact)
+        if friend.get_source() is not None:
+            contact.add_mapping(friend.get_source())
 
- for service in something.get_services_by_prioritisation():
-   service.finalise(updated_contacts)
 
- for contact in updated_contacts:
-   contact.save()
-"""
+    # -----------------------------------------------------------------------
+    def create_contact_from_friend(self, friend):
+        econtact = self._create_empty_contact(friend)
+        contact = self._create_contact_wrapper(econtact)
+                
+        self.address_book.add_contact(contact.get_econtact())
+        self.update_contact(contact, friend)
+        
+        print "Created [%s]" % (contact.get_name())
+        
+        
+    # -----------------------------------------------------------------------
+    def _get_address_book(self):
+        return evolution.ebook.open_addressbook('default')
+
+    # -----------------------------------------------------------------------
+    def _create_empty_contact(self, friend):
+        econtact = evolution.ebook.EContact()
+        econtact.props.given_name = friend['first_name']
+        econtact.props.family_name = friend['last_name']
+        econtact.props.full_name = friend.get_name()
+        return econtact
+    
+    # -----------------------------------------------------------------------
+    def _create_contact_wrapper(self, econtact):
+        return Contact(self.address_book, econtact)