public void updateProvider(
      Feed feed, Long syncLocalId, Entry entry, ContentProvider provider, Object info)
      throws ParseException {
    SyncInfo syncInfo = (SyncInfo) info;
    EventEntry event = (EventEntry) entry;

    ContentValues map = new ContentValues();

    // use the calendar's timezone, if provided in the feed.
    // this overwrites whatever was in the db.
    if ((feed != null) && (feed instanceof EventsFeed)) {
      EventsFeed eventsFeed = (EventsFeed) feed;
      syncInfo.calendarTimezone = eventsFeed.getTimezone();
    }

    if (entry.isDeleted()) {
      deletedEntryToContentValues(syncLocalId, event, map);
      if (Config.LOGV) {
        Log.v(TAG, "Deleting entry: " + map);
      }
      provider.insert(Events.DELETED_CONTENT_URI, map);
      return;
    }

    int entryState = entryToContentValues(event, syncLocalId, map, syncInfo);

    if (entryState == ENTRY_DELETED) {
      if (Config.LOGV) {
        Log.v(TAG, "Got deleted entry from server: " + map);
      }
      provider.insert(Events.DELETED_CONTENT_URI, map);
    } else if (entryState == ENTRY_OK) {
      if (Config.LOGV) {
        Log.v(TAG, "Got entry from server: " + map);
      }
      Uri result = provider.insert(Events.CONTENT_URI, map);
      long rowId = ContentUris.parseId(result);
      // handle the reminders for the event
      Integer hasAlarm = map.getAsInteger(Events.HAS_ALARM);
      if (hasAlarm != null && hasAlarm == 1) {
        // reminders should not be null
        Vector alarms = event.getReminders();
        if (alarms == null) {
          Log.e(TAG, "Have an alarm but do not have any reminders " + "-- should not happen.");
          throw new IllegalStateException("Have an alarm but do not have any reminders");
        }
        Enumeration reminders = alarms.elements();
        while (reminders.hasMoreElements()) {
          ContentValues reminderValues = new ContentValues();
          reminderValues.put(Calendar.Reminders.EVENT_ID, rowId);

          Reminder reminder = (Reminder) reminders.nextElement();
          byte method = reminder.getMethod();
          switch (method) {
            case Reminder.METHOD_DEFAULT:
              reminderValues.put(Calendar.Reminders.METHOD, Calendar.Reminders.METHOD_DEFAULT);
              break;
            case Reminder.METHOD_ALERT:
              reminderValues.put(Calendar.Reminders.METHOD, Calendar.Reminders.METHOD_ALERT);
              break;
            case Reminder.METHOD_EMAIL:
              reminderValues.put(Calendar.Reminders.METHOD, Calendar.Reminders.METHOD_EMAIL);
              break;
            case Reminder.METHOD_SMS:
              reminderValues.put(Calendar.Reminders.METHOD, Calendar.Reminders.METHOD_SMS);
              break;
            default:
              // should not happen.  return false?  we'd have to
              // roll back the event.
              Log.e(TAG, "Unknown reminder method: " + method + " should not happen!");
          }

          int minutes = reminder.getMinutes();
          reminderValues.put(
              Calendar.Reminders.MINUTES,
              minutes == Reminder.MINUTES_DEFAULT ? Calendar.Reminders.MINUTES_DEFAULT : minutes);

          if (provider.insert(Calendar.Reminders.CONTENT_URI, reminderValues) == null) {
            throw new ParseException("Unable to insert reminders.");
          }
        }
      }

      // handle attendees for the event
      Vector attendees = event.getAttendees();
      Enumeration attendeesEnum = attendees.elements();
      while (attendeesEnum.hasMoreElements()) {
        Who who = (Who) attendeesEnum.nextElement();
        ContentValues attendeesValues = new ContentValues();
        attendeesValues.put(Calendar.Attendees.EVENT_ID, rowId);
        attendeesValues.put(Calendar.Attendees.ATTENDEE_NAME, who.getValue());
        attendeesValues.put(Calendar.Attendees.ATTENDEE_EMAIL, who.getEmail());

        byte status;
        switch (who.getStatus()) {
          case Who.STATUS_NONE:
            status = Calendar.Attendees.ATTENDEE_STATUS_NONE;
            break;
          case Who.STATUS_INVITED:
            status = Calendar.Attendees.ATTENDEE_STATUS_INVITED;
            break;
          case Who.STATUS_ACCEPTED:
            status = Calendar.Attendees.ATTENDEE_STATUS_ACCEPTED;
            break;
          case Who.STATUS_TENTATIVE:
            status = Calendar.Attendees.ATTENDEE_STATUS_TENTATIVE;
            break;
          case Who.STATUS_DECLINED:
            status = Calendar.Attendees.ATTENDEE_STATUS_DECLINED;
            break;
          default:
            Log.w(TAG, "Unknown attendee status " + who.getStatus());
            status = Calendar.Attendees.ATTENDEE_STATUS_NONE;
        }
        attendeesValues.put(Calendar.Attendees.ATTENDEE_STATUS, status);
        byte rel;
        switch (who.getRelationship()) {
          case Who.RELATIONSHIP_NONE:
            rel = Calendar.Attendees.RELATIONSHIP_NONE;
            break;
          case Who.RELATIONSHIP_ORGANIZER:
            rel = Calendar.Attendees.RELATIONSHIP_ORGANIZER;
            break;
          case Who.RELATIONSHIP_ATTENDEE:
            rel = Calendar.Attendees.RELATIONSHIP_ATTENDEE;
            break;
          case Who.RELATIONSHIP_PERFORMER:
            rel = Calendar.Attendees.RELATIONSHIP_PERFORMER;
            break;
          case Who.RELATIONSHIP_SPEAKER:
            rel = Calendar.Attendees.RELATIONSHIP_SPEAKER;
            break;
          default:
            Log.w(TAG, "Unknown attendee relationship " + who.getRelationship());
            rel = Calendar.Attendees.RELATIONSHIP_NONE;
        }

        attendeesValues.put(Calendar.Attendees.ATTENDEE_RELATIONSHIP, rel);

        byte type;
        switch (who.getType()) {
          case Who.TYPE_NONE:
            type = Calendar.Attendees.TYPE_NONE;
            break;
          case Who.TYPE_REQUIRED:
            type = Calendar.Attendees.TYPE_REQUIRED;
            break;
          case Who.TYPE_OPTIONAL:
            type = Calendar.Attendees.TYPE_OPTIONAL;
            break;
          default:
            Log.w(TAG, "Unknown attendee type " + who.getType());
            type = Calendar.Attendees.TYPE_NONE;
        }
        attendeesValues.put(Calendar.Attendees.ATTENDEE_TYPE, type);
        if (provider.insert(Calendar.Attendees.CONTENT_URI, attendeesValues) == null) {
          throw new ParseException("Unable to insert attendees.");
        }
      }

      // handle the extended properties for the event
      Integer hasExtendedProperties = map.getAsInteger(Events.HAS_EXTENDED_PROPERTIES);
      if (hasExtendedProperties != null && hasExtendedProperties.intValue() != 0) {
        // extended properties should not be null
        // TODO: make the extended properties a bit more OO?
        Hashtable extendedProperties = event.getExtendedProperties();
        if (extendedProperties == null) {
          Log.e(
              TAG,
              "Have extendedProperties but do not have any properties" + "-- should not happen.");
          throw new IllegalStateException("Have extendedProperties but do not have any properties");
        }
        Enumeration propertyNames = extendedProperties.keys();
        while (propertyNames.hasMoreElements()) {
          String propertyName = (String) propertyNames.nextElement();
          String propertyValue = (String) extendedProperties.get(propertyName);
          ContentValues extendedPropertyValues = new ContentValues();
          extendedPropertyValues.put(Calendar.ExtendedProperties.EVENT_ID, rowId);
          extendedPropertyValues.put(Calendar.ExtendedProperties.NAME, propertyName);
          extendedPropertyValues.put(Calendar.ExtendedProperties.VALUE, propertyValue);
          if (provider.insert(Calendar.ExtendedProperties.CONTENT_URI, extendedPropertyValues)
              == null) {
            throw new ParseException("Unable to insert extended properties.");
          }
        }
      }
    } else {
      // If the DTSTART == -1, then the date was out of range.  We don't
      // need to throw a ParseException because the user can create
      // dates on the web that we can't handle on the phone.  For
      // example, events with dates before Dec 13, 1901 can be created
      // on the web but cannot be handled on the phone.
      Long dtstart = map.getAsLong(Events.DTSTART);
      if (dtstart != null && dtstart == -1) {
        return;
      }

      if (Config.LOGV) {
        Log.v(TAG, "Got invalid entry from server: " + map);
      }
      throw new ParseException("Got invalid entry from server: " + map);
    }
  }
  private void addAttendeesToEntry(long eventId, EventEntry event) throws ParseException {
    Cursor c =
        getContext()
            .getContentResolver()
            .query(Calendar.Attendees.CONTENT_URI, null, "event_id=" + eventId, null, null);

    try {
      int nameIndex = c.getColumnIndexOrThrow(Calendar.Attendees.ATTENDEE_NAME);
      int emailIndex = c.getColumnIndexOrThrow(Calendar.Attendees.ATTENDEE_EMAIL);
      int statusIndex = c.getColumnIndexOrThrow(Calendar.Attendees.ATTENDEE_STATUS);
      int typeIndex = c.getColumnIndexOrThrow(Calendar.Attendees.ATTENDEE_TYPE);
      int relIndex = c.getColumnIndexOrThrow(Calendar.Attendees.ATTENDEE_RELATIONSHIP);

      while (c.moveToNext()) {
        Who who = new Who();
        who.setValue(c.getString(nameIndex));
        who.setEmail(c.getString(emailIndex));
        int status = c.getInt(statusIndex);
        switch (status) {
          case Calendar.Attendees.ATTENDEE_STATUS_NONE:
            who.setStatus(Who.STATUS_NONE);
            break;
          case Calendar.Attendees.ATTENDEE_STATUS_ACCEPTED:
            who.setStatus(Who.STATUS_ACCEPTED);
            break;
          case Calendar.Attendees.ATTENDEE_STATUS_DECLINED:
            who.setStatus(Who.STATUS_DECLINED);
            break;
          case Calendar.Attendees.ATTENDEE_STATUS_INVITED:
            who.setStatus(Who.STATUS_INVITED);
            break;
          case Calendar.Attendees.ATTENDEE_STATUS_TENTATIVE:
            who.setStatus(Who.STATUS_TENTATIVE);
            break;
          default:
            Log.e(TAG, "Unknown attendee status: " + status);
            who.setStatus(Who.STATUS_NONE);
            break;
        }
        int type = c.getInt(typeIndex);
        switch (type) {
          case Calendar.Attendees.TYPE_NONE:
            who.setType(Who.TYPE_NONE);
            break;
          case Calendar.Attendees.TYPE_REQUIRED:
            who.setType(Who.TYPE_REQUIRED);
            break;
          case Calendar.Attendees.TYPE_OPTIONAL:
            who.setType(Who.TYPE_OPTIONAL);
            break;
          default:
            Log.e(TAG, "Unknown attendee type: " + type);
            who.setType(Who.TYPE_NONE);
            break;
        }
        int rel = c.getInt(relIndex);
        switch (rel) {
          case Calendar.Attendees.RELATIONSHIP_NONE:
            who.setRelationship(Who.RELATIONSHIP_NONE);
            break;
          case Calendar.Attendees.RELATIONSHIP_ATTENDEE:
            who.setRelationship(Who.RELATIONSHIP_ATTENDEE);
            break;
          case Calendar.Attendees.RELATIONSHIP_ORGANIZER:
            who.setRelationship(Who.RELATIONSHIP_ORGANIZER);
            break;
          case Calendar.Attendees.RELATIONSHIP_SPEAKER:
            who.setRelationship(Who.RELATIONSHIP_SPEAKER);
            break;
          case Calendar.Attendees.RELATIONSHIP_PERFORMER:
            who.setRelationship(Who.RELATIONSHIP_PERFORMER);
            break;
          default:
            Log.e(TAG, "Unknown attendee relationship: " + rel);
            who.setRelationship(Who.RELATIONSHIP_NONE);
            break;
        }
        event.addAttendee(who);
      }
    } finally {
      c.close();
    }
  }