/*
	PIP - Platform Independent Primitives
	Process resource monitor
	Ivan Pelipenko peri4ko@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PISYSTEMMONITOR_H
#define PISYSTEMMONITOR_H

#include "pithread.h"
#include "pifile.h"

class PIP_EXPORT PISystemMonitor: public PIThread
{
	PIOBJECT_SUBCLASS(PISystemMonitor, PIThread)
	friend class PIIntrospectionServer;
public:
	PISystemMonitor();
	~PISystemMonitor();

#pragma pack(push, 1)
	struct PIP_EXPORT ProcessStatsFixed {
		ProcessStatsFixed();
		int ID;
		int parent_ID;
		int group_ID;
		int session_ID;
		int priority;
		int threads;
		ullong physical_memsize;
		ullong resident_memsize;
		ullong share_memsize;
		ullong virtual_memsize;
		ullong data_memsize;
		ullong ram_total;
		ullong ram_free;
		ullong ram_used;
		float cpu_load_system;
		float cpu_load_user;
	};

	struct PIP_EXPORT ThreadStatsFixed {
		ThreadStatsFixed();
		llong id;
		PISystemTime work_time;
		PISystemTime kernel_time;
		PISystemTime user_time;
		float cpu_load_kernel;
		float cpu_load_user;
	};
#pragma pack(pop)

	struct PIP_EXPORT ProcessStats: ProcessStatsFixed {
		void makeStrings();
		PIString exec_name;
		PIString state;
		PIString physical_memsize_readable;
		PIString resident_memsize_readable;
		PIString share_memsize_readable;
		PIString virtual_memsize_readable;
		PIString data_memsize_readable;
	};

	struct PIP_EXPORT ThreadStats: ThreadStatsFixed {
		PIString name;
		PIDateTime created;
	};

#ifndef FREERTOS
	bool startOnProcess(int pID, int interval_ms = 1000);
#endif
	bool startOnSelf(int interval_ms = 1000);
	void stop();
	
	int pID() const {return pID_;}
	ProcessStats statistic() const;
	PIVector<ThreadStats> threadsStatistic() const;
	void setStatistic(const ProcessStats & s);

	static ullong totalRAM();
	static ullong freeRAM();
	static ullong usedRAM();


private:
	void run();
	void gatherThread(llong id);
	float calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old);

	ProcessStats stat;
	PIVector<ThreadStats> cur_ts;
	PIMap<llong, ThreadStats> last_tm, cur_tm;
	PIMap<llong, PIString> tbid;
	mutable PIMutex stat_mutex;
	int pID_, page_size, cpu_count, cycle;
#ifndef FREERTOS
	PRIVATE_DECLARATION(PIP_EXPORT)
#endif

	class PIP_EXPORT Pool {
		friend class PISystemMonitor;
	public:
		static Pool * instance();
		PISystemMonitor * getByPID(int pID);
	private:
		void add(PISystemMonitor * sm);
		void remove(PISystemMonitor * sm);
		PIMap<int, PISystemMonitor*> sysmons;
		PIMutex mutex;
	};


};

inline PICout operator <<(PICout s, const PISystemMonitor::ThreadStats & v) {
	s.setControl(0, true);
	s << "ThreadInfo(\"" << v.name << "\", created " << v.created
	  << ", work " << v.work_time.toMilliseconds() << " ms"
	  << ", kernel " << v.kernel_time.toMilliseconds() << " ms"
	  << ", user " << v.user_time.toMilliseconds() << " ms"
	  << ")\n";
	s.restoreControl();
	return s;
}

PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ProcessStats & v);
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s,       PISystemMonitor::ProcessStats & v);
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ThreadStats & v);
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s,       PISystemMonitor::ThreadStats & v);

#endif // PISYSTEMMONITOR_H
