/** \file
 *
 *  Contains the PCaller class declaration
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef PCALLER_H_
#define PCALLER_H_

#include <pthread.h>
#include <signal.h>

#include "component/Behavior.h"
#include "logger/Logger.h"
#include "utils/FlexArray.h"
#include "utils/Mutex.h"

/**
 *  Protected Caller
 *
 *  Can be used by a Handler or Component to make signal-handling protected
 *  calls to the execute(), initialize(), or uninitialize() methods of a component.
 *
 *  \ingroup process
 */
class PCaller
{
public:

    PCaller( bool idleThread, Logger & logger );

    virtual ~PCaller();

    typedef enum
    {
        BLOCK_NO_OPERATION,
        BLOCK_INITIALIZE,
        BLOCK_EXECUTE,
        BLOCK_EXECUTE_IF_UNSATISFIED,
        BLOCK_UNINITIALIZE,
        PCALLER_START,
        PCALLER_TERMINATE
    } PCallOperationType;

    bool pInitialize( Component & component )
    {
        return pCall( component, BLOCK_INITIALIZE, NULL );
    }

    bool pExecute( Component & component )
    {
        return pCall( component, BLOCK_EXECUTE, NULL );
    }

    bool pExecuteIfUnsatisfied( Behavior & component, bool & satisfied )
    {
        return pCall( component, BLOCK_EXECUTE_IF_UNSATISFIED, &satisfied );
    }

    bool pUninitialize( Component & component )
    {
        return pCall( component, BLOCK_UNINITIALIZE, NULL );
    }

private:
    struct PCallOperation
    {
        Component *component_;
        PCallOperationType operation_;
        bool *returnValue_;
    };
    bool startThread();
    void stopThread();
    bool pCall( Component & component, PCallOperationType operation, bool *returnValue );
    static void LogTrace( Component* component, int signal, int errnum, int code, size_t addr, size_t backtraceCount, char **backtraceStrings );
    void containedWait();
    void ownerWait();
    void yieldToContained();
    void yieldToOwner();
    static const char *PCallOperationToChars( const PCallOperationType operation );
    static void *PThreadRun( void *pCaller );
    Logger& logger_;
    Mutex pCallMutex_;
    Mutex threadConditionMutex_;
    ThreadCondition threadCondition_;
    pthread_t containedThread_;
    pthread_t ownerThread_;
    pthread_t runningThread_;
    Component *currentComponent_;
    PCallOperation currentOperation_;
    pthread_attr_t threadAttributes_;
    bool threadRunning_;
    bool threadDone_;
    bool idle_;
    class Initializer
    {
    public:
        Initializer();
    };
    static Initializer Initializer_;
    static void RegisterDefaultSignals( void );
    static void DefaultSignalHandler( int signal, siginfo_t *sigIngo, void *context );
    static const char *SignalMessage( int signal, int code );
    static const char SIGNAL_LOG_FILE[];
    static FlexArray<PCaller*> PCallers_;

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    PCaller( const PCaller& old ); // disallow copy constructor

};

#endif /*PCALLER_H_*/
