#include "cdutils_core.h"
#include "cdutils_parser.h"
#include "piconfig.h"
#include "piiobytearray.h"
#include "piiostring.h"
#include "pifile.h"

using namespace CDUtils;

const char CDCore::app_config[] =
		"include = cd_ip.conf\n\
		port_rec = 2\n\
		port_send = 1\n\
		[connection]\n\
		device.cd = peer://cd_app:cd_pult #s\n\
		[]\n\
		connectionmodel = AAAM2Xja7VXLTttAFD12QpsikKjUSixYlLbKEpIUtVIlVEfqhk2FWuiGRRolUYtoHgrmpYiv6IItf8AveMMH9E/YsG6Ph3sde5hGoQoblLGuPHfunTPjc49nADxDA110+LTYC7FrPCAPeAO+vZu+aX7c/8PGd45WCJC0OGcfT6FDnmfSTPtwhZFt3HjgDs/Qtu5jPbZHtI/x50XfIzMQbdwEolbg9INP4ku++myPaUtCHYRaT2j1ldIh3VP60/Qff8vSfXLu9BP6JX9K/0TVH6jqVe22P1X/fao/oddWu/paDs1vBf9Jv/EZ91clbyHqv7BL6sscDOd4v4WTqs6jzaHGJ8QJerxlpJSpdZ7IWFJvDW7I2JxZqIM62k6A57RZmMQGmlyrxdV+WGBnmR01mXPI267hBKwp4FeBeo9VPtssxyb7rzHg1B7T9nCMU45U8BZlWuVWtIcD/CRGOqtsbW09851tXsHN0UTlLIAdASjSXnLyLn+H7L2+xbGYvC63Ezqg543egkLmn8qnRF6USbM4Qp9godkhzI777Ne5bCIt/5UtGz2o/yGby0nKpjqmbOa1ynkjmyzIrzvIZUeBPjvlUmbh32EFJbGyJZhR8YcvlS+3TpjhqeWSyvUkpbI9plSWtcKLcsK05beOJVEnhaEFfHEH+RwpeMcpn1JKGqWMNOL+G6wZyahlpdVOtufKfbDS+guLke9O\n\
		";

const char CDCore::pult_config[] =
		"include = cd_ip.conf\n\
		port_rec = 1\n\
		port_send = 2\n\
		[connection]\n\
		device.cd = peer://cd_pult:cd_app #s\n\
		[]\n\
		connectionmodel = AAAM2Xja7VXLTttAFD12QpsikKjUSixYlLbKEpIUtVIlVEfqhk2FWuiGRRolUYtoHgrmpYiv6IItf8AveMMH9E/YsG6Ph3sde5hGoQoblLGuPHfunTPjc49nADxDA110+LTYC7FrPCAPeAO+vZu+aX7c/8PGd45WCJC0OGcfT6FDnmfSTPtwhZFt3HjgDs/Qtu5jPbZHtI/x50XfIzMQbdwEolbg9INP4ku++myPaUtCHYRaT2j1ldIh3VP60/Qff8vSfXLu9BP6JX9K/0TVH6jqVe22P1X/fao/oddWu/paDs1vBf9Jv/EZ91clbyHqv7BL6sscDOd4v4WTqs6jzaHGJ8QJerxlpJSpdZ7IWFJvDW7I2JxZqIM62k6A57RZmMQGmlyrxdV+WGBnmR01mXPI267hBKwp4FeBeo9VPtssxyb7rzHg1B7T9nCMU45U8BZlWuVWtIcD/CRGOqtsbW09851tXsHN0UTlLIAdASjSXnLyLn+H7L2+xbGYvC63Ezqg543egkLmn8qnRF6USbM4Qp9godkhzI777Ne5bCIt/5UtGz2o/yGby0nKpjqmbOa1ynkjmyzIrzvIZUeBPjvlUmbh32EFJbGyJZhR8YcvlS+3TpjhqeWSyvUkpbI9plSWtcKLcsK05beOJVEnhaEFfHEH+RwpeMcpn1JKGqWMNOL+G6wZyahlpdVOtufKfbDS+guLke9O\n\
		";


int __Core_Initializer__::count_(0);
CDCore * __Core_Initializer__::__instance__(0);


__Core_Initializer__::__Core_Initializer__() {
	count_++;
	//piCout << "try create Core" << count_;
	if (count_ > 1) return;
	//piCout << "create Core";
	__instance__ = new CDCore();
}


__Core_Initializer__::~__Core_Initializer__() {
	count_--;
	//piCout << "try delete Core" << count_;
	if (count_ > 0) return;
	//piCout << "delete Core";
	if (__instance__ != 0) {
		delete __instance__;
		__instance__ = 0;
	}
}




CDCore::CDCore() {
	setName("CDCore");
	datatr.setPacketSize(960);
	CONNECTU(&connection, dataReceivedEvent, this, dataReceived);
	/*PIString s(app_config);
	connection.configureFromString(&s);
	connection.start();*/
	initRoot(k_);

	CONNECTU(&datatr, sendRequest, this, dtSendRequest)
	CONNECTU(&datatr, receiveFinished, this, dtReceiveFinished)
	CONNECTU(&sendt, started, this, sendThread)
	CONNECTU(&x_timer, tickEvent, this, xTimerTick)

	/*k_[1] = KType(1, "123", "120+3", "comment");
	k_[2] = KType(2, "1", "2", "comm");
	k_[4] = KType(4, "-0.6", "-6/10", "mment");
	k_.section(10)[5] = KType(5, "8", "2*2*2", "88");
	k_.section(10).section(50)[100] = KType(100, "8", "2*2*2", "88");
	k_.section(11)[3] = KType(3, "1", "1", "88");
	k_.section(11)[4] = KType(4, "0", "0", "88");
	k_.section(11)[6] = KType(6, "0", "0", "88");*/
	//piCout << s;
}


