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

//
// .NAME: MagPlusService
//
// .AUTHOR:
//  Fernando Augusto Mitsuo Ii
//     ECMWF, December 2005
//
// .SUMMARY:
//  Describes the MagPlusService class, which handles
//  the communication with Magics++.
//
// .CLIENTS:
//
// .RESPONSABILITY:
//
// .COLLABORATORS:
//  MvServiceTask
//
// .ASCENDENT:
//  MvClient
//
// .DESCENDENT:
//  MagPlusInteractiveService, MagPlusBatchService
//
// .REFERENCES:
//  This class is based on the general facilities for
//  process communication used in METVIEW, especially the
//  MvClient and MvServiceTask facilities. Please refer
//  to these classes (or have a chat with Baudoin) for
//  more information.
//
//  This class implements a "singleton" as suggested
//  by Myers, "More Effective C+", page 130.
//

#ifndef MagPlusService_H
#define MagPlusService_H

#include <MagPlus.h>

#include "Metview.h"
#include "MvTask.h"
#include "MagicsEvent.h"

class MtInputEvent;
class MvMagParam : public MagParam
{
public:
    MvMagParam(MvRequest& request, const string& name, int index = 0) :
        request_(request),
        name_(name),
        index_(index) {}
    ~MvMagParam() {}

    operator double() const { return (double)request_(name_.c_str(), index_); }
    operator string() const
    {
        const char* val = request_(name_.c_str(), index_);
        return (val) ? string(val) : string("");
    }
    operator int() const { return (int)request_(name_.c_str(), index_); }
    operator long int() const { return (long int)request_(name_.c_str(), index_); }
    MagParam& operator=(int i)
    {
        request_(name_.c_str(), index_) = i;
        return *this;
    }
    MagParam& operator=(long int i)
    {
        request_(name_.c_str(), index_) = i;
        return *this;
    }
    MagParam& operator=(string s)
    {
        request_(name_.c_str(), index_) = s.c_str();
        return *this;
    }
    MagParam& operator=(double d)
    {
        request_(name_.c_str(), index_) = d;
        return *this;
    }
    void index(int index) { index_ = index; }


protected:
    MvRequest& request_;
    string name_;
    int index_;
};

class MvMagRequest : public MagRequest
{
public:
    MvMagRequest(MvRequest request) :
        request_(request) {}
    ~MvMagRequest() {}

    MagParam& operator()(const string& name) const
    {
        map<string, MvMagParam>::iterator param = parameters_.find(name);
        if (param == parameters_.end()) {
            parameters_.insert(make_pair(name, MvMagParam(request_, name)));
            param = parameters_.find(name);
        }
        return param->second;
    }
    void advance()
    {
        request_.advance();
    }
    string getVerb() const { return request_.getVerb(); }

    MagParam& operator()(const string& name, int i) const
    {
        map<string, MvMagParam>::iterator param = parameters_.find(name);
        if (param == parameters_.end()) {
            parameters_.insert(make_pair(name, MvMagParam(request_, name, i)));
            param = parameters_.find(name);
        }
        param->second.index(i);
        return param->second;
    }
    int countValues(const string& name) const
    {
        return request_.countValues(name.c_str());
    }

    MagRequest& getSubRequest(const string& name)
    {
        return *(new MvMagRequest(request_.getSubrequest(name.c_str())));
    }
    operator bool() const { return request_; }

    int countParameters() { return request_.countParameters(); }
    int countValues(const string& name) { return request_.countValues(name.c_str()); }
    string getParameter(int i) { return request_.getParameter(i); }
    void print() { return request_.print(); }
    void read(const string& file) { request_.read(file.c_str()); }
    MagRequest& justOneRequest()
    {
        MvRequest sub = request_.justOneRequest();
        return *(new MvMagRequest(sub));
    }

    MvRequest& getRequest() { return request_; }

protected:
    mutable MvRequest request_;
    mutable map<string, MvMagParam> parameters_;
};
//public magics::MagicsObserver {
class MagPlusService : public MvClient
{
public:
    // Access to singleton object
    static MagPlusService* magPlusServiceInstance_;
    static MagPlusService& Instance();
    static void Instance(MagPlusService*);

    // Destructor
    ~MagPlusService() {}

    // Methods
    // Perform actions after receiving response from Magics
    virtual void endOfTask(MvTask*);
    //	virtual void endOfTask ( MvTask* ){}

    // Call MagPlus application to redraw the map on a specified device(s)
    //	void CallMagPlusRedraw( MvRequest& request );
    //	void CallMagPlusRedraw( MvRequest& request ){}

    // Call MagPlus application to draw the map on screen
    virtual void CallMagPlus(MvRequest&) = 0;
    //	void CallMagPlus( MvRequest& request ){}

    // Set request to be sent to Magics++
    void SetRequest(const MvRequest&);
    //	void SetRequest ( const MvRequest& ){}

    // Decode the geographical coordinates in json string to a MvRequest class
    void decode(MvRequest&, const string&);

    // Register to magics observer
    //	void RegisterObserver(MagicsObserver* observer);
    //	void RegisterObserver(MagicsObserver* observer){}

    // UnRegister to magics observer
    //	void UnRegisterObserver(MagicsObserver* observer);
    //	void UnRegisterObserver(MagicsObserver* observer){}

protected:
    // Constructors
    MagPlusService();  // no external access point

    magics::MagPlus* magplus_;
};

#endif
