/**
  * _Heartbeat method
  *
  * Hourly periodic rotine
  *
  * @param mixed $console
  * @return array
  */
 function _HeartbeatHourly($console)
 {
     App::uses('LilCrmGoogleContactsApi', 'LilCrm.Lib');
     App::uses('LilCrmGoogleGroups', 'LilCrm.Lib');
     App::uses('LilCrmGoogleGroup', 'LilCrm.Lib');
     App::uses('LilCrmGoogleGroups', 'LilCrm.Lib');
     App::uses('LilCrmGoogleGroup', 'LilCrm.Lib');
     if (!($lastUpdated = Cache::read('LilCrm.lastGoogleSync', 'Lil'))) {
         $lastUpdated = strftime('%Y-%m-%d %H:%M:%S', 0);
     }
     $Contact = ClassRegistry::init('LilCrm.Contact');
     $contacts = $Contact->find('all', array('conditions' => array('Contact.kind' => 'T', 'Contact.syncable' => true, 'Contact.modified >=' => $lastUpdated), 'contain' => array('ContactsEmail', 'ContactsPhone', 'ContactsAddress', 'Company')));
     // setup last update
     Cache::write('LilCrm.lastGoogleSync', strftime('%Y-%m-%d %H:%M:%S', time()), 'Lil');
     if (empty($contacts)) {
         return;
     }
     $User = ClassRegistry::init('LilCrm.Contact');
     $User->bindModel(array('hasOne' => array('PrimaryEmail' => array('className' => 'LilCrm.ContactsEmail', 'type' => 'INNER', 'foreignKey' => 'contact_id', 'conditions' => array('PrimaryEmail.primary' => true)))), false);
     $sync_users = $User->find('all', array('conditions' => array('NOT' => array(0 => array('Contact.username' => null), 1 => array('Contact.oauth_token' => null))), 'contain' => array('PrimaryEmail')));
     foreach ($sync_users as $sync_user) {
         $api = new LilCrmGoogleContactsApi($sync_user['PrimaryEmail']['email'], $sync_user['Contact']['oauth_token']);
         if (!$api->ready) {
             CakeLog::write('error', sprintf("Cannot get access token for user %s.", $sync_user['PrimaryEmail']['email']));
             continue 1;
         }
         if ($myContactsGroup = $api->fetchSystemGroup()) {
             // fetch all contacts
             $cs = $api->fetchContacts();
             foreach ($contacts as $c) {
                 if (!($gc = $cs->extractByLilContactId($c['Contact']['id']))) {
                     $gc = new LilCrmGoogleContact();
                 }
                 $gc->name = $c['Contact']['title'];
                 $gc->clearEmails();
                 foreach ($c['ContactsEmail'] as $email) {
                     $gc->addEmail(array('address' => $email['email'], 'primary' => $email['primary'], 'kind' => $email['kind']));
                 }
                 $gc->clearPhones();
                 foreach ($c['ContactsPhone'] as $phone) {
                     if (!empty($phone['no'])) {
                         $gc->addPhone(array('no' => $phone['no'], 'kind' => $phone['kind']));
                     }
                 }
                 $gc->clearAddresses();
                 foreach ($c['ContactsAddress'] as $address) {
                     $gc->addAddress(array('street' => $address['street'], 'zip' => $address['zip'], 'city' => $address['city'], 'primary' => $address['primary'], 'kind' => $address['kind']));
                 }
                 $gc->clearOrganizations();
                 if (!empty($c['Company']['title'])) {
                     $gc->addOrganization(array('title' => $c['Company']['title'], 'job' => $c['Contact']['job']));
                 }
                 $gc->clearGroups();
                 $gc->addGroup($myContactsGroup->id);
                 $gc->addProperty('lil_crm-id', $c['Contact']['id']);
                 if (!$gc->id) {
                     $res = $api->createContact($gc);
                 } else {
                     $res = $api->updateContact($gc);
                 }
                 unset($gc);
             }
             // remaining contacts are not in local database; they can be deleted.
             foreach ($cs as $c) {
                 $api->deleteContact($c);
             }
         }
         unset($api);
     }
 }
 /**
  * updateContact
  *
  * @return mixed
  */
 public function updateContact(LilCrmGoogleContact $contact)
 {
     $g = array();
     $g['atom:entry'] = $contact->toArray();
     $g['atom:entry']['xmlns:atom'] = 'http://www.w3.org/2005/Atom';
     $g['atom:entry']['xmlns:gd'] = 'http://schemas.google.com/g/2005';
     $g['atom:entry']['xmlns:gContact'] = 'http://schemas.google.com/contact/2008';
     unset($g['atom:entry']['app:edited']);
     $contactXml = Xml::fromArray($g, array('format' => 'tags'));
     $response = $this->Client->fetch($contact->links['edit'], substr($contactXml->saveXML(), 39), 'PUT', array('Content-Type' => 'application/atom+xml', 'GData-Version' => '3.0', 'If-Match' => $contact->etag));
     if ($response['code'] == 200) {
         $xmlContact = Xml::build($response['result']);
         $contactArray = Xml::toArray($xmlContact);
         return new LiLCrmGoogleContact($contactArray['entry']);
     } else {
         return false;
     }
 }