/*==================================================================================================

                    Copyright (c) 2007 UGS
                             Unpublished - All rights reserved
====================================================================================================
File description:

    Filename: OperationDispatcher.hxx
    Module  : extensionframework

    This class is used by auto-generated Dispatch mechanism (<BO>Dispatch::operation).
    <br/>To facilitate the compile/build of the auto generated Dispatch classes, this class is made public.
    @important The class and its members are not intended to be used explicitly for any other purposes.

    This class dispatches the function calls for a particular BO operation.

====================================================================================================
   Date      Name                    Description of Change
30-Oct-2008  Krzysztof Blaszczyk     Following members made const: askBMOperationtag(), baseFunctionExists(), isPropagateInheritedDone()
31-Oct-2008  Krzysztof Blaszczyk     Following members made const: getSizeOfPreConditions(), getSizeOfPreActions(), getSizeOfPostActions()
$HISTORY$
==================================================================================================*/
#ifndef OPERATIONDISPATCHER_HXX
#define OPERATIONDISPATCHER_HXX

#include <unidefs.h>
#include <vector>
#include <tccore/method.h>
#include <itk/bmf.h> //for adding reference of ExtensionPointType_t
#include <metaframework/BusinessObject.hxx>
#include <metaframework/Object.hxx>
#include <property/BulkPropertyContextData.hxx>
#include <extensionframework/libextensionframework_exports.h>

namespace Teamcenter
{
    class OperationDispatcher;
    class FunctionInvoker;
    class OpToOpExtensionInvoker;
    class BusinessObject;
    class ExtensionSet;
    class ExtensionFunctionSet;
    class ImanTypeCache;
    struct extn_fn;
}

/** Pre, Post and Base extension category updated during extension registration for each type of operation
 *  These extension categories would help to identify the
 *  function invoker required to convert set based input to the legacy message based extension inputs and
 *  also the set based input to the object based meta model extension inputs
 */
typedef enum EXTENSIONFRAMEWORK_extension_category_e
{
    EXTENSION_CATEGORY_UNDEFINED = 0,           /**< Identifies default extension category */
    OBJECT_BASED_METAMODEL_EXTENSION,           /**< Identifies object based metamodel extension category */
    LEGACY_MESSAGE_BASED_EXTENSION,             /**< Identifies legacy message based extension category */
    SET_BASED_METAMODEL_EXTENSION              /**< Identifies set based metamodel extension category */
}EXTENSIONFRAMEWORK_extension_category_t;


/** Specify the Operation Extensions propagation context during merge of extensions.
 *  This would help to idnetify if the function invoker is required for set based operation
 *  The value MERGE_PROPAGATION is updated during merge operation only and pass till ExtensionAttachCache
 *  from Operation dispatcher code
 */
typedef enum EXTENSIONFRAMEWORK_operation_extn_propagation_context_e
{
    DEFAULT_PROPAGATION = 0,                                /**< Signifies if the extensions are propagated from parent to child operation dispatcher */
    SET_BASED_MERGE_PROPAGATION,                            /**< Signifies if the extensions are merged from object based or legacy message based
                                                                 operation dispatcher to set based operation dispatcher */
    OBJECT_BASED_MESSAGE_BASED_MERGE_PROPAGATION            /**< Signifies if the extensions are merged from set based operation dispatcher to the object based
                                                                 or the legacy message based operation dispatcher */
}EXTENSIONFRAMEWORK_operation_extn_propagation_context_t;


/** Specify the extension priority. The high priority extensions should always be executed before the
 *  low priority extensions
 */
typedef enum EXTENSIONFRAMEWORK_extension_priority_e
{
    PRIORITY_LOW = 0,                       /**< Identifies the extension added to the operation as low priority extension. This is the default priority of the extension */
    PRIORITY_HIGH                           /**< Identifies the extension added to the operation as high priority extension */
}EXTENSIONFRAMEWORK_extension_priority_t;


/** To set type of PostActions to execute. HIGH_PRIORITY_POST_ACTIONS option is used to execute
 *  PRIORITY_HIGH PostAction extensions (i.e. internal PostAction extensions) for non-refactored Save functions
 */
