/*-----------------------------------------------------------------------------
 * Initialize API
 *---------------------------------------------------------------------------*/
ClRcT clGmsInitialize(
    CL_OUT   ClGmsHandleT* const    gmsHandle,
    CL_IN    const ClGmsCallbacksT* const gmsCallbacks,
    CL_INOUT ClVersionT*   const      version)
{
    struct gms_instance *gms_instance_ptr = NULL;
    ClRcT rc = CL_OK;
    ClGmsClientInitRequestT req = {{0}};
    ClGmsClientInitResponseT *res = NULL;

    /* Step 0: Check readiness of library */

    rc = check_lib_init();
    if (rc != CL_OK)
    {
        return CL_GMS_RC(CL_ERR_NOT_INITIALIZED);
    }
    
    /* Step 1: Checking inputs */
    CL_ASSERT(gmsHandle != NULL);
    CL_ASSERT(version != NULL);
#if 0    
    if ((gmsHandle == NULL) || (version == NULL))
    {
        return CL_GMS_RC(CL_ERR_NULL_POINTER);
    }
#endif    

    *gmsHandle = CL_HANDLE_INVALID_VALUE;

    /* Step 2: Verifying version match */
    
    rc = clVersionVerify (&version_database, version);
    if (rc != CL_OK)
    {
        return CL_GMS_RC(CL_ERR_VERSION_MISMATCH); 
    }

    /* Step 3: Obtain unique handle */
    rc = clHandleCreate(gmsHandleDb, sizeof(struct gms_instance), gmsHandle);
    CL_ASSERT(rc == CL_OK);
#if 0    
    if (rc != CL_OK)
    {
        rc = CL_GMS_RC(CL_ERR_NO_RESOURCE);
        goto error_no_destroy;
    }
#endif    
    clLogInfo("GMS","CLT","GMS client handle is [%llX]",*gmsHandle);
    
    rc = clHandleCheckout(gmsHandleDb, *gmsHandle, (void **)&gms_instance_ptr);
    CL_ASSERT(rc == CL_OK);
    CL_ASSERT(gms_instance_ptr != NULL);
#if 0    
    if(rc != CL_OK)
    {
        goto error_destroy;
    }
    if (gms_instance_ptr == NULL)
    {
        clHandleCheckin(gmsHandleDb, *gmsHandle);
        rc = CL_GMS_RC(CL_ERR_NULL_POINTER);
        goto error_destroy;
    }
#endif

    rc = clGmsMutexCreate(&gms_instance_ptr->response_mutex);
    CL_ASSERT(rc == CL_OK);
#if 0    
    if(rc != CL_OK)
    {
        clHandleCheckin(gmsHandleDb, *gmsHandle);
        goto error_destroy;
    }
#endif

    /* Step 4: Negotiate version with the server */
    req.clientVersion.releaseCode = version->releaseCode;
    req.clientVersion.majorVersion= version->majorVersion;
    req.clientVersion.minorVersion= version->minorVersion;

    rc = cl_gms_clientlib_initialize_rmd(&req, 0x0 ,&res );
    if(rc != CL_OK )
    {
        clLogError(GEN,NA,"cl_gms_clientlib_initialize_rmd failed with rc:0x%x ",rc);
        clGmsMutexDelete(gms_instance_ptr->response_mutex);
        gms_instance_ptr->response_mutex = 0;
        clHandleCheckin(gmsHandleDb, *gmsHandle);
        rc = CL_GMS_RC(rc);
        goto error_destroy;
    }
    
    /* Step 5: Initialize instance entry */
    if (gmsCallbacks) 
    {
        memcpy(&gms_instance_ptr->callbacks, gmsCallbacks, sizeof(ClGmsCallbacksT));
    } 
    else 
    {
        memset(&gms_instance_ptr->callbacks, 0, sizeof(ClGmsCallbacksT));
    }

    memset(&gms_instance_ptr->cluster_notification_buffer, 0, sizeof(ClGmsClusterNotificationBufferT));
    memset(&gms_instance_ptr->group_notification_buffer, 0, sizeof(ClGmsGroupNotificationBufferT));

    /* Step 6: Decrement handle use count and return */
    if ((clHandleCheckin(gmsHandleDb, *gmsHandle)) != CL_OK)
    {
        clLogError(GEN,DB, "\nclHandleCheckin failed");
    }
    clHeapFree(res);
    return CL_OK;

    error_destroy:
    clHandleDestroy(gmsHandleDb, *gmsHandle);
    *gmsHandle = CL_HANDLE_INVALID_VALUE;

    //error_no_destroy:
    return rc;
}
/*  FIXME:
 */
