/*
    PIP - Platform Independent Primitives
    Introspection module
    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/>.
*/

#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)

#  include "piintrospection_server.h"

#  include "pichunkstream.h"
#  include "piintrospection_server_p.h"
#  include "piprocess.h"


PRIVATE_DEFINITION_START(PIIntrospectionServer)
	PIIntrospection::ProcessInfo process_info;
PRIVATE_DEFINITION_END(PIIntrospectionServer)


PIIntrospectionServer::PIIntrospectionServer(): PIPeer(genName()) {
	PRIVATE->process_info = PIIntrospection::getInfo();
}


PIIntrospectionServer::~PIIntrospectionServer() {
	// stop();
}


PIIntrospectionServer * PIIntrospectionServer::instance() {
	static PIIntrospectionServer ret;
	return &ret;
}


void PIIntrospectionServer::start(const PIString & server_name) {
	if (!sysmon) {
		sysmon = PISystemMonitor::Pool::instance()->getByPID(PIProcess::currentPID());
		if (sysmon) {
			piCoutObj << "using existing sysmon";
			CONNECT1(void, PIObject *, sysmon, deleted, this, sysmonDeleted);
		} else {
			piCoutObj << "create own sysmon";
			sysmon = new PISystemMonitor();
			sysmon->setProperty("__iserver__", true);
			sysmon->startOnSelf();
		}
	}
	changeName(server_name + genName());
	PIPeer::start();
}


void PIIntrospectionServer::stop() {
	PIPeer::stopAndWait();
	PIPeer::destroy();
	if (sysmon)
		if (sysmon->property("__iserver__").toBool()) delete sysmon;
	sysmon = nullptr;
}


PIString PIIntrospectionServer::genName() {
	randomize();
	return "__introspection__server_" + PIString::fromNumber(randomi() % 1000);
}


void PIIntrospectionServer::dataReceived(const PIString & from, const PIByteArray & data) {
	if (data.size() < 8) return;
	PIByteArray rba(data);
	uint _sign(0);
	rba >> _sign;
	if (_sign != PIIntrospection::sign) return;
	PIIntrospection::RequiredInfo ri;
	rba >> ri;
	PIChunkStream cs;
	if (ri.types[PIIntrospection::itInfo]) cs.add(PIIntrospection::itInfo, PIIntrospection::packInfo());
	if (ri.types[PIIntrospection::itProcStat]) {
		sysmon_mutex.lock();
		cs.add(PIIntrospection::itProcStat, PIIntrospection::packProcStat(sysmon));
		sysmon_mutex.unlock();
	}
	if (ri.types[PIIntrospection::itContainers]) cs.add(PIIntrospection::itContainers, PIIntrospection::packContainers());
	if (ri.types[PIIntrospection::itObjects]) cs.add(PIIntrospection::itObjects, PIIntrospection::packObjects());
	if (ri.types[PIIntrospection::itThreads]) cs.add(PIIntrospection::itThreads, PIIntrospection::packThreads());
	PIByteArray ba;
	ba << PIIntrospection::sign;
	ba.append(cs.data());
	send(from, ba);
}


void PIIntrospectionServer::sysmonDeleted() {
	PIMutexLocker _ml(sysmon_mutex);
	sysmon = nullptr;
}

#endif // PIP_INTROSPECTION
