TEST(cps_api_key,key_insert) {
    cps_api_key_t key;
    memset(&key,0,sizeof(key));
    cps_api_key_set(&key,0,0);
    cps_api_key_set(&key,1,1);
    cps_api_key_set(&key,2,2);
    cps_api_key_set_len(&key,3);

    cps_api_key_t new_key ;
    cps_api_key_copy(&new_key,&key);


    cps_api_key_remove_element(&new_key,0);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,0)== 1);
    ASSERT_TRUE(cps_api_key_get_len(&new_key)==2);

    cps_api_key_insert_element(&new_key,0,5);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,0)== 5);
    ASSERT_TRUE(cps_api_key_get_len(&new_key)==3);

    cps_api_key_insert_element(&new_key,3,5);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,3)== 5);
    ASSERT_TRUE(cps_api_key_get_len(&new_key)==4);

    cps_api_key_insert_element(&new_key,2,5);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,2)== 5);
    ASSERT_TRUE(cps_api_key_get_len(&new_key)==5);

    ASSERT_TRUE(cps_api_key_element_at(&new_key,0)== 5);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,2)== 5);
    ASSERT_TRUE(cps_api_key_element_at(&new_key,4)== 5);

}
TEST(cps_api_key,key_create) {
    cps_api_key_t key;
    memset(&key,0,sizeof(key));
    cps_api_key_set(&key,0,0);
    cps_api_key_set(&key,1,1);
    cps_api_key_set(&key,2,2);
    cps_api_key_set_len(&key,3);

    ASSERT_TRUE(cps_api_key_get_len(&key)==3);
    ASSERT_TRUE(cps_api_key_element_at(&key,0)==0);
    ASSERT_TRUE(cps_api_key_element_at(&key,1)==1);
    ASSERT_TRUE(cps_api_key_element_at(&key,2)==2);

}
extern "C" cps_api_return_code_t cps_api_object_stats(cps_api_key_t *key, cps_api_object_t stats_obj) {
    cps_api_return_code_t rc = cps_api_ret_code_ERR;

    cps_api_channel_t handle = -1;

    if (key==nullptr || cps_api_key_get_len(key)==0) {
        std_socket_address_t addr;
        cps_api_ns_get_address(&addr);

        int sock;
        t_std_error _rc = std_sock_connect(&addr,&sock);
        if (_rc!=STD_ERR_OK) {
            return rc;
        }
        handle = sock;
    } else {
        if (!cps_api_get_handle(*key,handle)) {
            char buff[CPS_API_KEY_STR_MAX];
            EV_LOG(ERR,DSAPI,0,"NS","Failed to find owner for %s",
                    cps_api_key_print(key,buff,sizeof(buff)-1));
            return cps_api_ret_code_NO_SERVICE;
        }
    }
    if (handle==-1) {
        EV_LOG(ERR,DSAPI,0,"NS-STATS","No connection to the NS for stats.");
        return rc;
    }
    do {
        if (!cps_api_send_header(handle,cps_api_msg_o_STATS,0)) {
            break;
        }
        size_t len;
        uint32_t op=0;
        if (!cps_api_receive_header(handle,op,len)) break;
        if (op!=cps_api_msg_o_STATS) break;

        cps_api_object_guard og (cps_api_receive_object(handle,len));
        if(!og.valid()) return false;

        if (!cps_api_object_clone(stats_obj,og.get())) {
            break;
        }
        rc = cps_api_ret_code_OK;
    } while (0);
    cps_api_disconnect_owner(handle);
    return rc;
}
cps_api_return_code_t ds_api_linux_interface_get_function (void * context, cps_api_get_params_t * param, size_t ix) {
    cps_api_return_code_t rc = cps_api_ret_code_OK;
    cps_api_key_t key;
    cps_api_int_if_key_create(&key,false,0,0);

    if (cps_api_key_matches(&(param->keys[ix]),&key,false)==0) {
        if (cps_api_key_get_len(&param->keys[ix])<=CPS_OBJ_KEY_APP_INST_POS) {
            return get_all_interfaces(param->list);
        } else {
            uint32_t ifix = cps_api_key_element_at(&param->keys[ix],CPS_API_INT_IF_OBJ_KEY_IFIX);
            char if_name[HAL_IF_NAME_SZ+1];
            if (cps_api_interface_if_index_to_name(ifix,if_name,
                    sizeof(if_name))==NULL) {
                return cps_api_ret_code_OK;
            }
            rc = get_interface(if_name,param,&ix);
            //toss rc on a query unless it fails due to some sw err
        }
    }

    return rc;
}
static cps_api_return_code_t _cps_api_event_service_publish_msg(cps_api_event_service_handle_t handle,
        cps_api_object_t msg) {

    STD_ASSERT(msg!=NULL);
    STD_ASSERT(handle!=NULL);

    cps_api_key_t *_okey = cps_api_object_key(msg);

    if (cps_api_key_get_len(_okey) < CPS_OBJ_KEY_SUBCAT_POS) {
        //likely invalid message
        return cps_api_ret_code_ERR;
    }

    std_event_key_t key;
    cps_api_to_std_key(&key,_okey);

    cps_api_to_std_event_map_t *p = handle_to_data(handle);

    int retry = (int)p->retry;
    for (; retry > 0 ; --retry) {
        std_mutex_simple_lock_guard lg(&p->lock);
        if (!__connect_to_service(handle)) {
            std_usleep(MILLI_TO_MICRO(1));
            continue;
        }

        t_std_error rc = std_client_publish_msg_data(
                handle_to_std_handle(handle), &key,
                cps_api_object_array(msg),
                cps_api_object_to_array_len(msg));
        if (rc!=STD_ERR_OK) {
            __close_channel(handle);
        } else {
            return cps_api_ret_code_OK;
        }
    }
    return cps_api_ret_code_ERR;
}
cps_api_return_code_t cps_api_process_commit_request(cps_api_transaction_params_t *param, size_t ix) {
    cps_api_return_code_t rc = cps_api_ret_code_ERR;

    cps_api_object_t obj = cps_api_object_list_get(param->change_list,ix);
    cps_api_object_t pre = cps_api_object_list_get(param->prev,ix);
    if (obj==NULL) {
        EV_LOG(ERR,DSAPI,0,"CPS IPC","No Commit Object");
        return rc;
    }

    cps_api_channel_t handle;
    cps_api_key_t *key = cps_api_object_key(obj);

    char buff[CPS_API_KEY_STR_MAX];
    EV_LOG(TRACE,DSAPI,0, "CPS IPC", "Object for commit request: %s ",
                                    cps_api_key_name_print(key, buff, sizeof(buff)));


    if (!cps_api_get_handle(*key,handle)) {
        EV_LOG(ERR,DSAPI,0,"CPS IPC","No Service");
        return cps_api_ret_code_NO_SERVICE;
    }


    rc = cps_api_ret_code_ERR;

    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(handle,&rset);

    do {
        if (!cps_api_send_one_object(handle,cps_api_msg_o_COMMIT_CHANGE,obj)) {
            EV_LOG(ERR,DSAPI,0,"CPS IPC","Could not send COMMIT CHANGE ");
            break;
        }

        if (!cps_api_send_one_object(handle,cps_api_msg_o_COMMIT_PREV,pre)) {
            EV_LOG(ERR,DSAPI,0,"CPS IPC","Could not send COMMIT PREV ");
            break;
        }


        uint32_t op;
        size_t len;
        if (param->timeout > 0) {
            if ((rc=cps_api_timeout_wait(handle,&rset,param->timeout,"CPS-OP-TR"))!=cps_api_ret_code_OK) {
                EV_LOG(ERR,DSAPI,0,"CPS IPC","Transaction Response timed out ");
                break;
            }
        }
        rc = cps_api_ret_code_ERR;

        if (!cps_api_receive_header(handle,op,len)) {
            EV_LOG(ERR,DSAPI,0,"CPS IPC","Failed to read the receive header ");
            break;
        }


        if (op == cps_api_msg_o_COMMIT_OBJECT) {
            cps_api_object_guard og(cps_api_receive_object(handle,len));
            if (!og.valid()) {
                EV_LOG(ERR,DSAPI,0,"CPS IPC","Transaction response missing cur object..");
                break;
            }
            cps_api_object_clone(obj,og.get());

            if (!cps_api_receive_header(handle,op,len)) {
                EV_LOG(ERR,DSAPI,0,"CPS IPC","Failed to read the receive header for prev object ");
                break;
            }

            if (op!=cps_api_msg_o_COMMIT_OBJECT) {
                EV_LOG(ERR,DSAPI,0,"CPS IPC","Transaction response header incorrect for prev object" );
                break;
            }

            if (len>0) {
                cps_api_object_guard og(cps_api_receive_object(handle,len));
                if (!og.valid()) {
                    EV_LOG(ERR,DSAPI,0,"CPS IPC","Transaction response missing resp object..");
                    break;
                }
                obj = cps_api_object_list_get(param->prev,ix);

                if (obj==NULL) { //if there was no previous object passed by client override
                    if (cps_api_object_list_append(param->prev,og.get())) {
                        og.release();
                        rc = cps_api_ret_code_OK;
                    }
                } else {
                    //take the previous provided by the client if the key is valid
                    //assume that the data is valid too
                    if (cps_api_key_get_len(cps_api_object_key(og.get()))>0) {
                        cps_api_object_clone(obj,og.get());
                    }
                    rc = cps_api_ret_code_OK;
                }
            }
        }
        if (op == cps_api_msg_o_RETURN_CODE) {
            if (!cps_api_receive_data(handle,&rc,sizeof(rc))) break;
        }
    } while (0);

    cps_api_disconnect_owner(handle);

    return rc;
}
static void cps_api_to_std_key(std_event_key_t *key,const cps_api_key_t *cps_key) {
    memcpy(key->event_key,cps_api_key_elem_start((cps_api_key_t *)cps_key),
            cps_api_key_get_len((cps_api_key_t *)cps_key)* sizeof (key->event_key[0]));
    key->len = cps_api_key_get_len((cps_api_key_t *)cps_key);
}