//
// Copyright (C) 2006-2012 SIPez LLC.  All rights reserved.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <assert.h>

// APPLICATION INCLUDES
#include "os/OsServerTask.h"
#include "os/OsMsg.h"

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
const int OsServerTask::DEF_MAX_MSGS = OsMsgQ::DEF_MAX_MSGS;

// STATIC VARIABLE INITIALIZATIONS

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
OsServerTask::OsServerTask(const UtlString& name,
                           void* pArg,
                           const int maxRequestQMsgs,
                           const int priority,
                           const int options,
                           const int stackSize)
:  OsTask(name, pArg, priority, options, stackSize),
   mIncomingQ(maxRequestQMsgs, OsMsgQ::DEF_MAX_MSG_LEN, OsMsgQ::Q_PRIORITY)

   // other than initialization, no work required
{
/*
   // Only useful when debugging queue problems -- very small case and doesn't
   // warrant spam in general case -- my opinion anyways.

   if (OsSysLog::willLog(FAC_KERNEL, PRI_INFO))
   {

           OsSysLog::add(FAC_KERNEL, PRI_INFO,
                                "OsServerTask::OsServerTask %s queue: %p queue limit: %d",
                                mName.data(), &mIncomingQ, maxRequestQMsgs);
   }
*/
}

// Destructor
// As part of destroying the task, flush all messages from the incoming
// OsMsgQ.
OsServerTask::~OsServerTask()
{
   waitUntilShutDown(20000);  // upto 20 seconds

   mIncomingQ.flush();    // dispose of any messages in the request queue
}

/* ============================ MANIPULATORS ============================== */

// Handle an incoming message.
// This is the message handler of last resort. It should only be called when
// the handleMessage() method in the derived class returns FALSE (indicating
// that the message has not been handled.
UtlBoolean OsServerTask::handleMessage(OsMsg& rMsg)
{
   UtlBoolean handled;

   handled = FALSE;

   switch (rMsg.getMsgType())
   {
   case OsMsg::OS_SHUTDOWN:
      handled = TRUE;
      break;
   default:
      osPrintf(
         "OsServerTask::handleMessage(): msg type is %d.%d, not OS_SHUTDOWN\n",
         rMsg.getMsgType(), rMsg.getMsgSubType());
   //   assert(FALSE);
      break;
   }

   return handled;
}

// Post a message to this task.
// Return the result of the message send operation.
OsStatus OsServerTask::postMessage(const OsMsg& rMsg, const OsTime& rTimeout,
                                   UtlBoolean sentFromISR)
{
   OsStatus res;

   if (sentFromISR)
      res = mIncomingQ.sendFromISR((OsMsg&)rMsg);
   else
      res = mIncomingQ.send(rMsg, rTimeout);
   return res;
}

// Call OsTask::requestShutdown() and then post an OS_SHUTDOWN message
// to the incoming message queue to unblock the task.
void OsServerTask::requestShutdown(void)
{
   OsStatus res;

   OsMsg msg(OsMsg::OS_SHUTDOWN, 0);

   OsTask::requestShutdown();
   res = postMessage(msg);
   assert(res = OS_SUCCESS);
}

/* ============================ ACCESSORS ================================= */

// Get the pointer to the incoming message queue
OsMsgQ* OsServerTask::getMessageQueue()
{
    return(&mIncomingQ);
}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

// Waits for a message to arrive on the task's incoming message queue.
OsStatus OsServerTask::receiveMessage(OsMsg*& rpMsg)
{
   return mIncomingQ.receive(rpMsg);
}

// Waits for a message to arrive on the task's incoming message queue.
OsStatus OsServerTask::receiveMessage(OsMsg*& rpMsg,
                                      const OsTime& rTimeout)
{
   return mIncomingQ.receive(rpMsg, rTimeout);
}

// The entry point for the task.
// This method executes a message processing loop until either
// requestShutdown(), deleteForce(), or the destructor for this object
// is called.
int OsServerTask::run(void* pArg)
{
   UtlBoolean doShutdown = FALSE;
   OsMsg*    pMsg = NULL;
   OsStatus  res;

   do
   {
      res = receiveMessage((OsMsg*&) pMsg);          // wait for a message

      if(res == OS_SUCCESS)
      {

          doShutdown = isShuttingDown();
          if (!doShutdown)
          {                                              // comply with shutdown
             if (!handleMessage(*pMsg))                  // process the message
                OsServerTask::handleMessage(*pMsg);
          }

          if (!pMsg->getSentFromISR())
             pMsg->releaseMsg();                         // free the message
      }
      else
      {
          OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsServerTask receiveMessage returned: %d", res);
          OsSysLog::flush();
          //assert(res == OS_SUCCESS);

      }
   }
   while (!doShutdown);

   return 0;        // and then exit
}

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ FUNCTIONS ================================= */
