'Given a list of event_ids this method fetches the state at each
event, resolves conflicts between them and returns them.
Returns:
a Deferred tuple of (`state_group`, `state`, `prev_state`).
`state_group` is the name of a state group if one and only one is
involved. `state` is a map from (type, state_key) to event, and
`prev_state` is a list of event ids.'

@defer.inlineCallbacks
@log_function
def resolve_state_groups(self, room_id, event_ids):

    logger.debug('resolve_state_groups    event_ids    %s', event_ids)
    state_groups_ids = (yield self.store.get_state_groups_ids(room_id, event_ids))
    logger.debug('resolve_state_groups    state_groups    %s', state_groups_ids.keys())
    group_names = frozenset(state_groups_ids.keys())
    if (len(group_names) == 1):
        (name, state_list) = state_groups_ids.items().pop()
        (prev_group, delta_ids) = (yield self.store.get_state_group_delta(name))
        defer.returnValue(_StateCacheEntry(state=state_list, state_group=name, prev_group=prev_group, delta_ids=delta_ids))
    with (yield self.resolve_linearizer.queue(group_names)):
        if (self._state_cache is not None):
            cache = self._state_cache.get(group_names, None)
            if cache:
                defer.returnValue(cache)
        logger.info('Resolving    state    for    %s    with    %d    groups', room_id, len(state_groups_ids))
        state = {}
        for st in state_groups_ids.values():
            for (key, e_id) in st.items():
                state.setdefault(key, set()).add(e_id)
        conflicted_state = {k: list(v) for (k, v) in state.items() if (len(v) > 1)}
        if conflicted_state:
            logger.info('Resolving    conflicted    state    for    %r', room_id)
            with Measure(self.clock, 'state._resolve_events'):
                new_state = (yield resolve_events(state_groups_ids.values(), state_map_factory=(lambda ev_ids: self.store.get_events(ev_ids, get_prev_content=False, check_redacted=False))))
        else:
            new_state = {key: e_ids.pop() for (key, e_ids) in state.items()}
        state_group = None
        new_state_event_ids = frozenset(new_state.values())
        for (sg, events) in state_groups_ids.items():
            if (new_state_event_ids == frozenset((e_id for e_id in events))):
                state_group = sg
                break
        prev_group = None
        delta_ids = None
        for (old_group, old_ids) in state_groups_ids.iteritems():
            if (not (set(new_state) - set(old_ids))):
                n_delta_ids = {k: v for (k, v) in new_state.iteritems() if (old_ids.get(k) != v)}
                if ((not delta_ids) or (len(n_delta_ids) < len(delta_ids))):
                    prev_group = old_group
                    delta_ids = n_delta_ids
        cache = _StateCacheEntry(state=new_state, state_group=state_group, prev_group=prev_group, delta_ids=delta_ids)
        if (self._state_cache is not None):
            self._state_cache[group_names] = cache
        defer.returnValue(cache)
