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

 Copyright 2013 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 <string>
#include <vector>

#include "mars.h"

class MvProcNode;
class MvProcRequest;

class CpuTime
{
public:
    CpuTime() { clear(); }
    void clear()
    {
        uTime_ = 0;
        sTime_ = 0;
        cuTime_ = 0;
        csTime_ = 0;
        total_ = 0;
    }
    bool isEmpty() const { return total_ == 0; }

    long unsigned int uTime_;
    long int sTime_;
    long unsigned int cuTime_;
    long int csTime_;
    long unsigned int total_;
};

class MvProcStat
{
public:
    MvProcStat(const std::string&, long);

    std::string vmSize() const { return vmSize_; }
    std::string vmRss() const { return vmRss_; }
    std::string vmShared() const { return vmShared_; }
    int cpu() const { return cpu_; }
    std::string elapsedTime();
    bool update();

protected:
    void readStartTime();
    int updateStats();
    int getCpuUsage(CpuTime*, CpuTime*);
    std::string byteToMbyte(unsigned long int);
    static void readUptime();
    static bool hasUptime() { return uptime_ > 0; }

    std::string procPath_;
    std::string sysPath_;
    std::string vmSize_;
    std::string vmRss_;
    std::string vmShared_;
    int cpu_;
    CpuTime prevCpuTime_;
    time_t startTime_;
    std::string lastElapsedTime_;
    static long pageSize_;
    static unsigned long uptime_;
};


class MvProcNodeObserver
{
public:
    MvProcNodeObserver() = default;
    virtual void infoChanged(MvProcNode*) {}
};

class MvProcNode
{
public:
    MvProcNode(const MvProcNode&) = delete;
    MvProcNode& operator=(const MvProcNode&) = delete;

    std::string name() { return name_; }
    std::string niceName() { return niceName_; }
    long pid() { return pid_; }
    std::string pidAsString() { return pidStr_; }
    std::string host() { return host_; }
    std::string user() { return user_; }
    long ref() { return ref_; }

    MvProcStat* stats() const { return stats_; }

    void killProc();
    virtual void debug() {}
    virtual void open() {}

    MvProcNode* childAt(int) const;
    int indexOfChild(MvProcNode*) const;
    MvProcNode* parent() const { return parent_; }
    int childrenCount() const { return static_cast<int>(children_.size()); }
    void setProcRequest(MvProcRequest*);
    MvProcRequest* procRequest() { return procRequest_; }

    static MvProcNode* root();
    static void add(long, request* r);
    static void remove(long, std::string);
    static void updateInfo();
    static void setObserver(MvProcNodeObserver* o) { observer_ = o; }
    static MvProcNode* find(long, std::string);
    static void addProcRequest(long, long, const std::string&, request*);
    static void assignProcRequest(long, long, const std::string&);
    static bool hasProcFs() { return hasProcFs_; }
    static void initHasProcFs(bool b) { hasProcFs_ = b; }

protected:
    MvProcNode(long, request* r);
    virtual ~MvProcNode();

    void queryNiceName();
    void setParent(MvProcNode*);
    void addChild(MvProcNode*);
    void removeChild(MvProcNode*);
    void updateStats();

    std::string name_;
    std::string niceName_;
    long ref_;
    long pid_;
    std::string pidStr_;
    std::string host_;
    std::string user_;
    MvProcStat* stats_;
    int killLevel_;
    MvProcRequest* procRequest_;

    MvProcNode* parent_;
    std::vector<MvProcNode*> children_;

    static MvProcNode* root_;
    static MvProcNodeObserver* observer_;
    static std::vector<MvProcNode*> items_;
    static std::vector<MvProcRequest*> procRequests_;
    static bool hasProcFs_;
};

class MvProcRequest
{
public:
    MvProcRequest(request*);
    ~MvProcRequest();

    long reqId() const { return reqId_; }
    const std::string& source() const { return source_; }
    const std::string& target() const { return target_; }
    const std::string& className() const { return className_; }
    const std::string& name() const { return name_; }
    const std::string& reqStr() const { return reqStr_; }

private:
    std::string source_;
    std::string target_;
    long reqId_;
    long sourceRef_;

    request* req_;
    std::string reqStr_;
    std::string className_;
    std::string name_;
};


class MvServiceInfo : public MvProcNode
{
public:
    MvServiceInfo(long, request*);
    ~MvServiceInfo();

private:
    int killLevel_;
    /*std::string host_;
    std::string user_;
    long    pid_;
    long    ref_;
    int     killLevel_;

    long memTotal_;
        long memFree_;
    long maxrss_;

    std::string vmSize_;
    std::string vmRss_;*/

    // void kill();
    void debug();
    void open();
};


class MvRequestInfo : public MvProcNode
{
public:
    MvRequestInfo(long, long, long, request*, int);
    ~MvRequestInfo();

private:
    request* req_;
    long to_;
    // void kill();
    // void debug();
    // void update(request*);
    void update(long t) { to_ = t; }
    void open() {}
};

/*class MvQWaitInfo : public MvProcNode
{
public:
    MvQWaitInfo(long,long,const char*,request*);
    ~MvQWaitInfo();

private:
        request *req_;
    //long from_;
    //char *to_;
    void kill()  {           }
    void debug() {           }
    void open() {};
};*/
