/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#pragma once

// Base class, should not be used

//! Base class for registering a callback function
/*! Base class, should not be used!\n \n
 *  MvProtocol is a base class and it is responsible for registering
 *  a callback function associated with a Metview command. Its static
 *  method \c _serve is called when the module receives a command,
 *  and this method calls the virtual method \c _call_serve, which
 *  may be redefined by a derived class.
 */
class MvProtocol
{
protected:
    svcid* Id;
    err Error;

    //! Static "service" function.
    /*! This is the "service" function registered by the constructor,
     *  to be called when the module receives the command. It calls
     *  the virtual method \c _call_serve, which may be implemented in
     *  a derived class. Argument \c id is the service structure and \c obj
     *  points to the MvProtocol object that registered this function.
     */
    static void _serve(svcid* id, request* r, void* obj);


    //! The default virtual method called by \c _serve.
    /*! Transforms the incoming request structure \c rq into a MvRequest
     *  and calls the virtual method \c callback which should be
     *  implemented in a derived class.
     */
    virtual void _call_serve(svcid* id, request* rq);

    virtual void _clear_id();
    virtual ~MvProtocol();

public:
    //-- Information --

    //! Returns the value of parameter \c _NAME
    /*! In other words, returns the name of the object that is
     *  currently referenced in the incoming command.
     */
    const char* iconName();

    //! Returns the value of parameter \c _CLASS
    /*! In other words, returns the class of the object that is
     *  currently referenced in the incoming command.
     */
    const char* iconClass();

    //! Returns the value of parameter \c SOURCE from incoming command.
    const char* getSource();

    //! Returns the value of parameter \c TARGET from incoming command.
    const char* getTarget();

    //! Returns the value of parameter \c _ACTION from incoming command.
    const char* getAction();

    //! Returns a copy of the subrequest in parameter \c _MODE from incoming command.
    MvRequest getMode();

    //! Returns the value of parameter \c USER_REF from incoming command.
    void* getReference();


    //! Creates an empty object.
    MvProtocol() { Id = nullptr; }

    //! Constructor for command \c name
    /*! This constructor registers protected static method \c _serve
     *  to be called when the module receives command \c name.
     */
    MvProtocol(const char* name);

    virtual void addCallbackKeyword(const char*);

    //! Empty virtual method
    /*! This method should be implemented in a derived class.
     */
    virtual void callback(MvRequest&) {}

    //-- Communication --

    //! Creates an error message
    /*! Sets the error number \c e and formats an error message into
     *  the internal service structure. Arguments \c fmt and \c ... are
     *  formats like in C language printf function.
     */
    void setError(err e, const char* fmt, ...);

    //! Sets the error number \c e into the internal service structure
    void setError(err e);

    //! Returns the error code
    int getError();

    //! Returns the error message
    const char* getMessage(int err);

    //! Sends back the reply request answer
    /*! Error code and error messages will be sent back as well.
     */
    void sendReply(const MvRequest& answer);

    //! Broadcasts a progress message
    /*! Arguments \c fmt and \c ... are formats like in C language printf function.
     */
    void sendProgress(const std::string& msg);
    void sendProgress(const char* fmt, ...);

    //! Broadcasts a progress message coded as a MvRequest
    void sendProgress(const MvRequest& req);

    void reDispatch(MvRequest& req);
};

// Used for asynchronious calls (use MvService for synchronious calls)
// Goes with the template below..

//! Used for asynchronious calls (use MvService for synchronious calls)
/*! When a module does not have the behaviour of a typical Metview module,
 *  a more general class MvTransaction may be used instead of MvService.
 *  MvTransaction is an abstract class and a new class must be defined
 *  for each command the module must execute.\n \n
 *  A C++ template TMvTransaction is provided for defining a MvTransaction derived class.
 */
class MvTransaction : public MvProtocol
{
    /*! This method deletes the current instance, the one
     *  that is created by method \c _call_serve.
     */
    virtual void _clear_id();

    /*! This method creates a new instance of MvTransaction and
     *  calls this new instance's method callback.
     */
    virtual void _call_serve(svcid*, request*);

    //! This pure virtual method is implemented in MvTransaction template
    virtual MvTransaction* cloneSelf() = 0;

protected:
    //! This constructor calls MvProtocol empty constructor.
    MvTransaction() :
        MvProtocol() {}

    //! This constructor calls the equivalent MvProtocol constructor.
    MvTransaction(const char* name) :
        MvProtocol(name) {}

    //! This constructor makes a copy of MvTransaction \c from
    MvTransaction(MvTransaction* x);
};

//

//=======================================================================

//! Used by MetviewUI. Base class for MvServiceReply
class MvReply : public MvProtocol
{
public:
    MvReply(const char* = nullptr);
    void addCallbackKeyword(const char*);
};

//! [used by MetviewUI]
class MvProgress : public MvProtocol
{
public:
    MvProgress(const char* = nullptr);
    void addCallbackKeyword(const char*);
};

//! [used by MvPreferenceMessage and MetviewUI]
class MvMessage : public MvProtocol
{
public:
    MvMessage(const char* = nullptr);
};