typedef enum EXTENSIONFRAMEWORK_postactions_execution_option_e
{
    ALL_POST_ACTIONS = 0,                   /**< All the post action extensions attached to the operation needs to be executed */
    HIGH_PRIORITY_POST_ACTIONS              /**< Only the high priority( PRIORITY_HIGH ) post action extensions attached to the operation needs to be executed */
}EXTENSIONFRAMEWORK_postactions_execution_option_t;

struct EXTENSIONFRAMEWORK_API Teamcenter::extn_fn
{
    METHOD_function_t  fn_ptr;
    TC_argument_list_t *user_args;

    /**
        flag to know which ones are coming from parent
    */
    bool isParentExt;
    bool functionInvokerRequired;
    /**
        reattached from source to target
    */
    bool m_reattached;
    extn_fn();
};

class EXTENSIONFRAMEWORK_API Teamcenter::OperationDispatcher : public Teamcenter::Object
{
public:
    OperationDispatcher();
    virtual ~OperationDispatcher();
    
    /**
        The method to add pre condition extension to the legacy operation
    */
    void addPreCondition( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, bool functionInvokerRequired = true );
    void addPreConditionAt( int pos, METHOD_function_t fnPtr, TC_argument_list_t* userArgs );

    /**
        The method to add pre action extension to the legacy operation
    */
    void addPreAction( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, bool functionInvokerRequired = true );
    void addPreActionAt( int pos, METHOD_function_t fnPtr, TC_argument_list_t *userArgs );

    /**
        The method to add post action extension to the legacy operation
    */
    void addPostAction( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, bool functionInvokerRequired = true,
                        bool auto_dispatched = true );
    void addPostActionAt( int pos, METHOD_function_t fnPtr, TC_argument_list_t *userArgs );

    /**
        The method to add high priority post action extension to the set based meta model operation
    */
    void addPostActionInternal( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, bool functionInvokerRequired = true,
                        bool auto_dispatched = true );
    void setBaseAction( METHOD_function_t baseActionFnPtr, TC_argument_list_t* baseActionUserArgs );
    void setBaseActionCategory( EXTENSIONFRAMEWORK_extension_category_t extnCategory );
    EXTENSIONFRAMEWORK_extension_category_t getBaseActionCategory() const;
    void setBaseActionFunctionInvokerRequired( bool functionInvokerRequired );


    /**
        Dump function to display all member variables
    */
    void dumpFunction();
    /**
        get base action
    */
    extn_fn getBaseAction() const;

    bool isPropagateInheritedDone() const { return m_populateInheritedDone; }
    void propagatedInheritedDone( bool done ){ m_populateInheritedDone = done; }

    /**
        This method would return true if the set based operation dispatcher contains
        object based base action after merge of extensions
    */
    bool getIsObjectBasedBaseActionMergedToSetBased() const;

    bool baseFunctionExists() const;

    void propagateInherited( OperationDispatcher* parentOpDispatcher );

    /**
        bmf related methods
    */
    void setBMOperationtag( tag_t bmoptag );
    void askBMOperationtag( tag_t* bmoptag ) const;
    const char* askBMOperationName() const;

    /**
        function invoker related stuff
    */
    void setFunctionInvoker( Teamcenter::FunctionInvoker* functionInvokerObj );

    /**
        meta operation related stuff
    */
    void setMetaOperation( bool isMetaOperation );
    bool isOperation() const { return m_isOperation; }
    int removePreConditionAt( int position );
    int removePreActionAt( int position );
    int removePostActionAt( int position );
    int movePreCondition( int oldPosition, int newPosition );
    int movePreAction( int oldPosition, int newPosition );
    int movePostAction( int oldPosition, int newPosition );
    int reattachExtensions( ImanTypeCache*  imanType );
    int reattachPostActionExtensions ( OperationDispatcher* tarOpDispatcher );

