/**
 *  Add event to the event q.
 *
 *  API to add event to the state machine instance queue.  The
 *  event properties are copied (a new event is created and 
 *  the contents of the event passed a re copied to the new 
 *  event), but the payload is just referenced and not copied.
 *  
 *  @param smThis Extended State machine Instance handle
 *  @param msg  Event information
 *
 *  @returns 
 *    CL_OK on CL_OK <br/>
 *    CL_SM_RC(CL_ERR_NO_MEMORY) on memory allocation FAILURE <br/>
 *    CL_SM_RC(CL_ERR_NULL_POINTER) on invalid/null instance handle <br/>
 *
 *  @see #clEsmInstanceProcessEvent
 *  @see #clEsmInstanceProcessEvents
 *
 */
ClRcT
clEsmInstanceEventAdd(ClExSmInstancePtrT smThis, 
                    ClSmEventPtrT msg
                    )
{
  ClRcT ret = CL_OK;

  CL_FUNC_ENTER();

  CL_ASSERT(smThis);
  CL_ASSERT(msg);

  if(smThis && msg)
    {
      ClSmQueueItemPtrT item;

      item = (ClSmQueueItemPtrT) mALLOC(sizeof(ClSmQueueItemT)); 
      if(!item)
        {
          ret = CL_SM_RC(CL_ERR_NO_MEMORY);
        }
      else 
        {
          if(ESM_LOCK(smThis)!=CL_OK)
            {
              ret = SM_ERR_LOCKED;
              mFREE(item);
              CL_FUNC_EXIT();
              return ret;
            }
          item->event = *msg;
          if (ESM_IS_PAUSED(smThis) && ESM_IS_DROP_ON_PAUSE(smThis))
          {
              ret = CL_OK;
              mFREE(item);
              ESM_UNLOCK(smThis);
              CL_FUNC_EXIT();
              return ret;
          }
          ret = SMQ_ENQUEUE(smThis->q, item);
          clLogTrace(ESM_LOG_AREA,ESM_LOG_CTX_EVENT,"Event %d added => ret [%d]",
                                item->event.eventId,
                                ret);
          ESM_UNLOCK(smThis);
        }
    } else 
      {
        ret = CL_SM_RC(CL_ERR_NULL_POINTER);
      }

  CL_FUNC_EXIT();
  return ret;
}
/**
 *  Create a new State machine type.
 *
 *  API to create a new State macine Type. Maximum states in the
 *  state machine is passed in the parameter. Each state is 
 *  identified by a state id (index) and captures the transition
 *  table at each table.
 *                                                                        
 *  @param maxStates maximum states in State Machine 
 *  @param sm        [out] handle to the newly created state machine type
 *
 *  @returns 
 *    CL_OK on CL_OK <br/>
 *    CL_SM_RC(CL_ERR_NO_MEMORY) on memory allocation FAILURE <br/>
 *    CL_SM_RC(CL_ERR_NULL_POINTER) on invalid/null state machine handle <br/>
 *
 *  @see #clSmTypeDelete
 */
