'Calculate the new state deltas for a room.
Assumes that we are only persisting events for one room at a time.
Returns:
3-tuple (to_delete, to_insert, new_state) where both are state dicts,
i.e. (type, state_key) -> event_id. `to_delete` are the entries to
first be deleted from current_state_events, `to_insert` are entries
to insert. `new_state` is the full set of state.
May return None if there are no changes to be applied.'

@defer.inlineCallbacks
def _calculate_state_delta(self, room_id, events_context, new_latest_event_ids):

    state_sets = []
    state_groups = set()
    missing_event_ids = []
    was_updated = False
    for event_id in new_latest_event_ids:
        for (ev, ctx) in events_context:
            if (event_id == ev.event_id):
                if (ctx.current_state_ids is None):
                    raise Exception('Unknown    current    state')
                if (ctx.state_group not in state_groups):
                    state_sets.append(ctx.current_state_ids)
                    if (ctx.delta_ids or hasattr(ev, 'state_key')):
                        was_updated = True
                    if ctx.state_group:
                        state_groups.add(ctx.state_group)
                break
        else:
            was_updated = True
            missing_event_ids.append(event_id)
    if missing_event_ids:
        event_to_groups = (yield self._get_state_group_for_events(missing_event_ids))
        groups = (set(event_to_groups.itervalues()) - state_groups)
        if groups:
            group_to_state = (yield self._get_state_for_groups(groups))
            state_sets.extend(group_to_state.itervalues())
    if (not new_latest_event_ids):
        current_state = {}
    elif was_updated:
        if (len(state_sets) == 1):
            current_state = state_sets[0]
        else:
            events_map = {ev.event_id: ev for (ev, _) in events_context}
            @defer.inlineCallbacks
            def get_events(ev_ids):
                db = []
                to_return = {}
                for ev_id in ev_ids:
                    ev = events_map.get(ev_id, None)
                    if ev:
                        to_return[ev_id] = ev
                    else:
                        db.append(ev_id)
                if db:
                    evs = (yield self.get_events(ev_ids, get_prev_content=False, check_redacted=False))
                    to_return.update(evs)
                defer.returnValue(to_return)
            current_state = (yield resolve_events(state_sets, state_map_factory=get_events))
    else:
        return
    existing_state = (yield self.get_current_state_ids(room_id))
    existing_events = set(existing_state.itervalues())
    new_events = set((ev_id for ev_id in current_state.itervalues()))
    changed_events = (existing_events ^ new_events)
    if (not changed_events):
        return
    to_delete = {key: ev_id for (key, ev_id) in existing_state.iteritems() if (ev_id in changed_events)}
    events_to_insert = (new_events - existing_events)
    to_insert = {key: ev_id for (key, ev_id) in current_state.iteritems() if (ev_id in events_to_insert)}
    defer.returnValue((to_delete, to_insert, current_state))