CDCore::~CDCore() {
	datatr.stop();
	x_timer.stop();
	sendt.stop();
	sendt.waitForFinish(10);
	connection.stop();
}


void CDCore::k_write(PIIODevice * d) {
	k_.write(d, PIString());
}


void CDCore::k_read(PIIODevice * d) {
	PIConfig conf(d, PIIODevice::ReadOnly);
	k_.read(&(conf.rootEntry()));
	initRoot(k_);
	K_ChangedGlobal();
	/*PIVector<PIIODevice * > ds = connection.allDevices();
	piForeach(PIIODevice * d, ds) {
		if (d)
			piCoutObj << d->constructFullPath() << d->isOpened();
	}*/
}


void CDCore::k_parse(PIIODevice * d) {
	k_ = CDParser::parse(d, CDType::cdK);
	initRoot(k_);
	K_ChangedGlobal();
}


void CDCore::k_update(PIIODevice * d, UpdateModeFlags mode) {
	CDSection uk = k_;
	k_parse(d);
	/*bool kn = true;
	if (!uk.isEmpty())
		if (!uk.isSameStructure(k_)) {
			piCout << "ask for save names";
			K_KeepNamesRequest(&kn);
		}*/
	uk.update(k_, mode);
	//piCout << k_.count() << uk.count();
	k_ = uk;
	initRoot(k_);
	K_ChangedGlobal();
}


void CDCore::k_calculate() {
	k_.calculate();
	K_ChangedGlobal();
}


void CDCore::initApp() {
	init(appConfig());
}


void CDCore::initPult() {
	init(pultConfig());
}


void CDCore::init(const PIString & configuration) {
	PIString c = configuration;
	//piCoutObj << "init" << c;
	connection.stop();
	connection.removeAllDevices();
	connection.configureFromString(&c);
	connection.start();
}


void CDCore::startPing() {
	x_timer.start(1);
}


void CDUtils::CDCore::dataReceived(const PIString & from, const PIByteArray & data) {
//	piCoutObj << "dataReceived" << from << data.size();
	PIIODevice * d = connection.deviceByName("cd");
	if (d && d == connection.deviceByFullPath(from)) {
		if (data.size() >= sizeof(4)) {
			const uint sig = *((const uint*)(data.data()));
			if (sig == PIBaseTransfer::packetSignature()) datatr.received(data);
			else {
				CDPacketType pt = (CDPacketType)sig;
				switch(pt) {
					case CD_Ping:
						//piCoutObj << "ping";
						break;
					default: break;
				}
			}
		}

	}
}


CDCore * CDCore::instance() {
	/*static CDCore * ret = new CDCore();
	return ret;*/
	return __Core_Initializer__::__instance__;
}


void CDCore::K_Send() {
	piCoutObj << "K_Send";
	PIByteArray ba;
	PIIOByteArray iob(&ba, PIIODevice::ReadWrite);
	k_write(&iob);
	//piCoutObj << PIString(ba);
	if (sendt.isRunning()) {
		piCoutObj << "send in process...";
		return;
	}
	wheader.session_id = 0;
	wheader.type = CD_KSend;
	send_data.clear();
	send_data << wheader << ba;
	sendt.startOnce();
//	ios.close();
//	piCout << s;
	//PIByteArray ba = PIByteArray::fromString(s);
//	PIFile pf("k.txt", PIIODevice::ReadWrite);
//	pf.resize(0);
//	pf.write(s.toUTF8());
	//k_write(&pf);
	//piCout << pf.readLine();
}


void CDCore::K_Request() {
	piCoutObj << "K_Request";
	if (sendt.isRunning()) {
		piCoutObj << "send in process...";
		return;
	}
	wheader.session_id = 0;
	wheader.type = CD_KQuery;
	send_data.clear();
	send_data << wheader;
	sendt.startOnce();
}


void CDCore::sendThread() {
	bool ok = datatr.send(send_data);
	CDPacketType pt = (CDPacketType)wheader.type;
	switch (pt) {
	case CD_KSend:
		if (ok) K_Sended();
		else K_SendFail();
		break;
	case CD_KQuery:
		if (!ok) K_ReceiveFail();
		break;
	default: break;
	}
}


void CDCore::xTimerTick() {
	PacketHeader ph;
	ph.type = CD_Ping;
	PIByteArray ba;
	ba << ph;
	connection.writeByName("cd", ba);
}


void CDCore::initRoot(CDSection & r) {
	r.name = "__root__";
	r.alias = "root";
	r.makePath();
	r.calculate();
}


void CDCore::dtSendRequest(PIByteArray &data) {
	connection.writeByName("cd", data);
//	piCoutObj << "send" << data.size() << ret;
}


void CDCore::dtReceiveFinished(bool ok) {
	if (ok) {
		PIByteArray ba = datatr.data();
		PacketHeader p;
		ba >> p;
		CDPacketType pt = (CDPacketType)p.type;
		switch (pt) {
		case CD_KQuery:
			K_Send();
			break;
		case CD_KSend: {
			piCoutObj << "K received";
			PIByteArray k;
			ba >> k;
			k << uchar(0);
			PIString s = PIString::fromUTF8((const char *)k.data());
			PIIOString ios(&s);
			k_read(&ios);
			K_Received();
			} break;
		default: break;
		}
	}
}

