void sys_mbox_free(sys_mbox_t mbox)
{
    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mbox;
    
    mem_free(queue->Storage());
    mem_free(queue);
}
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
{
    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mbox;

    // TODO
    // TODO
    // TODO
    // implement timeout
    OpaqueQueueNode* node = queue->Pop();

    if(node) 
    {
        *msg = node->payload;
        return 0;
    }
    else 
    {
        // schedule the tcp thread to run when the next timeout occurs
        // Any incoming data should retrigger the thread prior to timeout
        SOCKETS_RestartTcpIpProcessor(timeout * 1000);

        *msg = NULL; 
        return SYS_MBOX_EMPTY;    
    }

    // time needed
    // do not return SYS_ARCH_TIMEOUT or the system will wait forever
}
void sys_mbox_post(sys_mbox_t mbox, void *msg)
{
    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mbox;

    OpaqueQueueNode* node = NULL;
    
    if((node = queue->Push()) != NULL) 
    {
        //tcpip_msg* m = (tcpip_msg*)mem_malloc(sizeof(tcpip_msg));
        //api_msg* a = (api_msg*)mem_malloc(sizeof(api_msg));
        //sys_sem_t* s = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t));
        //if(!a || !m || !s) return;
        
        //memset(m,0,sizeof(tcpip_msg));
        //memset(a,0,sizeof(api_msg));
        //memset(s,0,sizeof(sys_sem_t));

        //memcpy(s,((tcpip_msg*)msg)->sem,sizeof(sys_sem_t));
        //memcpy(a,((tcpip_msg*)msg)->msg.apimsg,sizeof(api_msg));
        //memcpy(m,msg,sizeof(tcpip_msg));
        

        //m->msg.apimsg = a;
        
        //node->payload = m;
        
        node->payload = msg;
    }

    SOCKETS_RestartTcpIpProcessor(0);
}
void sys_mbox_free(sys_mbox_t* mbox)
{
    if(mbox == NULL || *mbox == NULL) { ASSERT(FALSE); return; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)*mbox;
    
    mem_free(queue->Storage());
    mem_free(queue);
}
sys_mbox_t sys_mbox_new(int size)
{    
    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mem_malloc(sizeof(Hal_Queue_UnknownSize<OpaqueQueueNode>));
    OpaqueQueueNode* memory = (OpaqueQueueNode*)mem_malloc(sizeof(OpaqueQueueNode) * size);
    memset(memory, 0, sizeof(OpaqueQueueNode) * size);
    queue->Initialize(memory, size);

    return queue;
}
void sys_mbox_post(sys_mbox_t* mbox, void *msg)
{
    if(mbox == NULL || *mbox == NULL) { ASSERT(FALSE); return; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)*mbox;

    OpaqueQueueNode* node = NULL;
    
    if((node = queue->Push()) != NULL) 
    {
        node->payload = msg;
    }

    SOCKETS_RestartTcpIpProcessor(0);
}
u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
{
    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mbox;

    OpaqueQueueNode* node = queue->Pop();

    if(node)
    {
        *msg = node->payload;
    }
    else
    {
        *msg = NULL;
        return SYS_MBOX_EMPTY;
    }

    return 0;    
}
err_t sys_mbox_trypost(sys_mbox_t* mbox, void *msg)
{
    if(mbox == NULL || *mbox == NULL) { ASSERT(FALSE); return ERR_ARG; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)*mbox;

    OpaqueQueueNode* node = queue->Push();

    if(node != NULL) 
    {
        node->payload = msg;

        SOCKETS_RestartTcpIpProcessor(0);

        return ERR_OK;    
    }

    return ERR_MEM;
}
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{    
    if(mbox == NULL) { ASSERT(FALSE); return ERR_ARG; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mem_malloc(sizeof(Hal_Queue_UnknownSize<OpaqueQueueNode>));
    OpaqueQueueNode* memory = (OpaqueQueueNode*)mem_malloc(sizeof(OpaqueQueueNode) * size);

    if(memory == NULL || queue == NULL)
    {
        if(queue != NULL) mem_free(queue);
            
        return ERR_MEM;
    }
    
    memset(memory, 0, sizeof(OpaqueQueueNode) * size);
    queue->Initialize(memory, size);

    *mbox = (sys_mbox_t)queue;
    
    return ERR_OK;
}
u32_t sys_arch_mbox_tryfetch(sys_mbox_t* mbox, void **msg)
{
    if(mbox == NULL || *mbox == NULL) { *msg = NULL; ASSERT(FALSE); return SYS_MBOX_EMPTY; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)*mbox;

    OpaqueQueueNode* node = queue->Pop();

    if(node)
    {
        *msg = node->payload;
        
        SOCKETS_RestartTcpIpProcessor(0);
    }
    else
    {
        *msg = NULL;
        return SYS_MBOX_EMPTY;
    }

    return 0;    
}
err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
{

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)mbox;

    OpaqueQueueNode* node = queue->Push();

    if(node != NULL) {
        
        //tcpip_msg* m = (tcpip_msg*)mem_malloc(sizeof(tcpip_msg));
        //memset(m,0,sizeof(tcpip_msg));
        //memcpy(m,msg,sizeof(tcpip_msg));
        //node->payload = m;

        node->payload = msg;

        return ERR_OK;    
    }

    SOCKETS_RestartTcpIpProcessor(0);

    return ERR_MEM;
}
u32_t sys_arch_mbox_fetch(sys_mbox_t* mbox, void **msg, u32_t timeout)
{
    if(mbox == NULL || *mbox == NULL) { ASSERT(FALSE); return SYS_ARCH_TIMEOUT; }

    Hal_Queue_UnknownSize<OpaqueQueueNode>* queue = (Hal_Queue_UnknownSize<OpaqueQueueNode>*)*mbox;
    bool didTimeout = false;

    if(timeout == 0) 
    {
        timeout = 0xFFFFFFFF;
    }

    INT64 now = ::HAL_Time_CurrentTime();
    INT64 elapsed = now + (timeout * 10000);
    
    while(elapsed > ::HAL_Time_CurrentTime() || timeout == 1) 
    {
        OpaqueQueueNode* node = queue->Pop();
        
        if(node) 
        {
            *msg = node->payload;

            Events_Set(SYSTEM_EVENT_FLAG_NETWORK);            

            SOCKETS_RestartTcpIpProcessor(0);
            
            return 0;
        }
        else if(timeout == 1)
        {
            break;
        }
        
        if(INTERRUPTS_ENABLED_STATE())
        {
            if(Events_WaitForEvents(SYSTEM_EVENT_FLAG_NETWORK, timeout))
            {
                Events_Clear(SYSTEM_EVENT_FLAG_NETWORK);
                
                INT64 curTime = ::HAL_Time_CurrentTime();

                if(elapsed > curTime)
                {
                    timeout -= (elapsed - HAL_Time_CurrentTime()) / 10000;
                }
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    if(timeout != 1)
    {
        Events_Set(SYSTEM_EVENT_FLAG_NETWORK);            
    }
    else
    {
        didTimeout = true;
    }

    *msg = NULL; 
    return didTimeout ? SYS_ARCH_TIMEOUT : SYS_MBOX_EMPTY;    
}