ClRcT   _clGmsDbCreate(
           CL_IN        ClGmsDbT*  const      gmsDb,
           CL_OUT       ClGmsDbT** const      gmsElement)
{
    ClRcT       rc = CL_OK;
    ClUint32T   i = 0;
    ClUint64T   cntIndex = 0;

    if ((gmsDb == NULL) || (gmsElement == NULL))
    {
        return CL_GMS_RC(CL_ERR_NULL_POINTER);
    }

    for(i = 0; i < gmsGlobalInfo.config.noOfGroups; i++)
    {
        if (gmsDb[i].view.isActive == CL_FALSE)
        {
            cntIndex = i;
            break;
        }
    }
    if (i == gmsGlobalInfo.config.noOfGroups)
    {
        return CL_ERR_OUT_OF_RANGE;
    }

    /* Current view database. Holds cluster and groups info */


    rc = clCntHashtblCreate(
                      viewDbParams.htbleParams.gmsNumOfBuckets, 
                      viewDbParams.htbleParams.gmsHashKeyCompareCallback, 
                      viewDbParams.htbleParams.gmsHashCallback,
                      viewDbParams.htbleParams.gmsHashDeleteCallback,
                      viewDbParams.htbleParams.gmsHashDestroyCallback,
                      CL_CNT_UNIQUE_KEY, 
                      &gmsDb[cntIndex].htbl[CL_GMS_CURRENT_VIEW]);

    if (rc != CL_OK)
    {
        return rc;
    }

    /* Cluster joined/left view list. Used for tracking */

    rc = clCntHashtblCreate(
                      viewDbParams.htbleParams.gmsNumOfBuckets, 
                      viewDbParams.htbleParams.gmsHashKeyCompareCallback, 
                      viewDbParams.htbleParams.gmsHashCallback,
                      viewDbParams.htbleParams.gmsHashDeleteCallback,
                      viewDbParams.htbleParams.gmsHashDestroyCallback,
                      CL_CNT_UNIQUE_KEY, 
                      &gmsDb[cntIndex].htbl[CL_GMS_JOIN_LEFT_VIEW]);

    if (rc != CL_OK)
    {
        return rc;
    }

    /* Track hash table create */

    rc = clCntHashtblCreate(
                viewDbParams.trackDbParams->htbleParams.gmsNumOfBuckets, 
                viewDbParams.trackDbParams->htbleParams.
                                                 gmsHashKeyCompareCallback, 
                viewDbParams.trackDbParams->htbleParams.gmsHashCallback,
                viewDbParams.trackDbParams->htbleParams.
                                                     gmsHashDeleteCallback,
                viewDbParams.trackDbParams->htbleParams.
                                                        gmsHashDestroyCallback,
                CL_CNT_UNIQUE_KEY, 
                &gmsDb[cntIndex].htbl[CL_GMS_TRACK]);

    if (rc != CL_OK)
    {
        return rc;
    }

    clGmsMutexCreate(&gmsDb[cntIndex].viewMutex);


    clGmsMutexCreate(&gmsDb[cntIndex].trackMutex);


    gmsDb[cntIndex].view.isActive = CL_TRUE;

    clLog(DBG,GEN,DB,
            "Created View and Track DB for GroupId [%lld]",cntIndex);

    *gmsElement = &gmsDb[cntIndex++];

    return rc;
}