//..............................................................................
//
// IO Ninja IAS (In-App Scripting) API
//

import "log_Writer.jnc"
import "log_RecordCode.jnc"
import "std_Buffer.jnc"

//! \addtogroup api-ias
//! @{

//..............................................................................

// don't expose the whole log API -- otherwise, running in-app scripts gets
// kind of expensive (have to memorize all added converters/filters/etc and
// remove them all during clean up)

log.Writer* const g_logWriter;
void clearLog();

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

// basic session transport operations

bool errorcode connect();
void disconnect();

size_t errorcode transmit(
	void const* p,
	size_t size
);

size_t errorcode transmit(string_t text) {
	return transmit(text.m_p, text.m_length);
}

size_t getTransmitData(std.Buffer* buffer); // fetch contents of the "Transmit" pane

size_t errorcode receive(
	void* p,
	size_t size,
	uint_t timeout = -1 // return as much as received on timeout
);

bool errorcode unreceive( // put back to the receive buffer
	void const* p,
	size_t size
);

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

// higher level transmit/receive -- loop until the whole buffer is transferred

size_t errorcode transmitAll(
	void const* p,
	size_t size
) {
	void const* p0 = p;
	void const* end = p + size;
	while (p < end) {
		size_t blockSize = end - p;
		size_t result = transmit(p, blockSize);
		if (result < blockSize) { // buffer full, give it some time to flush
			sys.sleep(250);
			break;
		}

		p += result;
	}

	return p - p0;
}

size_t errorcode transmitAll(string_t text) {
	return transmitAll(text.m_p, text.m_length);
}

size_t errorcode receiveAll(
	void* p,
	size_t size
) {
	void const* p0 = p;
	void const* end = p + size;
	while (p < end) {
		size_t result = receive(p, end - p);
		p += result;
	}

	return p - p0;
}

size_t errorcode receiveAll(
	void* p,
	size_t size,
	uint_t timeout // return as much as was received on timeout
) {
	uint_t timeEnd = sys.getTimestamp() / 10000 + timeout; // in msec
	void const* p0 = p;
	void const* end = p + size;
	while (p < end) {
		uint_t time = sys.getTimestamp() / 10000;
		if (time >= timeEnd)
			break;

		size_t result = receive(p, end - p, timeEnd - time);
		if (!result) // timeout
			break;

		p += result;
	}

	return p - p0;
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

// dispatch iface provides access to session-specific functions

bool errorcode dispatch(
	uint_t code,
	variant_t in = null,
	variant_t* out = null
);

variant_t dispatchGet(
	uint_t code,
	variant_t in = null
) {
	variant_t result;
	dispatch(code, in, &result);
	return result;
}

namespace ias {

// sessions that support dispatch iface should normally derive from ias.Session

class Session {
	string_t const property m_id;
	string_t const property m_name;
	string_t const property m_description;
	string_t const property m_pluginDir;
}

} // namespace ias

//..............................................................................

// entry points for the script (beware the thread context!)

// IAS thread #1 (aka main thread)

[ prototype ]
void main();

// IAS thread #2 (aka event thread)
// - not called for direct `transmit()` invokations
// - kills the ability to track the actual (accepted) size

[ prototype ]
void pretransmit(
	void const* p,
	size_t size
);

// IAS thread #2 (aka event thread)

[ prototype ]
void onLogRecord(
	uint64_t timestamp,
	uint64_t recordCode,
	void const* p,
	size_t size
);

//..............................................................................

//! @}
