#include "hook.h"
#include "bmc_main.h"
#include <semaphore.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
extern sem_t sem_QUEUE;

#define WAIT_QUEUE do{ sem_wait(&sem_QUEUE);	}while(0);	
#define POST_QUEUE do{ sem_post(&sem_QUEUE);	}while(0);

//#define WAIT_QUEUE
//#define POST_QUEUE

/**
 ** @fn AddToQueue
 ** @brief Post a buffer to the destination task.
 ** @param pBuf   - Buffer to be posted.
 ** @param Queuepath    - Queuepath to post this buffer to.
 ** @return   0 if success, -1 if failed.
 ***/
int
AddToQueue (void* pBuf, INT8S *Queuepath,INT32U Size)
{
    int     Err,i=0; 

    for(i=0;i< MAX_IPMI_IFCQ;i++)
    {
         if(strcmp(g_IPMIIfcQueue[i].IfcName,Queuepath) == 0)
         {
//            LOCK_QUEUE   (g_IPMIIfcQueue[i].IfcQ);
            OS_ADD_TO_Q  (pBuf, Size, g_IPMIIfcQueue[i].IfcQ,&Err);
//            UNLOCK_QUEUE (g_IPMIIfcQueue[i].IfcQ);

            if ((Err == -1) || (Err != Size))
            {
                printf ("Message.c : Post To Queue %x %s\n",errno, strerror(errno));
                return -1;
            }             
            break;
         }
    }    

    if(i == MAX_IPMI_IFCQ)
    {
        return -1;
    }
    return 0;
}


/**
 ** @fn AddQueue
 ** @brief Adds the Queue to the common Queue Handle structure
 ** @param Queuepath - Queue Path
 ** @return Return 0
 ***/
int AddQueue(INT8S *Queuepath)
{
    int i=0;
    struct  stat buf;
    WAIT_QUEUE
    if(stat(Queuepath,&buf) == 0)
    {
        if(unlink(Queuepath) == -1)
        {
            printf("Failed to unlink %s \n",Queuepath);
        }
    }

    for(i=0; i< MAX_IPMI_IFCQ;i++)
    {
        if(strncmp(g_IPMIIfcQueue[i].IfcName,"",1) == 0)
        {
            strcpy(g_IPMIIfcQueue[i].IfcName,Queuepath);
            break;
        }
    }
    POST_QUEUE
    return 0;
}

/**
 ** @fn GetQueueHandle
 ** @brief Gets the Queue Handle from the Common Queue Handle Structure
 ** @param Queuepath - Queue Path
 ** @param IfcQ  Handle for the needed Queue
 ** @return Return 0
 ***/
int GetQueueHandle(INT8S *Queuepath,HQueue_T *IfcQ)
{
    int i=0;
    WAIT_QUEUE
    for(i=0;i<MAX_IPMI_IFCQ;i++)
    {
        if(strcmp(g_IPMIIfcQueue[i].IfcName,Queuepath) == 0)
        {
            *IfcQ = g_IPMIIfcQueue[i].IfcQ;
            break;
        }
    }
    POST_QUEUE
    if(i == MAX_IPMI_IFCQ)
    {
        return -1;
    }    
    return 0;
}


/**
 * @fn GetQueue
 * @brief Gets the Queue Handle from the Common
 *            Queue Handle Structure
 * @param Queuepath - Queue Path
 * @return Return 0
**/
int GetQueue(INT8S *Queuepath,int flags)
{
    int i=0;
    WAIT_QUEUE
    for(i=0;i<MAX_IPMI_IFCQ;i++)
    {
        if(strcmp(g_IPMIIfcQueue[i].IfcName,Queuepath) == 0)
        {
            g_IPMIIfcQueue[i].IfcQ = open (Queuepath, flags);
            if(g_IPMIIfcQueue[i].IfcQ == -1)
            {
                printf ("Error opening named pipe %s\n",Queuepath);
                perror("");
            }
            break;
        }
    }
    POST_QUEUE
    if(i == MAX_IPMI_IFCQ)
    {
        return -1;
    }
    
    return 0;
}




