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

   Black Sun Interactive

   Project:    Community Services
   Subsystem:  Agent SDK

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

   Description:
               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:     evtcontext.cpp

   Date:       1998/01/22
   $Log: evtcontext.cpp,v $
   Revision 1.1  2001/03/12 15:04:57  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


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


//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//          Logging utilities and macros
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



//
//  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 )
   {
       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;
};



//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//          LOGIC                                                    
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

//
// We define a class
// for the arguments we pass to our thread function
//
class Thread_Arg 
{
private:
    char * query;
    hbEventContext *context;

    // private parameterless constructor
    Thread_Arg();

public:


    Thread_Arg( const char *q, const hbEventContext *c )
    {
        query   = 0 ;
        context = 0 ;

        if ( q ) 
        {
            query = new char ( strlen( q ) + 1 );
            if ( query )
            {
                strcpy ( query, q );
            }
        }
        if ( c ) 
        {
            context = new hbEventContext ( *c );
        }
    }

    ~Thread_Arg()
    {
        delete query ; 
        delete context;
    }

    const char *Query() const
    {
       return query;
    }

    const hbEventContext * Context()const
    {
       return context;
    }
};


//
// The thread function
//


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

#else

#define VOID_NULL (void *)0
void *threadfunc( void * arg ) 
#endif
{
    static int init_db = 1;
    Thread_Arg * args = (Thread_Arg *) arg;

    char * result = 0;
   
    fprintf(stderr, "\nstarted thread 1\n"); fflush(stderr);
    hbAPI::writeLog("\nstarted thread 2\n"); fflush(stderr);
    
    if ( ! args )
    {
        return VOID_NULL;
    }

   
    if ( init_db )
    {
        // initialise database interface

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

    //
    // 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

    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;
    }

    //
    // delete allocated args object and finish thread
    //

    delete args;

    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 )
{

  hbEventContext * contxt = getEventContext();
#ifndef _WIN32
  pthread_t               theThread;
#endif


  Thread_Arg * args = new Thread_Arg( input, contxt ) ;

  writeLog("STARTING thread ");
#ifndef _WIN32
  int rc = pthread_create( &theThread, NULL, threadfunc, args );
  if ( rc != 0)
#else
  long rc = _beginthread( threadfunc, 0, args );
  if ( rc == -1 )
#endif
  
  {
      writeLog("Error: could not create thread");
  }

  delete contxt;

  return 0;
}

//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//          END LOGIC                                                
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
