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

//--#--define USE_THREADS

#ifdef USE_THREADS
#include <pthread.h>
#include "Queue.h"
#endif

class Service
{
    static Service* gHead;
    static Service* gMonitor;

    Service* next_;

    int soc_;
    int valid_;
    char* name_;
    char* host_;
    char* user_;
    long pid_;
    XDR x_;

    long ref_;
    int ready_;

    time_t timeout_;
    time_t lastcall_;

    int want_message_;
    int want_progress_;

    int alive_;

    int outstanding_;
    int maximum_;

#ifdef USE_THREADS

    pthread_t thread_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
    int stop_;
    int running_;
    int threaded_;

    Queue queue_;
    Queue done_;

    void ThreadProc();
    static void* StartThread(void*);
#endif


public:
    void SendRequest(request*);
    void CallService(request*);
    void GotReply(request*);

    void HandleReply(request* r);
    void HandleProgress(request* r);
    void HandleExit(request* r);
    void HandleService(request* r);
    void HandleFollowup(request* r);
    void HandleMessage(request* r);
    void HandleRegister(request* r);
    void HandleGetInfo(request* r);
    void HandleStart(request* r);
    void HandleWant(request* r);
    void HandleDrop(request* r);
    void HandleTimeout(request* r);
    void HandleAlive(request* r);
    void HandleMonitor(request* r);
    void HandleMaximum(request* r);
    void HandleLater(request* r);
    void HandleStop(request* r);
    void Dispatch(request* r);

    Service(int);
    ~Service();

    static Service* Find(long);
    static Service* Find(const char*);
    static void DispatchInput(fd_set&);
    static void StartService(const char*);
    static void ReplyFail(const char*, const char*, request*);
    static void UserMessage(const char*, ...);
    static void Broadcast(request*);
    static void BroadcastMessage(request*);
    static int CheckTimeout();

    void NotifyMonitor(const char*, request*);
    static void NotifyMonitor(const char*, request*, long, const char*);

    void ProcessIncoming();
#ifdef USE_THREADS
    int EncodeRequest(QElem*);
#else
    int EncodeRequest(request*);
#endif


    const char* Name()
    {
        return name_;
    }
    int Busy();
};