    static int reattachCreateToSavePostAction(  ImanTypeCache*          imanType,
                                                OperationDispatcher*    srcOpDispatcher,
                                                const std::string&      tarMsgName );
    void getSizeOfPreConditions( int* size ) const;
    void getSizeOfPreActions( int* size ) const;
    void getSizeOfPostActions( int* size ) const;
    void setBOName( const std::string& boName );
    std::string getBOName()const { return m_boName; }
    void setOpIdInt( const int opIdInt );
    int getOpIdInt()const { return m_opIdInt; }
    typedef logical (* METHOD_user_arg_compare_t) (TC_argument_list_t * firstArg,
                                               TC_argument_list_t * secondArg);
    int getPreConditionUserArgPosition( TC_argument_list_t* user_arg_to_compare, METHOD_user_arg_compare_t compareFunc, int* positionFound );
    int getPreActionUserArgPosition( TC_argument_list_t* user_arg_to_compare, METHOD_user_arg_compare_t compareFunc, int* positionFound );
    int getPostActionUserArgPosition( TC_argument_list_t* user_arg_to_compare, METHOD_user_arg_compare_t compareFunc, int* positionFound );

    /**
        overridable methods
    */
    virtual void executePreConditions( METHOD_message_t& msg, va_list args ) const;
    virtual void executePreActions( METHOD_message_t& msg, va_list args ) const;
    virtual void executePostActions( METHOD_message_t& msg, va_list args ) const;

    /**
        when overriding, never change the default arguments
    */
    virtual void executeBaseAction( METHOD_message_t &  msg, va_list  args, bool  userExitBase = false ) const;

    virtual void executePreConditions( tag_t object_tag, va_list args ) const;
    virtual void executePreActions( tag_t object_tag, va_list args ) const;
    virtual void executePostActions( tag_t object_tag, va_list args ) const;

    /**
        when overriding, never change the default arguments
    */
    virtual void executeBaseAction( tag_t  object_tag, va_list  args, bool  userExitBase = false ) const;

    virtual void execute( tag_t object_tag, va_list args ) const;

    /**
        BusinessObject related methods
    */
    virtual void executePreConditions(Teamcenter::BusinessObject* obj, va_list  args ) const;
    virtual void executePreActions(Teamcenter::BusinessObject* obj, va_list  args ) const;
    virtual void executePostActions(Teamcenter::BusinessObject* obj, va_list  args ) const;
    virtual void executeBaseAction(Teamcenter::BusinessObject* obj, va_list  args ) const;
    virtual void execute(Teamcenter::BusinessObject* obj, va_list  args ) const;
    virtual void execute(Teamcenter::BusinessObject* obj, std::vector<void*>&  args )const;


    /**
        check if the base action of an operation dispatcher is the same as this'
    */
    bool sameBaseAction( const OperationDispatcher* dispatcher) const;

    virtual void setName(const std::string& /*name*/);

    bool hasPreOrPostAction() const;

    ExtensionSet* createExtensionSetObject( ExtensionPointType_t extType );

    static int executeUserExit( const char* typeName, const char* propName, const char* msgName, bool* customActionExecuted, ... );
    static int executeUserExit( const char* typeName, const char* propName, const char* msgName, va_list args );
    static int lookupUserExit(  const char* typeName, const char* propName, const char* msgName, OperationDispatcher** opDispatcher );

    int setBMOperationName( const char* opName );
    int setPostExtensionToBeReattached( const std::string& extensionName );

    static bool isExtensionValid( const std::string& typeName, const std::string& operationName,
        const std::string& extensionName, ExtensionPointType_t extType );
    bool validateAutoDispatch() const;
    static bool hasAction( const std::string& typeName, const std::string& operationName,
        ExtensionPointType_t extType );
    FunctionInvoker* resetFunctionInvoker( Teamcenter::FunctionInvoker* functionInvokerObj );

    /**
        Project 011450 changes
    */
    int exePreConditions( METHOD_message_t *  msg,  ... ) const ;
    int exeBaseAction( METHOD_message_t *  msg,  ... ) const;
    int exePreActions( METHOD_message_t *  msg,  ... ) const;
    int exePostActions( METHOD_message_t *  msg,  ... ) const;
    int exeHighPriorityPostActions( METHOD_message_t *  msg,  ... ) const;
    void executeHighPriorityPostActions( METHOD_message_t& msg, va_list args ) const;

