#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>




#include "osp.h"


/*
    Dep must be Power of 2 
*/
int32_t osp_create_softque(Osp_SoftQue *que, int32_t Dep, char *name)
{
    static int32_t id = 0;
    void *p;
    
    if (!OSP_IS_POWEOF2(Dep))
    {
        return -1;
    }
    p = osp_semsm_create(&que->mutex);
    if (NULL == p)
    {
        return -1;
    }
    que->Id = id++;
    strcpy(que->Name, name);
    que->EnIdx = 0;
    que->DeIdx = 0;
    que->Dep = Dep;
    que->CurNum = 0;
    que->EnCnt = 0;
    que->DeCnt = 0;
    que->FullCnt = 0;
    que->EmptyCnt = 0;
    que->Mask = que->Dep-1;    

    p = osp_semss_create(&que->sem);
    if (NULL == p)
    {
        return -1;
    }
   
    return que->Id;
}


int32_t osp_soft_que_enque(uint64_t value, Osp_SoftQue *que, int32_t IsNeedWake)
{

    int32_t CurNum;

    osp_sem_take(&que->mutex, -1);
    CurNum = que->CurNum;
    if (CurNum == que->Dep)/*full */
    {
        que->FullCnt ++; 
        osp_sem_give(&que->mutex);
        return -1;        
    }
    que->Buf[que->EnIdx] = value;
    que->EnIdx = (que->EnIdx + 1) & (que->Mask);
    osp_atomic_inc((int32_t *)&que->CurNum);
    que->EnCnt ++;
    osp_sem_give(&que->mutex);

    if (IsNeedWake)
    {
        osp_sem_give(&que->sem);
    }
    return 0;


}

int32_t osp_softque_deque(uint64_t *pvalue, Osp_SoftQue *que, int32_t IsBlock)
{
    int32_t CurNum;
    
    if (IsBlock)
    {
        osp_sem_take(&que->sem,-1);
    }
    
    osp_sem_take(&que->mutex, -1);
    
    CurNum = que->CurNum;
    if (CurNum == 0)/*empty*/
    {
        que->EmptyCnt ++;
        osp_sem_give(&que->mutex);
        return -1;
    } 
    *pvalue = que->Buf[que->DeIdx];
    que->DeIdx = (que->DeIdx + 1) & que->Mask;
    osp_atomic_dec((int32_t *)&que->CurNum);
    que->DeCnt ++;
    osp_sem_give(&que->mutex);
    
    return 0;               

}

int32_t osp_softque_dequetry(uint64_t *pvalue, Osp_SoftQue *que)
{
    int32_t ret;
    int32_t CurNum;

    
    ret = osp_sem_taketry(&que->sem);
    if (0 != ret)
    {
        return ret;
    }

    CurNum = que->CurNum;
    if (CurNum == 0)/*empty*/
    {
        que->EmptyCnt ++;

        return -1;
    } 
    *pvalue=que->Buf[que->DeIdx];
    que->DeIdx = (que->DeIdx + 1) & que->Mask;
    osp_atomic_dec((int32_t *)&que->CurNum);
    que->DeCnt ++;

    return 0;               

}

int32_t osp_softque_dequeTimeOut(uint64_t *pvalue, Osp_SoftQue *que, uint32_t timeout)
{
    int32_t ret;
    int32_t CurNum;

    ret = osp_sem_take(&que->sem, timeout);
    if (0 != ret)
    {
        return ret;
    }

    CurNum = que->CurNum;
    if (CurNum == 0)/*empty*/
    {
        que->EmptyCnt ++;

        return -1;
    } 
    *pvalue = que->Buf[que->DeIdx];
    que->DeIdx = (que->DeIdx + 1)&que->Mask;
    osp_atomic_dec((int32_t*)&que->CurNum);
    que->DeCnt ++;

    return 0;               

}

int32_t osp_soft_que_is_vaild(Osp_SoftQue *que)
{
    return ((que->Dep) != 0);
}

int32_t osp_get_soft_que_desc(char *pbuf)
{
    int32_t len = 0;
    osp_assert(pbuf != NULL);
    
    len = sprintf(pbuf, "%-8s%-24s%-12s%-12s%-12s%-12s%-12s%-12s%-12s%-12s%-12s\n", "Id", "Name", "EnIdx",
        "DeIdx", "Dep", "CurNum", "EnCnt", "DeCnt", "FullCnt", "EmptyCnt", "Mask");    

    return len;
}

int32_t osp_get_soft_que_info(Osp_SoftQue *que, char *pbuf)
{
    int32_t len = 0;

    osp_assert(pbuf != NULL);    
    
    if (osp_soft_que_is_vaild(que))
    {


        len += sprintf(pbuf + len, "%-8d%-24s%-12d%-12d%-12d%-12d%-12lu%-12lu%-12lu%-12lu%-12d\n",
            que->Id, que->Name,
            que->EnIdx,
            que->DeIdx,    
            que->Dep,
            que->CurNum, 
            que->EnCnt,
            que->DeCnt,
            que->FullCnt,
            que->EmptyCnt,
            que->Mask); 
    };
    return len;

}







