/* ----   file information  -------------------------------------------------
   Black Sun Interactive

   Project:    Community Services
   Subsystem:  Agent SDK Sample programs

   Purpose:    Call functions from Agent Script. 
               Implementation of hbAPI derived class.

   Description:
               As opposed to the simple example, this is example shows how to 
               use the API by using one single worker thread. Most of the code
               in this example is for synchronization of main (script interpreter) 
               thread and worker thread.

               evtcontext.h contains the TestEventContext class which is derived from 
               the hbAPI class.

               We only redefine the Constructor/Destructor, the className() method.
               The Constructor of Controller registers the function we want to call
               from the Agent scripts. 

   Module:     complex.cpp

   Date:       1998/01/22
   $Log: evtcontext.cpp,v $
   Revision 1.1  2001/03/12 15:05:14  robert
   Initial revision



   ----   file information  --------------------------------------------------*/



//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//             Include files and macros                                                  
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

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

#ifndef _WIN32

#include <unistd.h>
#include <pthread.h>

#else

#include <windows.h>
#include <process.h>

#endif


#include "hbapi.h"          // Agent API include file
#include "evtcontext.h"     // derivation of hbAPI class
#include "mutex.h"          // definition of mutual exclusion classes
#include "workerthread.h"   // definition of worker thread classes


#ifdef WIN32 
  #define EXT_HBAPI_EXPORT __declspec( dllexport )
#else
  #define EXT_HBAPI_EXPORT 
#endif



//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//          Main Class implementation
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

//
//  Constructor
//
TestEventContext::TestEventContext( CSHandle_t sessionHdl ) : hbAPI( sessionHdl )
{ 
    int rc;
      
   // here we register the function we want to call from the
   // Agent script.

#ifdef WIN32
   rc = registerFunc( "RetrieveData", (hbFuncType) RetrieveData);
#else
   rc = registerFunc( "RetrieveData", (hbFuncType) &RetrieveData);
#endif
   if ( rc != 0 )
   {
       hbAPI::writeLog("%-14s: API Could not register function: init_array\n", "" );
   }
};


//
//  Destructor
//
TestEventContext::~TestEventContext() 
{ 
};


//
//  this method just returns the name of the current class
//
const char * TestEventContext::className() const
{
   return "TestEventContext";
}



//
//  This is the entry point function for Agent
//  This function creates an instance of the current Agent API class.
//  Once it succeded, this function will never be called again.
//

EXT_HBAPI_EXPORT hbAPI * createInstance( CSHandle_t sessionHdl, const char *name )
{
   
    hbInitAPISession();

   if ( name != (char *) 0 )
   {
     return new TestEventContext( sessionHdl );
   }

   return 0;
};



//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//          Main application functions and worker thread DB access 
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

//
// The worker thread main function. 
//

#ifdef _WIN32
#define VOID_NULL
void threadfunc( void * thread ) 

#else

#define VOID_NULL (void *)0
void *threadfunc( void * thread ) 
#endif
{
    static int init_db = 1;
    WorkerThread * worker = (WorkerThread *) thread;
    Job          * args   = (Job  *) worker;
    

    if ( init_db )
    {
        // initialise database interface

        //
        // .... insert your code here
        //
        
        init_db = 0;
    }

    //
    // worker thread main loop
    // checks for new jobs to be done and issues the results 
    // as script events to the Agent script interpreter
    //
    while ( ! worker->stopped() )
    {
        args = worker->_jobs.get( 1 );
        if ( args == NULL )
        {
            continue;
        }

        //
        // now do the query from the DB
        // use args->Query() for your DB query
        //

        //
        // .... insert your code here, 

        //
        // we just sleep and assign some string here
        // to simulate a long-lasting successfull query
        // 

#ifdef _WIN32
        Sleep(3000);
#else
        sleep(3);
#endif

        char *result = "database query dummy result";

        // ok, result available, now  throw the api event
    
        const hbEventContext *context = args->Context();

        if ( context )
        {
            context->apiEvent( "DB_RESULT", result );
        }
        else
        {
            hbAPI::writeLog("Error: no event context available");
        }
    }

    return VOID_NULL;
}

//
// This is the function which is called by the Agent script
// in a  *Call* action.
//
// The input parameter "input" must not be modified by this function.
// The result returned is a string which also can be a null pointer.
// If the result string is not null, it is immediately copied into 
// Agent's memory.
//
// This function has to make sure to free memory allocated for the
// result strings or pass pointers to static memory as result 
//


char * TestEventContext::RetrieveData( const char * input )
{

  static WorkerThread *worker = 0;
  int rc;

  hbEventContext * context = getEventContext();
  Job              args ( input, context ) ;

  delete context;

  if ( worker == 0 )
  {
     //
     // first call of this function, create and start the worker thread
     //
     worker = new WorkerThread( threadfunc );
     if ( ! worker )
     {
          hbAPI::writeLog("Error: could not create worker thread");
          return 0;
     }
     if ( worker->start() )
     {
          hbAPI::writeLog("Error: could not start worker thread");
          return 0;
     }
  }
  
  // add the new job
  rc = worker->_jobs.add ( args );
  hbAPI::writeLog("Added job rc=%d\n", rc);

  return 0;
}

//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//          END 
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
