/*******************************************************************************
API: alarmClockFinalize

Description : Stops the timer driving the clock and delete the timer

Arguments In: 
    none
Arguments Out:
    none
Return Value:
    none
*******************************************************************************/
void alarmClockFinalize ( void )
{
    ClRcT                rc = CL_OK;

    /* Stop the clock
     */
    alarmClockStop();

    rc =  clTimerDelete(timerHandle);
    if (rc != CL_OK)
    {
        alarmClockLogWrite(CL_LOG_SEV_ERROR,
                    "alarmClockFinalize(pid=%d): Timer delete failed: 0x%x\n", 
                    getpid(), rc);
    }

    rc = clTimerFinalize();
    if (rc != CL_OK)
    {
        alarmClockLogWrite(CL_LOG_SEV_CRITICAL,
                    "alarmClockFinalize(pid=%d): Timer finalize failed:0x%x\n", 
                    getpid(), rc);
        return;
    }

}
void clMsgQueueFree(ClMsgQueueInfoT *pQInfo)
{
    ClRcT rc = CL_OK;
    SaNameT qName = {strlen("--Unknow--"), "--Unknow--"};
    ClUint32T i;

    CL_OSAL_MUTEX_LOCK(&pQInfo->qLock);

    (void)clMsgUnblockThreadsOfQueue(pQInfo);

    if(pQInfo->unlinkFlag == CL_FALSE && pQInfo->pQueueEntry != NULL)
    {
        saNameCopy(&qName, &pQInfo->pQueueEntry->qName);
    }
    
    if(pQInfo->timerHandle != 0)
    {
        rc = clTimerDelete(&pQInfo->timerHandle);
        if(rc != CL_OK)
            clLogError("QUE", "FREE", "Failed to delete [%.*s]'s timer handle. error code [0x%x].", 
                       qName.length, qName.value, rc);
    }
    
    clMsgQueueEmpty(pQInfo);

    for(i = 0; i < CL_MSG_QUEUE_PRIORITIES ; i++)
    {
        rc = clCntDelete(pQInfo->pPriorityContainer[i]);
        if(rc != CL_OK)
            clLogError("QUE", "FREE", "Failed to delete the [%.*s]'s [%d] priority container. error code [0x%x].", 
                       qName.length, qName.value, i, rc);
        else
            pQInfo->pPriorityContainer[i] = 0;
    }

    rc = clOsalCondDelete(pQInfo->qCondVar);
    if(rc != CL_OK)
        clLogError("QUE",  "FREE", "Failed to delete the [%.*s]'s condtional variable. error code [0x%x].",
                   qName.length, qName.value, rc);

    pQInfo->qCondVar = 0;

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

    rc = clOsalMutexDestroy(&pQInfo->qLock);
    if(rc != CL_OK)
        clLogError("QUE",  "FREE", "Failed to delete the [%.*s]'s lock. error code [0x%x].",
                   qName.length, qName.value, rc);

    clLogDebug("QUE", "FREE", "Freed the queue [%.*s].", qName.length, qName.value);

    return;
}
static ClRcT clMsgEventInitTimerThread(void *pParam)
{
    ClRcT rc = CL_OK;

    rc = clMsgEventInitialize();
    if(rc != CL_OK)
    {
        clLogError("FIN", "BLOCK", "Failed to initialize event client. error code [0x%x].", rc);
        if(gClMsgInit && gMsgEvtTimerHdl)
            clTimerStart(gMsgEvtTimerHdl); /*restart the timer again*/
        goto error_out;
    }

    clLogDebug("FIN", "BLOCK", "Event library is initialized.");

    rc = clTimerDelete(&gMsgEvtTimerHdl);
    if(rc != CL_OK)
        clLogError("FIN", "BLOCK", "Failed to delete event timer. error code [0x%x].", rc);

error_out:
    return rc;
}
static ClRcT
tsActiveTimersQueueDestroy (void)
{
    ClRcT returnCode = CL_ERR_INVALID_HANDLE;
    TsTimer_t* pUserTimer = NULL;
    TsTimer_t* pNextUserTimer = NULL;

    CL_FUNC_ENTER();
    returnCode = clOsalMutexLock (gActiveTimerQueue.timerMutex);

    if (returnCode != CL_OK) {
        CL_FUNC_EXIT();
        return (returnCode);
    }

    pNextUserTimer = NULL;

    for (pUserTimer = gActiveTimerQueue.pFirstTimer;
            pUserTimer != NULL;
            pUserTimer = pNextUserTimer) {

        pNextUserTimer = pUserTimer->pNextActiveTimer;

        returnCode = clOsalMutexUnlock (gActiveTimerQueue.timerMutex);

        returnCode = clTimerDelete ((ClTimerHandleT*)&pUserTimer);

        returnCode = clOsalMutexLock (gActiveTimerQueue.timerMutex);
    }

    gActiveTimerQueue.timerServiceInitialized = 0;

    returnCode = clOsalMutexUnlock (gActiveTimerQueue.timerMutex);

    returnCode = clOsalMutexDelete (gActiveTimerQueue.timerMutex);

    CL_FUNC_EXIT();
    return (returnCode);
}
ClRcT clMsgQueueOpen(SaMsgQueueHandleT qHandle,
        SaMsgQueueOpenFlagsT openFlags)
{
    ClRcT rc = CL_OK, retCode;
    ClMsgQueueInfoT *pQInfo;

    CL_OSAL_MUTEX_LOCK(&gClLocalQsLock);
    rc = clHandleCheckout(gClMsgQDatabase, qHandle, (void**)&pQInfo);
    if(rc != CL_OK)
    {
        CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);
        clLogError("QUE", "OPN", "Failed to checkout a queue handle. error code [0x%x].", rc);
        goto error_out;
    }

    CL_OSAL_MUTEX_LOCK(&pQInfo->qLock);
    CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);

    if(pQInfo->timerHandle)
        clTimerDelete(&pQInfo->timerHandle);

    if(openFlags & SA_MSG_QUEUE_EMPTY)
        clMsgQueueEmpty(pQInfo);

    pQInfo->openFlags = openFlags;
    pQInfo->state = CL_MSG_QUEUE_OPEN;
    pQInfo->closeTime = 0;

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

    retCode = clHandleCheckin(gClMsgQDatabase, qHandle);
    if(retCode != CL_OK)
        clLogError("QUE", "OPN", "Failed to check-in queue handle. error code [0x%x].", retCode);