/**
 ** @fn PostMsg
 ** @brief Post a message to the destination task.
 ** @param MsgPkt   - Message to be posted.
 ** @param Queue	   - Queue to post this message to.
 ** @return   0 if success, -1 if failed.
 ***/
int
PostMsg (MsgPkt_T* pMsgPkt, INT8S *Queuepath)
{
    int     Err,i=0;
    INT16U  Size;

    Size    = sizeof (MsgPkt_T) - MSG_PAYLOAD_SIZE + pMsgPkt->Size;
//	printf("Queuepath is %s\n",Queuepath);
	for(i=0;i<MAX_IPMI_IFCQ;i++)
	{
		if(strstr(g_IPMIIfcQueue[i].IfcName,Queuepath) != NULL)
		{
			//printf("_IPMIIfcQueue[i].IfcName is %s\n",g_IPMIIfcQueue[i].IfcName);
			//printf("g_IPMIIfcQueue[i].IfcQ is ");
			//printf("%d\n",g_IPMIIfcQueue[i].IfcQ);
			OS_ADD_TO_Q  (pMsgPkt, Size, g_IPMIIfcQueue[i].IfcQ, &Err);
			if ((Err == -1) || (Err != Size))
			{
				printf ("Message.c : PostMsg %x %s\n",errno, strerror(errno));
				return -1;
			}             
			break;
		}
	}

    if(i == MAX_IPMI_IFCQ)
    {
        return -1;
    }

    return 0;
}

/**
 * @fn GetMsg
 * @brief Gets the message posted to this task.
 * @param MsgPkt   - Pointer to the buffer to hold the message packet.
 * @param Queue    - Queue to fetch the message from.
 * @param Timeout    - Number of seconds to wait.
 * 
 * WAIT_NONE       - If the function has to return immediately.
 * WAIT_INFINITE   - If the function has to wait infinitely.
 * NOTE :
 * @return   0 if success, -1 if failed.
**/
int
GetMsg (_FAR_ MsgPkt_T* pMsgPkt, INT8S *Queuepath, INT16S Timeout)
{
    int     Err,i=0;
    int     Size;

    WAIT_QUEUE
    for(i=0;i<MAX_IPMI_IFCQ;i++)
    {
        if(strcmp(g_IPMIIfcQueue[i].IfcName,Queuepath) == 0)
        {
            break;
        }
    }
    POST_QUEUE
    
    if(i == MAX_IPMI_IFCQ)
    {
        printf("Message.c : Unable to Get Queue : %s",Queuepath);
        return -1;
    }
    
    /* check for limited wait time */
    if (Timeout >= 0)
    {
        struct timeval      Timeval;
        fd_set              fdRead;
        int                 n, RetVal;

        FD_ZERO (&fdRead);
        FD_SET (g_IPMIIfcQueue[i].IfcQ, &fdRead);
        n = g_IPMIIfcQueue[i].IfcQ + 1;

        Timeval.tv_sec  = Timeout;
        Timeval.tv_usec = 0;
        RetVal = select (n, &fdRead, NULL, NULL, &Timeval);
        if (-1 == RetVal)
        {
            printf ("Message.c : Error waiting on Queue [Error : %s, Queue : %s, Timeout : %d]\n", 
                    strerror (errno), g_IPMIIfcQueue[i].IfcName, Timeout);
            return -1;
        }
        else if (0 == RetVal)
        {
            return -2;
        }
    }

    /* Get the header first*/
    Size = sizeof (MsgPkt_T) - MSG_PAYLOAD_SIZE;
    OS_GET_FROM_Q (pMsgPkt, Size, g_IPMIIfcQueue[i].IfcQ, WAIT_INFINITE, &Err);
    if (Err == -1)
    {
        IPMI_WARNING ("Message.c : GetMsg %s\n",strerror(errno));
        return -1;
    }

    /* Get the payload data */
    Size = pMsgPkt->Size;
    OS_GET_FROM_Q (pMsgPkt->Data, Size, g_IPMIIfcQueue[i].IfcQ, WAIT_INFINITE, &Err);
    if (Err == -1)
    {
        IPMI_WARNING ("Message.c : GetMsg %s\n",strerror(errno));
        return -1;
    }

    return 0;
}
