static void
d_waitForCompletenessDCPSTopic(
    d_groupCreationQueue queue)
{
    d_group dcpstopicGroup;
    d_completeness completeness;
    d_admin admin;
    os_time sleepTime;
    d_durability durability;

    sleepTime.tv_sec  = 1;
    sleepTime.tv_nsec = 0;
    admin             = queue->admin;
    durability        = d_adminGetDurability(admin);

    d_printTimedEvent(durability,
                            D_LEVEL_FINE,
                            D_THREAD_GROUP_CREATION,
                            "Waiting for group '%s.%s' to be created.\n",
                            V_BUILTIN_PARTITION, V_TOPICINFO_NAME);

    do{
        dcpstopicGroup    = d_adminGetLocalGroup(admin,
                                    V_BUILTIN_PARTITION, V_TOPICINFO_NAME,
                                    D_DURABILITY_TRANSIENT);
        if((dcpstopicGroup == NULL) && (queue->terminate == FALSE)){
            os_nanoSleep(sleepTime);
        }
    } while((dcpstopicGroup == NULL) && (queue->terminate == FALSE));

    if(queue->terminate == FALSE){
        d_printTimedEvent(durability,
                                D_LEVEL_FINE,
                                D_THREAD_GROUP_CREATION,
                                "Group '%s.%s' is available. Waiting for completeness...\n",
                                V_BUILTIN_PARTITION, V_TOPICINFO_NAME);
    }

    do{
        if(dcpstopicGroup){
            completeness = d_groupGetCompleteness(dcpstopicGroup);

            if((completeness != D_GROUP_COMPLETE) && (queue->terminate == FALSE)){
                os_nanoSleep(sleepTime);
            }
        } else {
            completeness = D_GROUP_KNOWLEDGE_UNDEFINED;
        }
    } while((completeness != D_GROUP_COMPLETE) && (queue->terminate == FALSE));

    if(queue->terminate == FALSE){
        d_printTimedEvent(durability,
                                D_LEVEL_FINE,
                                D_THREAD_GROUP_CREATION,
                                "Group '%s.%s' is complete now.\n",
                                V_BUILTIN_PARTITION, V_TOPICINFO_NAME);
    } else {
        d_printTimedEvent(durability,
                                D_LEVEL_FINE,
                                D_THREAD_GROUP_CREATION,
                                "Not waiting for group '%s.%s', because termination is in progress.\n",
                                V_BUILTIN_PARTITION, V_TOPICINFO_NAME);
    }
    return;
}
static void*
d_groupCreationQueueRun(
    void* userData)
{
    d_groupCreationQueue queue;
    c_iter groupsToCreate, reinsert;
    d_group group, localGroup;
    d_durability durability;
    d_durabilityKind kind;
    u_participant uservice;
    c_char *partition, *topic;
    v_duration duration;
    u_group ugroup;
    c_long creationCountVolatile, creationCountTransient, creationCountPersistent;
    c_ulong maxBurst;
    os_time sleepTime, maxBurstSleepTime;
    c_bool update;

    sleepTime.tv_sec          = 1;
    sleepTime.tv_nsec         = 0;
    duration.seconds          = 0;
    duration.nanoseconds      = 5000000; /*5ms*/
    creationCountVolatile     = 0;
    creationCountTransient    = 0;
    creationCountPersistent   = 0;
    maxBurstSleepTime.tv_sec  = 0;
    maxBurstSleepTime.tv_nsec = 10000000; /*10ms*/

    queue                = d_groupCreationQueue(userData);
    groupsToCreate       = c_iterNew(NULL);
    reinsert             = c_iterNew(NULL);
    durability           = d_adminGetDurability(queue->admin);
    uservice             = u_participant(d_durabilityGetService(durability));

    d_waitForCompletenessDCPSTopic(queue);

    while(queue->terminate == FALSE) {
        d_lockLock(d_lock(queue));

        queue->groupsToCreateVolatile -= creationCountVolatile;
        assert(queue->groupsToCreateVolatile >= 0);
        queue->groupsToCreateTransient -= creationCountTransient;
        assert(queue->groupsToCreateTransient >= 0);
        queue->groupsToCreatePersistent -= creationCountPersistent;
        assert(queue->groupsToCreatePersistent >= 0);

        group = d_group(c_iterTakeFirst(queue->groups));

        while(group){
            groupsToCreate = c_iterInsert(groupsToCreate, group);
            group = d_group(c_iterTakeFirst(queue->groups));
        }
        assert((queue->groupsToCreateVolatile +
                queue->groupsToCreateTransient +
                queue->groupsToCreatePersistent) ==
               c_iterLength(groupsToCreate));

        durability = d_adminGetDurability(queue->admin);
        d_durabilityUpdateStatistics(durability, d_statisticsUpdateGroupsToCreate, queue);

        d_lockUnlock(d_lock(queue));

        creationCountVolatile   = 0;
        creationCountTransient  = 0;
        creationCountPersistent = 0;
        maxBurst                = 10;

        group = c_iterTakeFirst(groupsToCreate);

        while(group && (queue->terminate == FALSE)){
            partition  = d_groupGetPartition(group);
            topic      = d_groupGetTopic(group);
            kind       = d_groupGetKind(group);
            localGroup = d_adminGetLocalGroup(queue->admin, partition, topic, kind);
            update     = FALSE;

            if(localGroup) {
                d_printTimedEvent(durability,
                            D_LEVEL_FINE,
                            D_THREAD_GROUP_CREATION,
                            "Remote group %s.%s has already been created locally.\n",
                            partition, topic);
                update = TRUE;
            } else {
                ugroup = u_groupNew(uservice, partition, topic, duration);

                if(ugroup){
                    d_printTimedEvent(durability,
                                    D_LEVEL_FINE,
                                    D_THREAD_GROUP_CREATION,
                                    "Remote group %s.%s created locally.\n",
                                    partition, topic);
                    update = TRUE;
                    u_entityFree(u_entity(ugroup));
                    maxBurst--;

                    if(maxBurst == 0){
                        os_nanoSleep(maxBurstSleepTime);
                        maxBurst = 10;
                    }
                } else {
                    maxBurst++;
                    d_printTimedEvent(durability, D_LEVEL_FINE,
                                D_THREAD_GROUP_CREATION,
                                "Remote group %s.%s could not be created locally.\n",
                                partition, topic);

                    if(d_durabilityGetState(durability) == D_STATE_COMPLETE){
                        d_printTimedEvent(durability, D_LEVEL_FINE,
                                D_THREAD_GROUP_CREATION,
                                "I am complete so it will not be available anymore.\n");
                        update = TRUE;
                    } else if(d_adminGetFellowCount(queue->admin) == 0){
                        d_printTimedEvent(durability, D_LEVEL_WARNING,
                                D_THREAD_GROUP_CREATION,
                                "No fellows available to provide me with group information. " \
                                "Ignoring group.\n",
                                partition, topic);
                        update = TRUE;
                    } else {
                        reinsert = c_iterInsert(reinsert, group);
                    }
                }
            }
            if(update){
                switch(d_groupGetKind(group)){
                case D_DURABILITY_VOLATILE:
                    creationCountVolatile++;
                    break;
                case D_DURABILITY_TRANSIENT:
                case D_DURABILITY_TRANSIENT_LOCAL:
                    creationCountTransient++;
                    break;
                case D_DURABILITY_PERSISTENT:
                    creationCountPersistent++;
                    break;
                default:
                    assert(FALSE);
                    break;
                }
                d_groupFree(group);
            }
            os_free(partition);
            os_free(topic);
            group = c_iterTakeFirst(groupsToCreate);
        }
        group = d_group(c_iterTakeFirst(reinsert));

        while(group){
            groupsToCreate = c_iterInsert(groupsToCreate, group);
            group = d_group(c_iterTakeFirst(reinsert));
        }
        if(queue->terminate == FALSE){
            os_nanoSleep(sleepTime);
        }
    }

    group = d_group(c_iterTakeFirst(groupsToCreate));

    while(group) {
        d_groupFree(group);
        group = d_group(c_iterTakeFirst(groupsToCreate));
    }
    c_iterFree(groupsToCreate);
    c_iterFree(reinsert);

    d_lockLock(d_lock(queue));
    group = d_group(c_iterTakeFirst(queue->groups));

    while(group) {
        d_groupFree(group);
        group = d_group(c_iterTakeFirst(queue->groups));
    }
    d_lockUnlock(d_lock(queue));

    return NULL;
}
void
d_groupRemoteListenerAction(
    d_listener listener,
    d_message message)
{
    d_newGroup remote;
    d_configuration config;
    d_durability durability;
    d_admin admin;
    d_group group, group2;
    d_fellow fellow;
    c_bool createLocally, added;
    v_duration duration;
    u_group ugroup;
    d_networkAddress addr;
    c_bool result;
    d_subscriber subscriber;
    d_sampleChainListener sampleChainListener;
    d_completeness localCompleteness;

    assert(d_listenerIsValid(d_listener(listener), D_GROUP_REMOTE_LISTENER));

    remote     = d_newGroup(message);
    admin      = d_listenerGetAdmin(listener);
    durability = d_adminGetDurability(admin);
    config     = d_durabilityGetConfiguration(durability);
    addr       = d_networkAddressNew(message->senderAddress.systemId,
                                     message->senderAddress.localId,
                                     message->senderAddress.lifecycleId);
    fellow     = d_adminGetFellow(admin, addr);

    if(remote->partition && remote->topic){
        d_printTimedEvent(durability, D_LEVEL_FINEST,
                          D_THREAD_GROUP_REMOTE_LISTENER,
                          "Received remote group '%s.%s'.\n",
                          remote->partition, remote->topic);
    }
    if(fellow){
        if(d_fellowGetCommunicationState(fellow) == D_COMMUNICATION_STATE_APPROVED){
            if(!(remote->partition) && !(remote->topic)){
                d_fellowSetExpectedGroupCount(fellow, remote->alignerCount);
            } else {
                group = d_adminGetLocalGroup(admin, remote->partition,
                                             remote->topic, remote->durabilityKind);
                if(!group){
                    d_printTimedEvent(durability, D_LEVEL_FINE,
                                            D_THREAD_GROUP_REMOTE_LISTENER,
                                            "Received remote group %s.%s which is locally unknown.\n",
                                            remote->partition, remote->topic);

                    /* Group unknown locally, check if it is in the alignee namespace.
                     */
                    createLocally = d_adminGroupInAligneeNS(
                                                admin, remote->partition,
                                                remote->topic,
                                                remote->durabilityKind);

                    if(createLocally == TRUE){
                        group = d_groupNew(remote->partition, remote->topic,
                                           remote->durabilityKind,
                                           remote->completeness, remote->quality);
                        added = d_fellowAddGroup(fellow, group);
                        d_fellowSetExpectedGroupCount(fellow, remote->alignerCount);

                        if(added == FALSE){
                            d_groupFree(group);
                            group = d_fellowGetGroup(fellow, remote->partition,
                                                     remote->topic,
                                                     remote->durabilityKind);

                            if(group){
                                d_groupUpdate(group, remote->completeness,
                                              remote->quality);
                                d_groupFree(group);
                            }
                        }
                        /* Group unknown locally, check if it should be aligned
                         * initially.
                         */
                        createLocally = d_adminGroupInInitialAligneeNS(
                                                    admin, remote->partition,
                                                    remote->topic,
                                                    remote->durabilityKind);

                        if(createLocally == TRUE){
                            d_printTimedEvent(durability, D_LEVEL_FINE,
                                                D_THREAD_GROUP_REMOTE_LISTENER,
                                                "Remote group %s.%s in initial alignee namespace.\n",
                                                remote->partition, remote->topic);

                            duration.seconds = 0;
                            duration.nanoseconds = 10000000;

                            ugroup = u_groupNew(
                                    u_participant(d_durabilityGetService(durability)),
                                    remote->partition, remote->topic, duration);

                            if(ugroup){
                                d_printTimedEvent(durability, D_LEVEL_FINE,
                                                D_THREAD_GROUP_REMOTE_LISTENER,
                                                "Remote group %s.%s with quality %d created locally.\n",
                                                remote->partition, remote->topic, remote->quality.seconds);
                                u_entityFree(u_entity(ugroup));
                            } else {
                                d_printTimedEvent(durability, D_LEVEL_WARNING,
                                    D_THREAD_GROUP_REMOTE_LISTENER,
                                    "Remote group %s.%s with quality %d could NOT be created locally.\n",
                                    remote->partition, remote->topic, remote->quality.seconds);
                                /**
                                 * TODO: quality must not be taken over
                                 * from remote.
                                 */
                                group2 = d_groupNew(remote->partition, remote->topic,
                                               remote->durabilityKind,
                                               D_GROUP_INCOMPLETE,
                                               remote->quality);
                                result = d_groupCreationQueueAdd(
                                    d_groupRemoteListener(listener)->groupCreationQueue,
                                    group2);

                                if(result == FALSE){
                                    d_printTimedEvent(durability, D_LEVEL_FINER,
                                            D_THREAD_GROUP_REMOTE_LISTENER,
                                            "Remote group %s.%s already in creation queue. Skipping this one.\n",
                                            remote->partition, remote->topic);
                                    d_groupFree(group2);
                                }
                            }
                        } else {
                            d_printTimedEvent(durability, D_LEVEL_FINE,
                                            D_THREAD_GROUP_REMOTE_LISTENER,
                                            "Remote group %s.%s in alignee namespace, but not initial.\n",
                                            remote->partition, remote->topic);
                        }
                    } else {
                        d_printTimedEvent(durability, D_LEVEL_INFO,
                            D_THREAD_GROUP_REMOTE_LISTENER,
                            "Remote group '%s.%s' is not in alignee namespace.\n",
                            remote->partition, remote->topic);
                    }
                } else {
                    localCompleteness = d_groupGetCompleteness(group);
                    group = d_fellowGetGroup(fellow, remote->partition,
                                                     remote->topic,
                                                     remote->durabilityKind);

                    if(group){
                        d_groupUpdate(group, remote->completeness,
                                      remote->quality);
                        d_printTimedEvent(durability, D_LEVEL_FINEST,
                              D_THREAD_GROUP_REMOTE_LISTENER,
                              "Updating remote group '%s.%s' completeness: '%d'.\n",
                              remote->partition, remote->topic, remote->completeness);
						d_groupFree(group);
                    } else if(localCompleteness != D_GROUP_COMPLETE){
                        group = d_groupNew(remote->partition, remote->topic,
                                           remote->durabilityKind,
                                           remote->completeness, remote->quality);
                        added = d_fellowAddGroup(fellow, group);

                        if(added == FALSE){
                            d_groupFree(group);
                            group = d_fellowGetGroup(fellow, remote->partition,
                                                     remote->topic,
                                                     remote->durabilityKind);

                            if(group){
                                d_groupUpdate(group, remote->completeness,
                                              remote->quality);
                                d_groupFree(group);
                            }
                        } else {

                            d_printTimedEvent(durability, D_LEVEL_FINEST,
                                                      D_THREAD_GROUP_REMOTE_LISTENER,
                                                      "Remote group '%s.%s' with completeness: '%d' registered for fellow.\n",
                                                      remote->partition, remote->topic, remote->completeness);
                        }
                    }
                    /* A complete group might be interesting in case there are
                     * still unfullfilled chain requests.
                     */
                    if(remote->completeness == D_GROUP_COMPLETE){
                        d_printTimedEvent(durability, D_LEVEL_FINEST,
                                                  D_THREAD_GROUP_REMOTE_LISTENER,
                                                  "Remote group '%s.%s' complete, check for unfullfilled chains.\n",
                                                  remote->partition, remote->topic);
                        subscriber = d_adminGetSubscriber(admin);
                        sampleChainListener = d_subscriberGetSampleChainListener(subscriber);

                        group = d_groupNew(remote->partition, remote->topic,
                                           remote->durabilityKind,
                                           remote->completeness, remote->quality);

                        d_sampleChainListenerTryFulfillChains(sampleChainListener, group);

                        d_groupFree(group);
                    }
                }
            }
        } else {
            d_printTimedEvent(durability, D_LEVEL_WARNING,
                       D_THREAD_GROUP_REMOTE_LISTENER,
                      "Fellow not approved, so ignore the message.\n");
        }
        d_fellowFree(fellow);
    } else {
        d_printTimedEvent(durability, D_LEVEL_WARNING,
                D_THREAD_GROUP_REMOTE_LISTENER,
                "Fellow unknown so far, so ignore the message.\n");
    }
    d_networkAddressFree(addr);

    return;
}