#ifndef CDUTILS_CORE_H
#define CDUTILS_CORE_H

#include "cdutils_types.h"
#include "cdutils_protocol.h"
#include "piconnection.h"
#include "pidatatransfer.h"


namespace CDUtils {

class CDCore;


class __Core_Initializer__ {
public:
	__Core_Initializer__();
	~__Core_Initializer__();
	static int count_;
	static CDCore * __instance__;
};


class CDCore: public PIObject
{
	PIOBJECT(CDUtils::CDCore)
	friend class __Core_Initializer__;
	friend class CDSection;
	friend class Interface;
	friend class XInterface;
public:
	static CDCore * instance();
	static bool destroy();

	EVENT(K_Sended)
	EVENT(K_SendFail)
	EVENT(K_Received)
	EVENT(K_ReceiveFail)
	EVENT(K_ChangedGlobal)
	EVENT_HANDLER2(void, K_DirectChange, PIDeque<int>, path, PIString, value);

	EVENT(X_Sended)
	EVENT(X_SendFail)
	EVENT(X_Received)
	EVENT(X_ReceiveFail)
	EVENT(X_ChangedGlobal)
	EVENT1(X_ReceivedX, PIVector<PIDeque<int> >, pathes)

	EVENT(C_Sended)
	EVENT(C_SendFail)
	EVENT(C_Received)
	EVENT(C_ReceiveFail)
	EVENT(C_ChangedGlobal)

	EVENT(M_Sended)
	EVENT(M_SendFail)
	EVENT(M_Received)
	EVENT(M_ReceiveFail)
	EVENT(M_ChangedGlobal)
	EVENT3(M_Message, PIDeque<int>, path, int, type, PIString, msg)

	void cd_write    (CDSection * cd, PIIODevice * d);
	void cd_read     (CDSection * cd, PIIODevice * d);
	void cd_parse    (CDSection * cd, PIIODevice * d);
	void cd_update   (CDSection * cd, PIIODevice * d, UpdateModeFlags mode);
	void cd_calculate(CDSection * cd);
	void cd_send     (CDSection * cd, CDPacketType pt, bool direct = false);
	void send(CDType::cdT cdt);
	void request(CDType::cdT cdt);
	void initApp();
	void initPult();
	void init(const PIString & configuration, bool pult = false);
	void stop();
	void release();
	void startX(double freq = 20.);
	void stopX();
	void sendCommand(const CDType & c);
	void registerCHandler(const CDType & c, PIObject * o, Handler h);
	bool inProgress() {return sendt.isRunning();}
	void sendMessage(const CDType & m, MessageType mt, const PIString & msg);

	CDSection * root(CDType::cdT cdt);
	PIString typeLetter(CDType::cdT cdt);
	static PIString pathToString(const PIDeque<int> & p);
	static PIDeque<int> stringToPath(const PIString & p);

	static PIString pultConfig() {return PIString(pult_config);}
	static PIString appConfig() {return PIString(app_config);}

private:
	CDCore();
	~CDCore();
	EVENT_HANDLER2(void, dataReceived, const PIString &, from, const PIByteArray &, data);
	EVENT_HANDLER1(void, dtSendRequest, PIByteArray &, data);
	EVENT_HANDLER1(void, dtReceiveFinished, bool, ok);
	EVENT_HANDLER(void, sendThread);
	EVENT_HANDLER(void, xTimerTick);
	EVENT_HANDLER2(void, piCoutFinished, int, id, PIString*, buffer);
	void initRoot(CDSection * r);
	PIByteArray makeHeader(CDPacketType type, int session_id = 0) const;
	void sendDirect(PIByteArray & ba);
	void sendThreaded(PIByteArray & ba);
	void procReceivedPacket(PIByteArray & ba);
	void raiseChangedGlobal(CDType::cdT cdt);

	typedef PIPair<PIObject * , Handler> OHPair;

	static const char app_config[], pult_config[];
	PIConnection connection;
	PIDataTransfer datatr;
	PIByteArray send_data;
	PIThread sendt;
	PITimer x_timer;
	CDSection k_, x_, c_, m_;
	PIMutex x_mutex;
	PIVector<PIDeque<int> > x_selected;
	PIMap<PIString, OHPair> c_handlers;
	bool need_rebuild_x, x_pult_side;

};


static __Core_Initializer__ __Core_initializer__;

}

#endif // CDUTILS_CORE_H