    bool anyPreConditions() const;
    bool anyPreActions() const;
    bool anyPostActions() const;

    /**
        Executes the base action during a super call for an object based operation based on dynamic lookup. This is used in auto code generation.
        It is meant for internal use only.
    */
    static int executeObjectBasedSuperBaseAction2( tag_t                 objectType,    /**< (I) The type. */
                                                   const std::string&    operationID,   /**< (I) The operation identifier. */
                                                   int&                  oprnInt,       /**< (IO) The operation identifier as an integer. It is meant for internal use only. */
                                                   tag_t                 object,        /**< (I) The object. */
                                                   ...                                  /**< (I) The variable argument list for the operation. It is meant for internal use only. */
                                                 );

    /**
        Executes the base action during a super call for a set based operation based on dynamic lookup. This is used in auto code generation.
        It is meant for internal use only.
    */
    static int executeSetBasedSuperBaseAction2( const std::string&  typeName,       /**< (I) The type name. */
                                                const std::string&  operationID,    /**< (I) The operation identifier. */
                                                int*                pOprnInt,       /**< (IO) The operation identifier as a pointer to an integer. It is meant for internal use only. */
                                                ...                                 /**< (I) The variable argument list for the operation. It is meant for internal use only. */
                                              );

    /**
        Executes set based base action with object based input. Function invoker adapts object based input to the set based input
    */
    int executeBaseAction2( METHOD_message_t&  msg, va_list  args ) const;

    void copyPreBasePostFromExistingOperationDispatcher( OperationDispatcher* opDispatcher );
    int addRuntimeUserArguments( const char * extensionName, ExtensionPointType_t extType, int argCount, const TC_argument_t * args );
    void setBulkOperationFuncPtr( BulkOperation_bulk_loader_t bulkOperationFuncPtr );
    const BulkOperation_bulk_loader_t askBulkOperationFuncPtr() const;

    virtual void setupMessageData( tag_t  object_tag, METHOD_message_t&  msgData ) const;

    void propagateInherited2( OperationDispatcher* sourceOpDispatcher, EXTENSIONFRAMEWORK_operation_extn_propagation_context_t opPropagationContext = DEFAULT_PROPAGATION );
    void propagateInherited3( OperationDispatcher* sourceOpDispatcher, EXTENSIONFRAMEWORK_operation_extn_propagation_context_t opPropagationContext = DEFAULT_PROPAGATION, bool baseActionMergeRequired = true );

    /**
        The method to add pre condition extension to the meta model operation
    */
    void addPreCondition2( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, EXTENSIONFRAMEWORK_extension_category_t extnCategory, bool functionInvokerRequired = true );

    /**
        The method to add pre action extension to the meta model operation
    */
    void addPreAction2( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, EXTENSIONFRAMEWORK_extension_category_t extnCategory, bool functionInvokerRequired = true );

    /**
        The method to add post action extension to the meta model operation
    */
    void addPostAction2( METHOD_function_t fnPtr, TC_argument_list_t* userArgs, EXTENSIONFRAMEWORK_extension_category_t extnCategory, bool functionInvokerRequired = true, bool auto_dispatched = true );

    /**
        These methods would be helpfull to verify the extension attribute
    */
    ExtensionSet* getPreConditionSet() const;
    ExtensionSet* getPreActionSet() const;
    ExtensionSet* getBaseActionSet() const;
    ExtensionSet* getPostActionSet() const;
    ExtensionFunctionSet* getPreConditionExtensionFunctions() const;
    ExtensionFunctionSet* getPreActionExtensionFunctions() const;
    ExtensionFunctionSet* getPostActionExtensionFunctions() const;

    /**
        Set the specified extension refactored as set based.
        The refactored object based or message based extension would not be merged
        to the set based dispatcher. If the specified extension is a set based
        extension, then the same would not be merged to the object based dispatcher.
    */
    int setExtensionRefactoredAsSetBased( const std::string& extensionName,
                                          ExtensionPointType_t extensionType );