error_out:
    return rc;
}
static ClRcT
clLogFlusherCookieHandleCreate(ClUint32T       numRecords,
                               ClTimerHandleT  *phTimer, 
                               ClHandleT       *phFlusher)
{
    ClRcT     rc   = CL_OK;
    ClLogFlushCookieT  *pFlushCookie = NULL;
    ClLogSvrEoDataT    *pSvrEoEntry  = NULL;
    ClTimerTimeOutT    timeout       = {0, 8000L};
    ClHandleT          *pTimerArg    = NULL;

    CL_LOG_DEBUG_TRACE(("Enter"));

    rc = clLogSvrEoEntryGet(&pSvrEoEntry, NULL);
    if(  CL_OK != rc )
    {
        return rc;
    }    
    if( CL_FALSE == pSvrEoEntry->logInit )
    {
        clLogError("LOG", "FLS", "Log Service has terminated...");
        return CL_OK;
    }
    CL_LOG_DEBUG_TRACE(("hFlusherDB: %p ", (ClPtrT) pSvrEoEntry->hFlusherDB));

    rc = clHandleCreate(pSvrEoEntry->hFlusherDB, sizeof(ClLogFlushCookieT), 
                        phFlusher);
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "clHandleCreate(): rc[0x %x]", rc);
        return rc;
    }    
    pTimerArg = (ClHandleT*) clHeapCalloc(1, sizeof(ClHandleT));

    if( NULL == pTimerArg )
    {
    	clLogError("LOG", "FLS", "clHeapCalloc() : rc[0x %x]", rc);
        CL_LOG_CLEANUP(clHandleDestroy(pSvrEoEntry->hFlusherDB, *phFlusher),
                       CL_OK);
        return CL_LOG_RC(CL_ERR_NO_MEMORY);
    }

    *pTimerArg = *phFlusher;

    rc = clTimerCreateAndStart(timeout, CL_TIMER_ONE_SHOT, 
                               CL_TIMER_SEPARATE_CONTEXT, 
                               clLogFlusherTimerCallback,
                               (ClPtrT)(ClWordT) pTimerArg, phTimer);
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "clTimerCreate(): rc[0x %x]", rc);
        CL_LOG_CLEANUP(clHandleDestroy(pSvrEoEntry->hFlusherDB, *phFlusher),
                       CL_OK);
        clHeapFree(pTimerArg);
        return rc;
    }    

    rc = clHandleCheckout(pSvrEoEntry->hFlusherDB, *phFlusher, 
            (void **) &pFlushCookie);
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "clHandleCheckout(): rc[0x %x]", rc);
        CL_LOG_CLEANUP(clTimerDelete(phTimer), CL_OK);
        CL_LOG_CLEANUP(clHandleDestroy(pSvrEoEntry->hFlusherDB, *phFlusher),
                CL_OK);
        return rc;
    }    
    pFlushCookie->numRecords = numRecords;
    pFlushCookie->hTimer     = *phTimer;
    rc = clHandleCheckin(pSvrEoEntry->hFlusherDB, *phFlusher);
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "clHandleCheckin(): rc[0x %x]", rc);
        CL_LOG_CLEANUP(clTimerDelete(phTimer), CL_OK);
        CL_LOG_CLEANUP(clHandleDestroy(pSvrEoEntry->hFlusherDB, *phFlusher),
                CL_OK);
    }    

    CL_LOG_DEBUG_TRACE(("Exit"));
    return rc;
}    
ClRcT
clLogFlusherCookieHandleDestroy(ClHandleT  hFlusher, 
                                ClBoolT    timerExpired)
{
    ClRcT     rc   = CL_OK;
    ClLogFlushCookieT  *pFlushCookie = NULL;
    ClLogSvrEoDataT    *pSvrEoEntry  = NULL;

    CL_LOG_DEBUG_TRACE(("Enter"));

    /*
     * FIXME:
     * Unable to flush this set of records but will this be true in
     * future also, DON'T know
     * Also need to reset the startAck otherwise it will not  enter
     * the cond_wait
     */
    rc = clLogSvrEoEntryGet(&pSvrEoEntry, NULL);
    if(  CL_OK != rc )
    {
        return rc;
    }

    rc = clHandleValidate(pSvrEoEntry->hFlusherDB, hFlusher);
    if( CL_OK != rc )
    {
        return rc;/*Flusher handle has already been destroyed*/
    }

    rc = clHandleCheckout(pSvrEoEntry->hFlusherDB, hFlusher, 
                          (void **) &pFlushCookie);

    if( (CL_TRUE == timerExpired) && (CL_OK != rc) )
    {
        clLogTrace("LOG", "FLS", "Timer has already destroyed the handle");
        return CL_OK;
    }    
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "Flusher handle checkout failed : "
                   "rc[0x %x]", rc);
        return rc;
    }

    if( CL_FALSE == timerExpired )
    {
        clLogWarning("LOG", "FLS", "Didn't get ack for %d records",
                     pFlushCookie->numRecords);
    }    
    CL_LOG_CLEANUP(clTimerDelete(&pFlushCookie->hTimer), CL_OK);

    rc = clHandleCheckin(pSvrEoEntry->hFlusherDB, hFlusher);
    if( CL_OK != rc )
    {
        clLogError("LOG", "FLS", "clHandleCheckin(): rc[0x %x]", rc);
    }    
    CL_LOG_CLEANUP(clHandleDestroy(pSvrEoEntry->hFlusherDB, hFlusher), CL_OK);

    CL_LOG_DEBUG_TRACE(("Exit"));
    return rc;
}