/*
 * The read function gets called every time the routing service
 *  gets notified of data available by the function on_data_available
 *  of every stream reader's listener
 */
void RTI_RoutingServiceFileStreamReader_read(
        RTI_RoutingServiceStreamReader stream_reader,
        RTI_RoutingServiceSample ** sample_list,
        RTI_RoutingServiceSampleInfo ** info_list,
        int * count,
        RTI_RoutingServiceEnvironment * env)
{

    int i = 0, sample_counter = 0;

    struct DDS_DynamicData * sample = NULL;
    struct DDS_DynamicDataProperty_t     dynamic_data_props =
            DDS_DynamicDataProperty_t_INITIALIZER;

    struct RTI_RoutingServiceFileStreamReader * self =
            (struct RTI_RoutingServiceFileStreamReader *) stream_reader;
    /*
     * We don't provide sample info in this adapter, which
     * is an optional feature
     */
    *info_list = NULL;

    /*
     * if the function read it is called because we have discovery data,
     * the pointer or the stream reader that calls the
     */
    if ((self->connection->input_discovery_reader == self)) {
        int new_discovered_samples = 0;

        fprintf(stdout,"DiscoveryReader: called function read "
                "for input discovery\n");
        /*
         * we keep track in the checking thread of the number of file names
         * inside the discovery_data array, every new discovered file, we
         * increase this counter (discovery_data_counter), and we keep track
         * of the files we have already read, and created the relative streams,
         * with the discovery_data_counter_read, subtracting one to another, we
         * know how many new discovered files we have
         */
        new_discovered_samples = self->discovery_data_counter -
                self->discovery_data_counter_read;

        /*
         * we receive as a parameter the pointer to an array, and we need to
         * allocate memory for it, first for the array, then for the single
         * elements we put in it.
         */
        *sample_list = calloc(
                new_discovered_samples,
                sizeof(struct RTI_RoutingServiceStreamInfo *));
        if (*sample_list == NULL) {
            RTI_RoutingServiceEnvironment_set_error(
                    env, "Failure creating dynamic data sample in read "
                    "function for discovery");
            return;
        }

        /*
         * inside this loop we create the sample info structures,
         * to describe the new stream to be created
         */
        for (i = 0; i < new_discovered_samples; i++) {
            struct RTI_RoutingServiceStreamInfo *streaminfo;
            /*
             * here we create the stream info type, passing as string name
             * the name of the file taken from the discovery_data array
             * filled by the checking thread.
             */
            streaminfo = RTI_RoutingServiceStreamInfo_new_discovered(
                    self->discovery_data[self->discovery_data_counter_read],
                    "TextLine",/*typename*/
                    RTI_ROUTING_SERVICE_TYPE_REPRESENTATION_DYNAMIC_TYPE,
                    self->type_code);

            if (streaminfo == NULL) {
                continue;
            }

            (*sample_list)[*count] = streaminfo;
            /*
             * we increment the count of the sample info generated and returned
             * inside the sampli_list dynamic array.
             */
            (*count)++;
            /*
             * we increment the index as we have already read that
             * position of the array
             */
            self->discovery_data_counter_read++;
        }


    } else {

        fprintf(stdout,"StreamReader: called function read for data\n");

        *sample_list = calloc(self->samples_per_read,sizeof(DDS_DynamicData *));
        if (*sample_list == NULL) {
            RTI_RoutingServiceEnvironment_set_error(
                    env,"Failure creating dynamic data "
                            "sample list in read function");
            return;
        }

        /*
         *  Read as many times as samples_per_read
         *  (or less if we encounter the end of file)
         */
        for (i = 0; i < self->samples_per_read && !feof(self->file); i++) {

            /*
             * Create a dynamic data sample for every buffer we read. We use
             * the type we received when the stream reader was created
             */
            sample = DDS_DynamicData_new(self->type_code, &dynamic_data_props);
            if (sample == NULL) {
                RTI_RoutingServiceEnvironment_set_error(
                        env,
                        "Failure creating dynamic data sample in read function");
                RTI_RoutingServiceFileStreamReader_freeDynamicDataArray(
                        (struct DDS_DynamicData **) *sample_list, sample_counter);
                *sample_list = NULL;
                return;
            }
            /*
             * Fill the dynamic data sample fields
             * with the buffer read from the file.
             */
            if ( !RTI_RoutingServiceFileAdapter_read_sample(
                    sample, self->file,
                    env)) {
                /* No sample read */
                DDS_DynamicData_delete(sample);
                continue;
            }

            (*sample_list)[sample_counter++] = sample;
        }
        /* Set the count to the actual number of samples we have generated */
        *count = sample_counter;

    }
    /*
     * If there are no samples to read we free the memory allocated straight
     * away as the routing service wouldn't call return_loan
     */
    if (*count == 0) {
        /* If we report zero samples we have to free the array now */
        free(*sample_list);
        *sample_list = NULL;
    }


}
int main() {
    struct DDS_TypeCode *inner_tc = NULL;
    struct DDS_TypeCode *outer_tc = NULL;
    struct DDS_TypeCodeFactory *factory = NULL;

    DDS_ExceptionCode_t err;
    DDS_ReturnCode_t retcode;
    int ret = -1;

    DDS_DynamicData *outer_data = NULL;
    DDS_DynamicData *inner_data = NULL;
    DDS_DynamicData *bounded_data = NULL;

    /* Getting a reference to the type code factory */
    factory = DDS_TypeCodeFactory_get_instance();
    if (factory == NULL) {
        fprintf(stderr, "! Unable to get type code factory singleton\n");
        goto fail;
    }

    /* Creating the typeCode of the inner_struct */
    inner_tc = inner_struct_get_typecode(factory);
    if (inner_tc == NULL) {
        fprintf(stderr, "! Unable to create typeCode\n");
        goto fail;
    }

    /* Creating the typeCode of the outer_struct that contains an inner_struct */
    outer_tc = outer_struct_get_typecode(factory);
    if (inner_tc == NULL) {
        fprintf(stderr, "! Unable to create typeCode\n");
        goto fail;
    }

    printf(" Connext Dynamic Data Nested Struct Example \n"
            "--------------------------------------------\n");

    printf(" Data Types\n"
            "------------------\n");
    DDS_TypeCode_print_IDL(inner_tc, 0, &err);
    DDS_TypeCode_print_IDL(outer_tc, 0, &err);

    /* Now, we create a dynamicData instance for each type */
    outer_data = DDS_DynamicData_new(outer_tc,
            &DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
    if (outer_data == NULL) {
        fprintf(stderr, "! Unable to create outer dynamicData\n");
        goto fail;
    }

    inner_data = DDS_DynamicData_new(inner_tc,
            &DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
    if (outer_data == NULL) {
        fprintf(stderr, "! Unable to create inner dynamicData\n");
        goto fail;
    }
    /* Setting the inner data */
    retcode = DDS_DynamicData_set_double(inner_data, "x",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 3.14159);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value 'x' in the inner struct \n");
        goto fail;
    }

    retcode = DDS_DynamicData_set_double(inner_data, "y",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 2.71828);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value 'y' in the inner struct\n");
        goto fail;
    }

    printf("\n\n get/set_complex_member API\n"
            "----------------------------\n");
    /* Using set_complex_member, we copy inner_data values in inner_struct of
     * outer_data */
    printf("Setting initial values of outer_data with "
            "set_complex_member()\n");
    retcode = DDS_DynamicData_set_complex_member(outer_data, "inner",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, inner_data);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set complex struct value "
                "(member inner in the outer struct)\n");
        goto fail;
    }

    DDS_DynamicData_print(outer_data, stdout, 1);

    retcode = DDS_DynamicData_clear_all_members(inner_data);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to clear all member in the inner data\n");
        goto fail;
    }

    printf("\n + get_complex_member() called\n");
    retcode = DDS_DynamicData_get_complex_member(outer_data, inner_data,
            "inner", DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to get complex struct value "
                "(member inner in the outer struct)\n");
        goto fail;
    }

    printf("\n + inner_data value\n");
    DDS_DynamicData_print(inner_data, stdout, 1);

    /* get_complex_member made a copy of the inner_struct. If we modify
     * inner_data values, outer_data inner_struct WILL NOT be modified. */
    printf("\n + setting new values to inner_data\n");
    retcode = DDS_DynamicData_set_double(inner_data, "x",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 1.00000);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value 'x' in the inner struct \n");
        goto fail;
    }

    retcode = DDS_DynamicData_set_double(inner_data, "y",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 0.00001);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value 'y' in the inner struct \n");
        goto fail;
    }

    DDS_DynamicData_print(inner_data, stdout, 1);

    /* Current value of outer_data
     * outer_data:
     * inner:
     *     x: 3.141590
     *     y: 2.718280
     *
     * inner_data:
     *     x: 1.000000
     *     y: 0.000010
     */

    printf("\n + current outer_data value \n");
    DDS_DynamicData_print(outer_data, stdout, 1);

    /* Bind/Unbind member API */
    printf("\n\n bind/unbind API\n"
            "------------------\n");
    printf("Creating a new dynamic data called bounded_data\n");
    bounded_data = DDS_DynamicData_new(NULL,
            &DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
    if (bounded_data == NULL) {
        fprintf(stderr, "! Unable to create new dynamic data\n");
        goto fail;
    }

    printf("\n + binding bounded_data to outer_data's inner_struct\n");

    /* Using bind_complex_member, we do not copy inner_struct, but bind it.
     * So, if we modify bounded_data, the inner member inside outer_data WILL
     * also be modified */
    retcode = DDS_DynamicData_bind_complex_member(outer_data, bounded_data,
            "inner", DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to bind the structs\n");
        goto fail;
    }

    DDS_DynamicData_print(bounded_data, stdout, 1);

    printf("\n + setting new values to bounded_data\n");
    retcode = DDS_DynamicData_set_double(bounded_data, "x",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 1.00000);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value to 'x' with the bounded data\n");
        goto fail;
    }

    retcode = DDS_DynamicData_set_double(bounded_data, "y",
            DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 0.00001);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to set value to 'x' with the bounded data\n");
        goto fail;
    }

    /* Current value of outer data
     * outer:
     * inner:
     *     x: 1.000000
     *     y: 0.000010
     */

    DDS_DynamicData_print(bounded_data, stdout, 1);
    retcode = DDS_DynamicData_unbind_complex_member(outer_data, bounded_data);
    if (retcode != DDS_RETCODE_OK) {
        fprintf(stderr, "! Unable to unbind the data\n");
        goto fail;
    }

    printf("\n + current outer_data value \n");
    DDS_DynamicData_print(outer_data, stdout, 1);

    ret = 1;

    fail:
    if (inner_tc != NULL) {
        DDS_TypeCodeFactory_delete_tc(factory, inner_tc, NULL);
    }

    if (outer_tc != NULL) {
        DDS_TypeCodeFactory_delete_tc(factory, outer_tc, NULL);
    }

    if (inner_data != NULL) {
        DDS_DynamicData_delete(inner_data);
    }

    if (outer_data != NULL) {
        DDS_DynamicData_delete(outer_data);
    }

    if (bounded_data != NULL) {
        DDS_DynamicData_delete(bounded_data);
    }

    return ret;
}