    extn_fn                 m_baseAction;

    /**
        Sets a flag to require access check before the operation named on this dispatcher is executed.
    */
    void setOarEnabled( bool value );

    /**
        Returns the flag indicating access check is required before the operation named on this dispatcher is executed
    */
    bool getOarEnabled() const;

    /**
        Sets a flag indicating the operation named on this dispatcher is set based.
    */
    void setAsSetBased( bool value );

    /**
        Returns the flag indicating the operation named on this dispatcher is set based.
    */
    bool isSetBased() const;



private:

    void validateOperationAccessControlRules( METHOD_message_t& msg, va_list  args ) const;
    bool isBaseActionExtensionsetEmpty() const;

    /**
        Determine if the object based super needs to execute set based base action at parent business object.
        It is meant for internal use only.
    */
    static int evaluateObjectBasedSuperNeedsToExecuteParentSetBasedBaseAction( tag_t                    objectType,                             /**< (I) The type. */
                                                                               const std::string&       objectBasedOperationID,                 /**< (I) The object based operation identifier. */
                                                                               int&                     oprnInt,                                /**< (IO) The operation identifier as an integer. It is meant for internal use only. */
                                                                               bool&                    oObjBasedSuperDelegToSetBasedParent,    /**< (O) Flag indicating if object based operation can be delegated to set based operation on the parent business object. */
                                                                               OperationDispatcher*&    opParentOprnDisp                        /**< (O) The evaluated operation dispatcher. */
                                                                             );

    /**
        Retrieves the first parent in the type hierarchy that has a base action implementation different than the one present on input type.
        It is meant for internal use only.
    */
    static int evaluateParentBusinessObjectOverrideOperation( tag_t                                     objectType,             /**< (I) The type. */
                                                              const std::string&                        operationID,            /**< (I) The object based operation identifier. */
                                                              int&                                      oprnInt,                /**< (IO) The operation identifier as an integer. It is meant for internal use only. */
                                                              EXTENSIONFRAMEWORK_extension_category_t   opCategory,             /**< (O) The extension category. */
                                                              tag_t&                                    parentWithOpOverriden,  /**< (O) The first parent type having a base action implementation different than the one present on the input type. */
                                                              OperationDispatcher*&                     opParentOprnDisp        /**< (O) The evaluated operation dispatcher. */
                                                            );

    /**
        Executes the base action during a super call for a set based operation based on dynamic lookup.
        It is meant for internal use only.
    */
    static int executeSetBasedSuperBaseAction( const std::string&   typeName,       /**< (I) The type name. */
                                               const std::string&   operationID,    /**< (I) The operation identifier. */
                                               int&                 oprnInt,        /**< (IO) The operation identifier as an integer. It is meant for internal use only. */
                                               va_list              args            /**< (I) The variable argument list for the operation. It is meant for internal use only. */
                                             );

    ExtensionFunctionSet*   createFunctionSetObject( ExtensionPointType_t  extType );



    ExtensionFunctionSet*   m_preConditionSet;
    ExtensionFunctionSet*   m_preActionSet;
    ExtensionFunctionSet*   m_postActionSet;
    ExtensionSet*           m_preConditionExtensionSet;
    ExtensionSet*           m_preActionExtensionSet;
    ExtensionSet*           m_baseActionExtensionSet; // only one is allowed
    ExtensionSet*           m_postActionExtensionSet;

    bool                    m_isOperation; // base action is a C++ method (for metamodel operation)
    bool                    m_populateInheritedDone;

    /**
        bmf operation for now
    */
    tag_t                           m_bmoperationTag;
    FunctionInvoker*                m_functionInvokerObj;

    std::string                     m_boName;
    bool                            m_oarEnabled;
    bool                            m_setBased;
    int                             m_opIdInt;
    char*                           m_operationName;
    BulkOperation_bulk_loader_t     m_bulkOperationFuncPtr;
};
#include <extensionframework/libextensionframework_undef.h>
#endif //OPERATIONDISPATCHER_HXX