ClRcT
clSmTypeCreate(ClUint16T maxStates,
             ClSmTemplatePtrT* sm
             )
{
  ClRcT ret = CL_OK;
  int sz = 0;

  CL_FUNC_ENTER();
  CL_ASSERT(sm);  

  CL_DEBUG_PRINT(CL_DEBUG_TRACE, ("Create State Machine Type [%d]", maxStates));

  if(sm && (maxStates > 0)) {
    /* allocate the states and assign to top */
    *sm = (ClSmTemplatePtrT) mALLOC(sizeof(ClSmTemplateT));
    if(*sm!=0) 
      {
        sz = sizeof(ClSmStatePtrT)*(int)maxStates;
        /* allocate space to hold maxStates handles  */
        (*sm)->top = (ClSmStatePtrT*) mALLOC((size_t)sz);
        if((*sm)->top) 
          {
            (*sm)->maxStates = maxStates;
            (*sm)->objects = 0;
            /* Introduced a semaphore for handling concurrent
             * SM Instance creation/deletion
             */
            ret = clOsalMutexCreate( &((*sm)->sem));
            if (CL_OK != ret)
            {
                mFREE((*sm)->top);
                mFREE(*sm);
                ret = SM_ERR_NO_SEMA;
            }
            else
            {
                /* 
                 * default initial state to first state
                 */
                (*sm)->init = (*sm)->top[0];
                (*sm)->type = SIMPLE_STATE_MACHINE;
#ifdef DEBUG
                (*sm)->name[0] = 0;
#endif
            }
          }
        else
          {
            mFREE(*sm);
          }
      }
    if(!(*sm) || !(*sm)->top)
      {
        ret = CL_SM_RC(CL_ERR_NO_MEMORY);
      }
  } else 
    {
      ret = CL_SM_RC(CL_ERR_NULL_POINTER);
    }

  CL_FUNC_EXIT();
  return ret;
}
/**
 *  Creates a new Extended State machine Instance.
 *
 *  This API creates a new Extended State macine Instance of given
 *  state machine type.  The extended state machine shall include
 *  all the regular state machine instance functionalities, plus
 *  additional event queue, history, and lock capabilities.
 *                                                                        
 *  @param sm       State machine type 
 *  @param instance [out] newly created extended state machine instance
 *
 *  @returns 
 *    CL_OK on CL_OK <br/>
 *    CL_SM_RC(CL_ERR_NO_MEMORY) on memory allocation FAILURE <br/>
 *    CL_SM_RC(CL_ERR_NULL_POINTER) on invalid/null sm / instance <br/>
 *
 *  @see #clEsmInstanceDelete
 */
ClRcT
clEsmInstanceCreate(ClSmTemplatePtrT sm, 
                  ClExSmInstancePtrT* instance
                  )
{
  ClRcT ret = CL_OK;

  CL_FUNC_ENTER();
  CL_ASSERT(instance);  
  CL_ASSERT(sm);  

  clLogTrace(ESM_LOG_AREA,ESM_LOG_CTX_CREATE,"Create Extended State Machine Instance");

  if(sm && instance) 
    {
      /* allocate the instance space */
      *instance = (ClExSmInstancePtrT) mALLOC(sizeof(ClExSmInstanceT));
      if(*instance!=0) 
        {
          memset(*instance, 0, sizeof(ClExSmInstanceT));
          /* call sm create here */
          ret = clSmInstanceCreate(sm, &(*instance)->fsm);
          if(ret == CL_OK)
            {
              ret = clOsalMutexCreate(&(*instance)->lock);
              if (CL_OK != ret)
              {
                  clSmInstanceDelete((*instance)->fsm);
                  mFREE(*instance);
                  ret = SM_ERR_NO_SEMA;
              }
              else
              {
              /* create queue and init */
              ret = SMQ_CREATE((*instance)->q);
              if(ret == CL_OK)
                {
                  /* init log buffer */
                  ESM_LOG_INIT((*instance)->log, ESM_LOG_ENTRIES);
                }
              if(!(*instance)->log.buffer || ret != CL_OK)
                {
                  /* delete the instance */
                  ret = clSmInstanceDelete((*instance)->fsm);
                  /* delete the mutex */
                  clOsalMutexDelete((*instance)->lock);
                  /* check if q init succeeded */
                  if(ret == CL_OK)
                    {
                      /* delete the queue */
                      clQueueDelete(&((*instance)->q));
                    }
                  /* free the instance */
                  mFREE(*instance);
                  ret = CL_SM_RC(CL_ERR_NO_MEMORY);
                }
              }
            }
          
        } else 
          {
            ret = CL_SM_RC(CL_ERR_NO_MEMORY);
          }
    } else 
      {
        ret = CL_SM_RC(CL_ERR_NULL_POINTER);
      }
  
  CL_FUNC_EXIT();
  return ret;
}