/*! \mainpage Device Library overview
 *
 * The device and enterprise client libraries simplify working with the Oracle IoT Cloud Service.
 * 
 * <p>The device and enterprise client libraries simplify working with the Oracle IoT
 * Cloud Service. These client libraries are a low-level abstraction over
 * top of messages and REST APIs. Device clients are primarily concerned with 
 * sending data and alert messages to the cloud service, and acting upon requests
 * from the cloud service. Enterprise clients are primarily concerned with 
 * monitor and control of device endpoints.</p>
 * 
 * <p>The Oracle Internet of Things C Client Library is a high level native library 
 * for accessing the Oracle IoT Cloud Service. Basically, Cloud Service supports 
 * only low level REST API and this library provides higher level abstraction on 
 * top of that making development of client applications easier and faster.</p>
 *
 * <h3>Trusted Assets</h3>
 *
 * <p>Trusted assets are defined as material that contribute to the chain of trust
 * between the client and the server. The client library relies on an
 * implementation of a TrustedAssetsManager to securely manage these
 * assets on the client. The client-library has a default implementation of the
 * TrustedAssetsManager which uses a trust-store to secure the trust assets.
 * To create the trust-store for the default TrustedAssetsManager, the user must
 * use the iotcs_tam.h methods.</p>
 *
 * <h3>Device Client Quick Start</h3>
 * 
 * <p>Note: C Posix library uses strlen(). Be sure tha you use a single byte chars and null terminated strings.</p>
 * <p>The following steps must be taken to run a device-client application.</p>
 * 
 * <ol>
 * <li>Initialize device client
 * <pre>
//// Initialize the library before any other calls. 
//// Initiate all subsystems like ssl, TAM, request dispatcher, 
//// async message dispatcher, etc which needed for correct library work.
//// Initialization require a path to trusted assets store and
//// a password for trusted assets store.
iotcs_init(trusted_assets_store_path, trusted_assets_store_password);
 * </pre>
 * </li>
 * <li>Activate the device
 * <pre>
//// set supported device models by device
if (!iotcs_is_activated()) {
    iotcs_activate(device_models);
}
 * </pre>
 * </li>
 * <li>Register indirectly-connected devices 
 * <pre>
//// create meta-data with the indirectly-connected device's
//// manufacturer, model, and serial number
const static iotcs_key_value temp_metadata[] = {
    {"manufacturer", "A Manufacturer"},
    {"modelNumber", "MN-xxxx-xxxx"},
    {"serialNumber", "SN-yyyyyyyy"},
    {NULL, NULL}
};
//// add any vendor-specific meta-data to the metaData Map
//// register it
iotcs_register_device(hardware_id, metadata, device_models, output_endpoint_id);
 * </pre>
 * </li>
 * <li>Register handler for attributes  
 * <pre>
request_dispatcher_init();
register_request_handler(endpoint_id, resource_path, resource_handler, arguments);
 * </pre>
 * </li>
 * <li>Send data from the indirectly-connected device
 * <pre>
//// create a Data or Alert Message
iotcs_message_base data_msg_base = {
    .type = IOTCS_MESSAGE_DATA,
    .reliability = IOTCS_MESSAGE_RELIABILITY_BEST_EFFORT,
    .priority = IOTCS_MESSAGE_PRIORITY_HIGH,
    .destination = "iotserver",
};

iotcs_data_message_base data_base = {
    .format = "urn:com:oracle:iot:device:humidity_sensor:attributes"
};

iotcs_data_item_desc desc[] = {
    { .type = IOTCS_VALUE_TYPE_INT, .key = "humidity"},
    { .type = IOTCS_VALUE_TYPE_INT, .key = "maxThreshold"},
    { .type = IOTCS_VALUE_TYPE_NONE, .key = NULL}
};

iotcs_value values[2];
values[0].int_value = int_value;
values[1].int_value = int_value;

iotcs_message iotcs_data_message = {
    .id = "",
    .base = &data_msg_base,
    .u.data.base = &data_base,
    .u.data.items_desc = desc,
    .u.data.items_value = values
};  
//// send the message
iotcs_send(&data_message, message_length, &fail_reason)
 * </pre>
 * </li>
 * <li>Receive and dispatch requests from the server
 * <pre>
while (NULL != (request_from_server = iotcs_receive(0))) {
    request_dispatcher_dispatch(request_from_server, &response);
    if (iotcs_send(&response, 1, &fail_reason) != IOTCS_RESULT_OK) {
        printf("Response sending has failed: %s\n", fail_reason);
    } else {
        printf("Response has been sent!\n");
    }
}
 * </pre>
 * </li>
 * <h3>Storage Cloud Quick Start</h3>
 *
 * <p>This shows how to use the messaging API to upload content to, or download content from, the Oracle Storage Cloud Service. To upload or
 * download content, there must be an attribute, field, or action in the device model with type URI. When creating a DataItem for an attribute, field,
 * or action of type URI, the value is set to the URI of the content in cloud storage. </p>
 *
 * <b>Uploading content</b>
 * <p>An instance of iotcs_storage_object is first needed to upload the content. The iotcs_storage_object is created using the
 * iotcs_create_storage_object API in "advanced/iotcs_storage_object.h". A iotcs_storage_object names the object in storage, and provides the mime-type
 * of the content. </p>
 * <p>To set the input to upload, the iotcs_storage_object API iotcs_storage_object_set_input_path(file_path) is used. Note that the storage_dispatcher
 * is a utility for putting the sync in the background. Progress can be monitored by setting a iotcs_storage_dispatcher_progress_callback on the
 * storage_dispatcher. iotcs_storage_dispatcher is an alternative to using the iotcs_storage_object_sync() API. </p>
 * <pre>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iotcs_device.h"
#include "advanced/iotcs_messaging.h"
#include "advanced/iotcs_storage_object.h"

static void progress_callback(iotcs_storage_object *storage,
            iotcs_storage_dispatcher_progress_state progress_state,
            int64_t bytes_transfered, const char *fail_reason) {
    if (progress_state == IOTCS_IN_PROGRESS) {
        if(iotcs_storage_object_get_input_path(storage)) {
            printf("*** scs %s file upload progress = %" PRId64 " bytes***\n", iotcs_storage_object_get_name(storage), bytes_transfered);
        } else {
            printf("*** scs %s file download progress = %" PRId64 " bytes***\n", iotcs_storage_object_get_name(storage), bytes_transfered);
        }
        
////check cancellation condition
        if (is_timeout()) {
            iotcs_storage_object_cancel(storage);    
        }
    }
    
    if (progress_state == IOTCS_CANCELED) {
        if(iotcs_storage_object_get_input_path(storage)) {
            printf("*** scs %s file upload was canceled. Total bytes: %" PRId64 " bytes***\n", iotcs_storage_object_get_name(storage), bytes_transfered);
        } else {
            printf("*** scs %s file download was canceled. Total bytes: %" PRId64 " bytes***\n", iotcs_storage_object_get_name(storage), bytes_transfered);
        }        
    }
    
    if (progress_state == IOTCS_COMPLETED) {
        printf("*** scs operation for %s was successed. Total bytes: %" PRId64 "***\n",iotcs_storage_object_get_name(storage), bytes_transfered);
    } else {  
        printf("*** scs operation failed***\n");
        if(fail_reason) {
            printf("*** Fail reason: %s", fail_reason);    
        }
    }    
    return 0;
}
...
main() {
    iotcs_storage_object *src_storage;
    iotcs_storage_object *dest_storage;
//// Upload
    iotcs_create_storage_object(name, "application/x-www-form-urlencoded", &src_storage);
    iotcs_storage_object_set_input_path(src_storage, filename);
    iotcs_storage_dispatcher_set_callback(progress_callback);
    //upload
    iotcs_storage_dispatcher_queue(src_storage);

//// Download
    iotcs_create_storage_object(name, "application/x-www-form-urlencoded", &dest_storage);
    iotcs_storage_object_set_output_path(dest_storage, "NewFile.txt");

    iotcs_storage_dispatcher_queue(dest_storage);
    iotcs_free_storage_object(dest_storage);
    iotcs_free_storage_object(src_storage);
}
 * </pre>
 * <li>Dispose the device client 
 * <pre>iotcs_finalize();</pre>
 * </li>
 * </ol>
 */