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

#include "MvFwd.h"
#include "MvAbstractApplication.h"
#include "MvRequest.h"

// The application of a non-ui module. It gets the basic parameters
// from the configuration file and command line, registers the service name
// and starts the communication with event.
// Only one instance can be created in a program!
class MvApplication : public MvAbstractApplication
{
    friend class MvLog;

public:
    MvApplication(int& argc, char** argv, const char* name = nullptr,
                  void* aparg = nullptr, int nopt = 0, option* = nullptr);

    // Starts the module's main MARS event loop.
    virtual void run();

    void wantPreferences(const char* = nullptr);
    virtual void newPreferences(const MvRequest&) {}
    virtual void addInputCallback(FILE*, inputproc, void*);

    static MvRequest getPreferences(const char* = nullptr);
    static MvRequest getExpandedPreferences(const char* = nullptr);
    static void setPreferences(const MvRequest&, const char* = nullptr);

    // Sends request req to service
    static void callService(const char* name, const MvRequest& req, void* ref);
    static MvRequest waitService(const char*, const MvRequest&, int&);
    static void callFunction(const char*, const MvRequest&, void*);

    // Broadcasts the message
    static void sendMessage(const MvRequest& req);
    static void sendMessage(const std::string& msg);

    static void recordOn(boolean = true);
    static void setFork(boolean);

    // Defines the maximum time the module may stay in an idle state before being aborted.
    static void setExitTimeout(int minutes);

    static void destroyService();
    static void setKeepAlive(boolean);
    static void setMaximum(int);
    static boolean stopAll(const char*, ...);
    static void notifyIconCreation(const char* icon_name, const char* icon_class);
    static void notifyIconModified(const char* icon_name, const char* icon_class);

    // Returns the service structure created by the constructor.
    static svc* getService() { return service_; }

    static MvRequest poolFetch(const char* icon_name, const char* icon_class);
    static void poolStore(const char* icon_name, const char* icon_class,
                          const MvRequest&);
    static void poolLink(const char* name1, const char* name2);

    static void saveErrorAsRequest(const std::string& outPath, const std::string& msg);
    static std::string buildAppName(const std::string& name);

    enum SaveAsFolderTarget
    {
        CurrentFoldertarget,
        PreviousFolderTarget
    };
    static SaveAsFolderTarget saveAsFolderTarget();

protected:
    void writeToLog(const std::string& msg, MvLogLevel level) override;
    void writeToUiLog(const std::string&, const std::string&, MvLogLevel, bool) override {}
    void exitWithError() override;

private:
    static MvApplication* app_;
    static svc* service_;
};


#ifndef DOXYGEN_SHOULD_SKIP_THIS

//-- obsolete? PlotMod and uPlot use directly MvApplication::setKeepAlive()

class KeepAlive
{
    static int count_;

public:
    KeepAlive()
    {
        if (++count_ == 1)
            MvApplication::setKeepAlive(true);
    }
    ~KeepAlive()
    {
        if (--count_ == 0)
            MvApplication::setKeepAlive(false);
    }
};
#endif
