int CalDavClient::removeCommonIncidences(KCalCore::Incidence::List *firstList, KCalCore::Incidence::List *secondList)
{
    QSet<QString> firstListUids;
    for (int i=0; i<firstList->count(); i++) {
        firstListUids.insert(firstList->at(i)->uid());
    }
    QSet<QString> commonUids;
    for (KCalCore::Incidence::List::iterator it = secondList->begin(); it != secondList->end();) {
        KCalCore::Incidence::Ptr incidence = *it;
        if (firstListUids.contains(incidence->uid())) {
            commonUids.insert(incidence->uid());
            it = secondList->erase(it);
        } else {
            ++it;
        }
    }
    int removed = commonUids.count();
    if (removed > 0) {
        for (KCalCore::Incidence::List::iterator it = firstList->begin(); it != firstList->end();) {
            KCalCore::Incidence::Ptr incidence = *it;
            if (commonUids.contains(incidence->uid())) {
                commonUids.remove(incidence->uid());
                it = firstList->erase(it);
            } else {
                ++it;
            }
        }
    }
    return removed;
}
static bool incidenceLessThan(const KCalCore::Incidence::Ptr e1,
                              const KCalCore::Incidence::Ptr e2)
{
    if (e1->dtStart() == e2->dtStart()) {
        int cmp = QString::compare(e1->summary(),
                                   e2->summary(),
                                   Qt::CaseInsensitive);
        if (cmp == 0)
            return QString::compare(e1->uid(), e2->uid()) < 0;
        else
            return cmp < 0;
    } else {
        return e1->dtStart() < e2->dtStart();
    }
}
bool NotebookSyncAgent::discardRemoteChanges(KCalCore::Incidence::List *localInserted,
                                             KCalCore::Incidence::List *localModified,
                                             KCalCore::Incidence::List *localDeleted)
{
    NOTEBOOK_FUNCTION_CALL_TRACE;

    // Go through the local inserted, modified and deletions list and:
    // - Discard from them respectively the additions, modifications and deletions that were
    //   created as a result of the last remote sync.
    // - Discard any incidences that have already been deleted on the server. (These will be
    //   deleted locally when the current sync finishes.)
    // - Discard any local modifications that were modified on the server, as the server
    //   modifications take precedence.

    if (!mNotebook) {
        LOG_CRITICAL("no notebook");
        return false;
    }
    bool ok = false;
    QSet<QString> remoteDeletedIncidences = QSet<QString>::fromList(mIncidenceUidsToDelete);

    QStringList additions = mDatabase->additions(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync additions for notebook:" << mNotebook->uid());
        return false;
    }
    QHash<QString,QString> modifications = mDatabase->modifications(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync modifications for notebook:" << mNotebook->uid());
        return false;
    }

    for (KCalCore::Incidence::List::iterator it = localInserted->begin(); it != localInserted->end();) {
        const KCalCore::Incidence::Ptr &incidence = *it;
        const QString &uid = incidence->uid();
        if (remoteDeletedIncidences.contains(uid)) {
            LOG_DEBUG("Discarding addition deleted on server:" << uid);
            it = localInserted->erase(it);
        } else if (additions.indexOf(uid) >= 0) {
            if (incidence->lastModified().isValid() && incidence->lastModified() > incidence->created()) {
                // This incidence has been modified since it was added from the server in the last sync,
                // so it's a modification rather than an addition.
                LOG_DEBUG("Moving to modified:" << uid);
                KCalCore::Incidence::Ptr savedIncidence = fetchIncidence(mCalendar, uid);
                if (savedIncidence) {
                    localModified->append(savedIncidence);
                    it = localInserted->erase(it);
                } else {
                    ++it;
                }
            } else {
                LOG_DEBUG("Discarding addition from previous sync:" << uid);
                it = localInserted->erase(it);
            }
        } else {
            ++it;
        }
    }

    QSet<QString> serverModifiedUids;
    for (int i=0; i<mReceivedCalendarResources.count(); i++) {
        serverModifiedUids.insert(Reader::hrefToUid(mReceivedCalendarResources[i].href));
    }
    for (KCalCore::Incidence::List::iterator it = localModified->begin(); it != localModified->end();) {
        KCalCore::Incidence::Ptr sourceIncidence = *it;
        const QString &uid = sourceIncidence->uid();
        if (remoteDeletedIncidences.contains(uid) || serverModifiedUids.contains(uid)) {
            LOG_DEBUG("Discarding modification,"
                      << (remoteDeletedIncidences.contains(uid) ? "was already deleted on server" : "")
                      << (serverModifiedUids.contains(uid) ? "was already modified on server": ""));
            it = localModified->erase(it);
            continue;
        } else if (modifications.contains(uid)) {
            KCalCore::ICalFormat iCalFormat;
            KCalCore::Incidence::Ptr receivedIncidence = iCalFormat.fromString(modifications[uid]);
            if (receivedIncidence.isNull()) {
                LOG_WARNING("Not sending modification, cannot parse the received incidence:" << modifications[uid]);
                it = localModified->erase(it);
                continue;
            }
            // If incidences are the same, then we assume the local incidence was not changed after
            // the remote incidence was received, and thus there are no modifications to report.
            IncidenceHandler::prepareImportedIncidence(receivedIncidence);  // ensure fields are updated as per imported incidences
            if (IncidenceHandler::copiedPropertiesAreEqual(sourceIncidence, receivedIncidence)) {
                LOG_DEBUG("Discarding modification" << uid);
                it = localModified->erase(it);
                continue;
            }
        }

        // The default storage implementation applies the organizer as an attendee by default. Don't do this
        // as it turns the incidence into a scheduled event requiring acceptance/rejection/etc.
        const KCalCore::Person::Ptr organizer = sourceIncidence->organizer();
        if (organizer) {
            Q_FOREACH (const KCalCore::Attendee::Ptr &attendee, sourceIncidence->attendees()) {
                if (attendee->email() == organizer->email() && attendee->fullName() == organizer->fullName()) {
                    LOG_DEBUG("Discarding organizer as attendee" << attendee->fullName());
                    sourceIncidence->deleteAttendee(attendee);
                    break;
                }
            }
        }
        ++it;
    }

    QStringList deletions = mDatabase->deletions(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync deletions for notebook:" << mNotebook->uid());
        return false;
    }
    for (KCalCore::Incidence::List::iterator it = localDeleted->begin(); it != localDeleted->end();) {
        const QString &uid = (*it)->uid();
        mLocalDeletedUids.insert(uid);
        if (remoteDeletedIncidences.contains(uid) || deletions.indexOf(uid) >= 0) {
            LOG_DEBUG("Discarding deletion" << uid);
            it = localDeleted->erase(it);
        } else {
            ++it;
        }
    }

    return true;
}