JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_deleteRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)

/*
 */

#undef IMPL

#include <WebCore/DOMException.h>
#include <WebCore/HTMLCollection.h>
#include <WebCore/HTMLElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLTableSectionElement.h>
#include <WebCore/JSExecState.h>

#include <wtf/RefPtr.h>
#include <wtf/GetPtr.h>

#include <WebCore/JavaDOMUtils.h>
#include <wtf/java/JavaEnv.h>

using namespace WebCore;

extern "C" {

#define IMPL (static_cast<HTMLTableSectionElement*>(jlong_to_ptr(peer)))

// Attributes
JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::alignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::alignAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChOffImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charoffAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChOffImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charoffAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getVAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::valignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setVAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::valignAttr, String(env, value));
}

JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getRowsImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLCollection>(env, WTF::getPtr(IMPL->rows()));
}

// Functions
JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_insertRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLElement>(env, WTF::getPtr(raiseOnDOMError(env, IMPL->insertRow(index))));
}

{
    WebCore::JSMainThreadNullState state;
    raiseOnDOMError(env, IMPL->deleteRow(index));
}

}


{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charAttr));
}

/*
 */

#undef IMPL

#include <WebCore/DOMException.h>
#include <WebCore/HTMLCollection.h>
#include <WebCore/HTMLElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLTableSectionElement.h>
#include <WebCore/JSExecState.h>

#include <wtf/RefPtr.h>
#include <wtf/GetPtr.h>

#include <WebCore/JavaDOMUtils.h>
#include <wtf/java/JavaEnv.h>

using namespace WebCore;

extern "C" {

#define IMPL (static_cast<HTMLTableSectionElement*>(jlong_to_ptr(peer)))

// Attributes
JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::alignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::alignAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChImpl(JNIEnv* env, jclass, jlong peer)

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChOffImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charoffAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChOffImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charoffAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getVAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::valignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setVAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::valignAttr, String(env, value));
}

JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getRowsImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLCollection>(env, WTF::getPtr(IMPL->rows()));
}

// Functions
JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_insertRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLElement>(env, WTF::getPtr(raiseOnDOMError(env, IMPL->insertRow(index))));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_deleteRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    raiseOnDOMError(env, IMPL->deleteRow(index));
}

}


/*
 */

#undef IMPL

#include <WebCore/DOMException.h>
#include <WebCore/HTMLCollection.h>
#include <WebCore/HTMLElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLTableSectionElement.h>
#include <WebCore/JSExecState.h>

#include <wtf/RefPtr.h>
#include <wtf/GetPtr.h>

#include <WebCore/JavaDOMUtils.h>
#include <wtf/java/JavaEnv.h>

using namespace WebCore;

extern "C" {

#define IMPL (static_cast<HTMLTableSectionElement*>(jlong_to_ptr(peer)))

// Attributes
JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::alignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::alignAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChOffImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState sta

    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charoffAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChOffImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charoffAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getVAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::valignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setVAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::valignAttr, String(env, value));
}

JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getRowsImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLCollection>(env, WTF::getPtr(IMPL->rows()));
}

// Functions
JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_insertRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLElement>(env, WTF::getPtr(raiseOnDOMError(env, IMPL->insertRow(index))));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_deleteRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    raiseOnDOMError(env, IMPL->deleteRow(index));
}

}


JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_insertRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLElement>(env, WTF::getPtr(raiseOnDOMError(env, IMPL->insertRow(index))));
}

/*
 */

#undef IMPL

#include <WebCore/DOMException.h>
#include <WebCore/HTMLCollection.h>
#include <WebCore/HTMLElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLTableSectionElement.h>
#include <WebCore/JSExecState.h>

#include <wtf/RefPtr.h>
#include <wtf/GetPtr.h>

#include <WebCore/JavaDOMUtils.h>
#include <wtf/java/JavaEnv.h>

using namespace WebCore;

extern "C" {

#define IMPL (static_cast<HTMLTableSectionElement*>(jlong_to_ptr(peer)))

// Attributes
JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::alignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::alignAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getChOffImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::charoffAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setChOffImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::charoffAttr, String(env, value));
}

JNIEXPORT jstring JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getVAlignImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<String>(env, IMPL->getAttribute(WebCore::HTMLNames::valignAttr));
}

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_setVAlignImpl(JNIEnv* env, jclass, jlong peer, jstring value)
{
    WebCore::JSMainThreadNullState state;
    IMPL->setAttributeWithoutSynchronization(WebCore::HTMLNames::valignAttr, String(env, value));
}

JNIEXPORT jlong JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_getRowsImpl(JNIEnv* env, jclass, jlong peer)
{
    WebCore::JSMainThreadNullState state;
    return JavaReturn<HTMLCollection>(env, WTF::getPtr(IMPL->rows()));
}

// Functions

JNIEXPORT void JNICALL Java_com_sun_webkit_dom_HTMLTableSectionElementImpl_deleteRowImpl(JNIEnv* env, jclass, jlong peer
    , jint index)
{
    WebCore::JSMainThreadNullState state;
    raiseOnDOMError(env, IMPL->deleteRow(index));
}

}


InNetAACStream::InNetAACStream(BaseProtocol *pProtocol,
		StreamsManager *pStreamsManager, string name)
: BaseInNetStream(pProtocol, pStreamsManager, ST_IN_NET_AAC, name)

/*
 *
 *  This file is part of crtmpserver.
 */

#ifdef HAS_PROTOCOL_MMS

#include "protocols/mms/innetaacstream.h"
#include "streaming/baseoutstream.h"
#include "streaming/streamstypes.h"

{
	_bytesCount = 0;
	_packetsCount = 0;
	_capabilities.Clear();
	_capabilities.audioCodecId = CODEC_AUDIO_UNKNOWN;
}

InNetAACStream::~InNetAACStream() {
}

bool InNetAACStream::IsCompatibleWithType(uint64_t type) {
	return (type == ST_OUT_NET_RTMP_4_TS)
			|| (type == ST_OUT_NET_RTP);
}

StreamCapabilities * InNetAACStream::GetCapabilities() {
	return &_capabilities;
}

void InNetAACStream::GetStats(Variant &info, uint32_t namespaceId) {
	BaseInNetStream::GetStats(info, namespaceId);
	info["audio"]["bytesCount"] = _bytesCount;
	info["audio"]["packetsCount"] = _packetsCount;
	info["audio"]["droppedPacketsCount"] = 0;
}

void InNetAACStream::ReadyForSend() {
	NYI;
}

void InNetAACStream::SignalOutStreamAttached(BaseOutStream *pOutStream) {
	NYI;
}

void InNetAACStream::SignalOutStreamDetached(BaseOutStream *pOutStream) {
	NYI;
}

bool InNetAACStream::SignalPlay(double &absoluteTimestamp, double &length) {
	NYIR;
}

bool InNetAACStream::SignalPause() {
	NYIR;
}

bool InNetAACStream::SignalResume() {
	return true;
}

bool InNetAACStream::SignalSeek(double &absoluteTimestamp) {
	return true;
}

bool InNetAACStream::SignalStop() {
	NYIR;
}

bool InNetAACStream::FeedData(uint8_t *pData, uint32_t dataLength,
		uint32_t processedLength, uint32_t totalLength,
		double absoluteTimestamp, bool isAudio) {
	_bytesCount += dataLength;
	_packetsCount++;
	if (dataLength == 0)
		return true;
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		if (!InitStreamCapabilities(pData, dataLength)) {
			FATAL("Unable to init stream capabilities");
			return false;
		}
	}
	LinkedListNode<BaseOutStream *> *pTemp = _pOutStreams;
	while (pTemp != NULL) {
		if (!pTemp->info->IsEnqueueForDelete()) {
			if (!pTemp->info->FeedData(pData, dataLength, processedLength, totalLength,
					absoluteTimestamp, isAudio)) {
				WARN("Unable to feed OS: %p", pTemp->info);
				pTemp->info->EnqueueForDelete();
				if (GetProtocol() == pTemp->info->GetProtocol()) {
					return false;
				}
			}
		}
		pTemp = pTemp->pPrev;
	}

	return true;
}

bool InNetAACStream::InitStreamCapabilities(uint8_t *pData, uint32_t dataLength) {
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		uint8_t mpegts2rtmpProfile[] = {
			1, 2, 3
		};

		BitArray codecSetup;
		//profile_index from MPEG-TS different from profile_index from RTMP
		//so we need a map
		uint8_t profile = pData[2] >> 6;
		codecSetup.PutBits<uint8_t > (mpegts2rtmpProfile[profile], 5);

		//frequence mapping is the same
		uint8_t sampling_frequency_index = (pData[2] >> 2)&0x0f;
		codecSetup.PutBits<uint8_t > (sampling_frequency_index, 4);

		//this could be an issue... AAC from RTMP only supports stereo
		//and we have mono in this file... Need to check out this one...
		codecSetup.PutBits<uint8_t > (2, 4);

		_capabilities.InitAudioAAC(GETIBPOINTER(codecSetup),
				GETAVAILABLEBYTESCOUNT(codecSetup));
	}
	return true;
}

#endif /* HAS_PROTOCOL_MMS */


/*
 *
 *  This file is part of crtmpserver.
 */

#ifdef HAS_PROTOCOL_MMS

#include "protocols/mms/innetaacstream.h"
#include "streaming/baseoutstream.h"
#include "streaming/streamstypes.h"

InNetAACStream::InNetAACStream(BaseProtocol *pProtocol,
		StreamsManager *pStreamsManager, string name)
: BaseInNetStream(pProtocol, pStreamsManager, ST_IN_NET_AAC, name) {
	_bytesCount = 0;
	_packetsCount = 0;
	_capabilities.Clear();
	_capabilities.audioCodecId = CODEC_AUDIO_UNKNOWN;
}

InNetAACStream::~InNetAACStream() {
}

bool InNetAACStream::IsCompatibleWithType(uint64_t type) {
	return (type == ST_OUT_NET_RTMP_4_TS)
			|| (type == ST_OUT_NET_RTP);
}

StreamCapabilities * InNetAACStream::GetCapabilities() {
	return &_capabilities;
}

void InNetAACStream::GetStats(Variant &info, uint32_t namespaceId) {
	BaseInNetStream::GetStats(info, namespaceId);
	info["audio"]["bytesCount"] = _bytesCount;
	info["audio"]["packetsCount"] = _packetsCount;
	info["audio"]["droppedPacketsCount"] = 0;
}

void InNetAACStream::ReadyForSend() {
	NYI;
}

void InNetAACStream::SignalOutStreamAttached(BaseOutStream *pOutStream) {
	NYI;
}

void InNetAACStream::SignalOutStreamDetached(BaseOutStream *pOutStream) {
	NYI;
}

bool InNetAACStream::SignalPlay(double &absoluteTimestamp, double &length) {
	NYIR;
}

bool InNetAACStream::SignalPause() {
	NYIR;
}

bool InNetAACStream::SignalResume()

bool InNetAACStream::SignalSeek(double &absoluteTimestamp) {
	return true;
}

bool InNetAACStream::SignalStop() {
	NYIR;
}

bool InNetAACStream::FeedData(uint8_t *pData, uint32_t dataLength,
		uint32_t processedLength, uint32_t totalLength,
		double absoluteTimestamp, bool isAudio) {
	_bytesCount += dataLength;
	_packetsCount++;
	if (dataLength == 0)
		return true;
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		if (!InitStreamCapabilities(pData, dataLength)) {
			FATAL("Unable to init stream capabilities");
			return false;
		}
	}
	LinkedListNode<BaseOutStream *> *pTemp = _pOutStreams;
	while (pTemp != NULL) {
		if (!pTemp->info->IsEnqueueForDelete()) {
			if (!pTemp->info->FeedData(pData, dataLength, processedLength, totalLength,
					absoluteTimestamp, isAudio)) {
				WARN("Unable to feed OS: %p", pTemp->info);
				pTemp->info->EnqueueForDelete();
				if (GetProtocol() == pTemp->info->GetProtocol()) {
					return false;
				}
			}
		}
		pTemp = pTemp->pPrev;
	}

	return true;
}

bool InNetAACStream::InitStreamCapabilities(uint8_t *pData, uint32_t dataLength) {
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		uint8_t mpegts2rtmpProfile[] = {
			1, 2, 3
		};

		BitArray codecSetup;
		//profile_index from MPEG-TS different from profile_index from RTMP
		//so we need a map
		uint8_t profile = pData[2] >> 6;
		codecSetup.PutBits<uint8_t > (mpegts2rtmpProfile[profile], 5);

		//frequence mapping is the same
		uint8_t sampling_frequency_index = (pData[2] >> 2)&0x0f;
		codecSetup.PutBits<uint8_t > (sampling_frequency_index, 4);

		//this could be an issue... AAC from RTMP only supports stereo
		//and we have mono in this file... Need to check out this one...
		codecSetup.PutBits<uint8_t > (2, 4);

		_capabilities.InitAudioAAC(GETIBPOINTER(codecSetup),
				GETAVAILABLEBYTESCOUNT(codecSetup));
	}
	return true;
}

#endif /* HAS_PROTOCOL_MMS */


/*
 *
 *  This file is part of crtmpserver.
 */

#ifdef HAS_PROTOCOL_MMS

#include "protocols/mms/innetaacstream.h"
#include "streaming/baseoutstream.h"
#include "streaming/streamstypes.h"

InNetAACStream::InNetAACStream(BaseProtocol *pProtocol,
		StreamsManager *pStreamsManager, string name)
: BaseInNetStream(pProtocol, pStreamsManager, ST_IN_NET_AAC, name) {
	_bytesCount = 0;
	_packetsCount = 0;
	_capabilities.Clear();
	_capabilities.audioCodecId = CODEC_AUDIO_UNKNOWN;
}

InNetAACStream::~InNetAACStream() {
}

bool InNetAACStream::IsCompatibleWithType(uint64_t type) {
	return (type == ST_OUT_NET_RTMP_4_TS)
			|| (type == ST_OUT_NET_RTP);
}

StreamCapabilities * InNetAACStream::GetCapabilities() {
	return &_capabilities;
}

void InNetAACStream::GetStats(Variant &info, uint32_t namespaceId) {
	BaseInNetStream::GetStats(info, namespaceId);
	info["audio"]["bytesCount"] = _bytesCount;
	info["audio"]["packetsCount"] = _packetsCount;
	info["audio"]["droppedPacketsCount"] = 0;
}

void InNetAACStream::ReadyForSend() {
	NYI;
}

void InNetAACStream::SignalOutStreamAttached(BaseOutStream *pOutStream) {
	NYI;
}

void InNetAACStream::SignalOutStreamDetached(BaseOutStream *pOutStream) {
	NYI;
}

bool InNetAACStream::SignalPlay(double &absoluteTimestamp, double &length) {
	NYIR;
}

bool InNetAACStream::SignalPause() {
	NYIR;
}

bool InNetAACStream::SignalResume() {
	return true;
}

bool InNetAACStream::SignalSeek(double &absoluteTimestamp) {
	return tru

}

bool InNetAACStream::SignalStop() {
	NYIR;
}

bool InNetAACStream::FeedData(uint8_t *pData, uint32_t dataLength,
		uint32_t processedLength, uint32_t totalLength,
		double absoluteTimestamp, bool isAudio) {
	_bytesCount += dataLength;
	_packetsCount++;
	if (dataLength == 0)
		return true;
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		if (!InitStreamCapabilities(pData, dataLength)) {
			FATAL("Unable to init stream capabilities");
			return false;
		}
	}
	LinkedListNode<BaseOutStream *> *pTemp = _pOutStreams;
	while (pTemp != NULL) {
		if (!pTemp->info->IsEnqueueForDelete()) {
			if (!pTemp->info->FeedData(pData, dataLength, processedLength, totalLength,
					absoluteTimestamp, isAudio)) {
				WARN("Unable to feed OS: %p", pTemp->info);
				pTemp->info->EnqueueForDelete();
				if (GetProtocol() == pTemp->info->GetProtocol()) {
					return false;
				}
			}
		}
		pTemp = pTemp->pPrev;
	}

	return true;
}

bool InNetAACStream::InitStreamCapabilities(uint8_t *pData, uint32_t dataLength) {
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		uint8_t mpegts2rtmpProfile[] = {
			1, 2, 3
		};

		BitArray codecSetup;
		//profile_index from MPEG-TS different from profile_index from RTMP
		//so we need a map
		uint8_t profile = pData[2] >> 6;
		codecSetup.PutBits<uint8_t > (mpegts2rtmpProfile[profile], 5);

		//frequence mapping is the same
		uint8_t sampling_frequency_index = (pData[2] >> 2)&0x0f;
		codecSetup.PutBits<uint8_t > (sampling_frequency_index, 4);

		//this could be an issue... AAC from RTMP only supports stereo
		//and we have mono in this file... Need to check out this one...
		codecSetup.PutBits<uint8_t > (2, 4);

		_capabilities.InitAudioAAC(GETIBPOINTER(codecSetup),
				GETAVAILABLEBYTESCOUNT(codecSetup));
	}
	return true;
}

#endif /* HAS_PROTOCOL_MMS */


while (pTemp != NULL) {
		if (!pTemp->info->IsEnqueueForDelete()) {
			if (!pTemp->info->FeedData(pData, dataLength, processedLength, totalLength,
					absoluteTimestamp, isAudio)) {
				WARN("Unable to feed OS: %p", pTemp->info);
				pTemp->info->EnqueueForDelete();
				if (GetProtocol() == pTemp->info->GetProtocol()) {
					return false;
				}
			}
		}
		pTemp = pTemp->pPrev;
	}

/*
 *
 *  This file is part of crtmpserver.
 */

#ifdef HAS_PROTOCOL_MMS

#include "protocols/mms/innetaacstream.h"
#include "streaming/baseoutstream.h"
#include "streaming/streamstypes.h"

InNetAACStream::InNetAACStream(BaseProtocol *pProtocol,
		StreamsManager *pStreamsManager, string name)
: BaseInNetStream(pProtocol, pStreamsManager, ST_IN_NET_AAC, name) {
	_bytesCount = 0;
	_packetsCount = 0;
	_capabilities.Clear();
	_capabilities.audioCodecId = CODEC_AUDIO_UNKNOWN;
}

InNetAACStream::~InNetAACStream() {
}

bool InNetAACStream::IsCompatibleWithType(uint64_t type) {
	return (type == ST_OUT_NET_RTMP_4_TS)
			|| (type == ST_OUT_NET_RTP);
}

StreamCapabilities * InNetAACStream::GetCapabilities() {
	return &_capabilities;
}

void InNetAACStream::GetStats(Variant &info, uint32_t namespaceId) {
	BaseInNetStream::GetStats(info, namespaceId);
	info["audio"]["bytesCount"] = _bytesCount;
	info["audio"]["packetsCount"] = _packetsCount;
	info["audio"]["droppedPacketsCount"] = 0;
}

void InNetAACStream::ReadyForSend() {
	NYI;
}

void InNetAACStream::SignalOutStreamAttached(BaseOutStream *pOutStream) {
	NYI;
}

void InNetAACStream::SignalOutStreamDetached(BaseOutStream *pOutStream) {
	NYI;
}

bool InNetAACStream::SignalPlay(double &absoluteTimestamp, double &length) {
	NYIR;
}

bool InNetAACStream::SignalPause() {
	NYIR;
}

bool InNetAACStream::SignalResume() {
	return true;
}

bool InNetAACStream::SignalSeek(double &absoluteTimestamp) {
	return true;
}

bool InNetAACStream::SignalStop() {
	NYIR;
}

bool InNetAACStream::FeedData(uint8_t *pData, uint32_t dataLength,
		uint32_t processedLength, uint32_t totalLength,
		double absoluteTimestamp, bool isAudio) {
	_bytesCount += dataLength;
	_packetsCount++;
	if (dataLength == 0)
		return true;
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		if (!InitStreamCapabilities(pData, dataLength)) {
			FATAL("Unable to init stream capabilities");
			return false;
		}
	}
	LinkedListNode<BaseOutStream *> *pTemp = _pOutStreams;

	return true;
}

bool InNetAACStream::InitStreamCapabilities(uint8_t *pData, uint32_t dataLength) {
	if (_capabilities.audioCodecId == CODEC_AUDIO_UNKNOWN) {
		uint8_t mpegts2rtmpProfile[] = {
			1, 2, 3
		};

		BitArray codecSetup;
		//profile_index from MPEG-TS different from profile_index from RTMP
		//so we need a map
		uint8_t profile = pData[2] >> 6;
		codecSetup.PutBits<uint8_t > (mpegts2rtmpProfile[profile], 5);

		//frequence mapping is the same
		uint8_t sampling_frequency_index = (pData[2] >> 2)&0x0f;
		codecSetup.PutBits<uint8_t > (sampling_frequency_index, 4);

		//this could be an issue... AAC from RTMP only supports stereo
		//and we have mono in this file... Need to check out this one...
		codecSetup.PutBits<uint8_t > (2, 4);

		_capabilities.InitAudioAAC(GETIBPOINTER(codecSetup),
				GETAVAILABLEBYTESCOUNT(codecSetup));
	}
	return true;
}

#endif /* HAS_PROTOCOL_MMS */


void InlineParamPack::addActor(const BaseProcLink& value, const sead::SafeString& key, s32 idx)

#include "KingSystem/ActorSystem/actAiParam.h"
#include <agl/Utils/aglParameter.h>
#include "KingSystem/ActorSystem/actActor.h"
#include "KingSystem/ActorSystem/actAiClassDef.h"
#include "KingSystem/ActorSystem/actAiInlineParam.h"

namespace ksys::act {
class BaseProcHandle;
}

namespace ksys::act::ai {

ParamPack::ParamPack() = default;

ParamPack::~ParamPack() {
    auto* param = mParams;
    while (param) {
        if (param->data) {
            switch (param->type) {
            case AIDefParamType::String:
                delete static_cast<sead::SafeString*>(param->data);
                break;
            case AIDefParamType::Int:
                delete static_cast<int*>(param->data);
                break;
            case AIDefParamType::Float:
                delete static_cast<float*>(param->data);
                break;
            case AIDefParamType::Vec3:
                delete static_cast<sead::Vector3f*>(param->data);
                break;
            case AIDefParamType::Bool:
                delete static_cast<bool*>(param->data);
                break;
            case AIDefParamType::AITreeVariablePointer:
                delete static_cast<void**>(param->data);
                break;
            case AIDefParamType::UInt:
                delete static_cast<u32*>(param->data);
                break;
            case AIDefParamType::MesTransceiverId:
                delete static_cast<MesTransceiverId*>(param->data);
                break;
            case AIDefParamType::BaseProcHandle:
                delete static_cast<BaseProcHandle**>(param->data);
                break;
            case AIDefParamType::Rail:
                delete static_cast<Rail**>(param->data);
                break;
            case AIDefParamType::BaseProcLink:
                delete static_cast<BaseProcLink*>(param->data);
                break;
            default:
                break;
            }
        }
        param = mParams->next;
        if (mParams)
            delete mParams;
        mParams = param;
    }
}

template <typename T>
T* ParamPack::getVariable(const sead::SafeString& key, AIDefParamType type, bool a4) const {
    const u32 hash = agl::utl::ParameterBase::calcHash(key);
    auto* param = mParams;
    if (!param)
        return nullptr;
    while (param->hash != hash || param->type != type) {
        param = param->next;
        if (!param)
            return nullptr;
    }
    if (a4)
        param->used = true;
    return static_cast<T*>(param->data);
}

bool ParamPack::load(const Actor& actor, const ParamNameTypePairs& pairs, s32 count,
                     sead::Heap* heap) {
    AIDef def;
    def.no_stop = false;
    def.trigger_action = false;
    def.dynamic_param_child = false;
    def._24b = false;
    def.num_params = 0;
    def.calc_timing = CalcTiming::AIAfter;

    for (s32 i = 0; i < pairs.count; ++i) {
        const auto& pair = pairs.pairs[i];
        if (pair.use_count < count) {
            def.param_names[def.num_params] = pair.name;
            def.param_types[def.num_params] = pair.type;
            def.param_values[def.num_params].vec3 = {0, 0, 0};
            def.param_values[def.num_params].variable_ptr = nullptr;
            ++def.num_params;
        }
    }

    return load(actor, def, heap, AIDefInstParamKind::Dynamic);
}

void* ParamPack::getAITreeVariablePointer(const sead::SafeString& key, AIDefParamType type,
                                          bool x) const {
    return getVariable<void>(key, type, x);
}

void ParamPack::copy(InlineParamPack* dest, bool x) const {
    for (auto* param = mParams; param; param = param->next) {
        if (!param->data || !param->used)
            continue;

        const s32 dest_idx = dest->findIndex(param->name, param->type);

        switch (param->type) {
        case AIDefParamType::String: {
            dest->addString(*static_cast<sead::SafeString*>(param->data), param->name, dest_idx);
            break;
        }
        case AIDefParamType::Int:
            dest->addInt(*static_cast<s32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Float:
            dest->addFloat(*static_cast<f32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Vec3:
            dest->addVec3(*static_cast<sead::Vector3f*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Bool:
            dest->addBool(*static_cast<bool*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::UInt:
            dest->addUInt(*static_cast<u32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::BaseProcLink:
            dest->addActor(*static_cast<BaseProcLink*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::MesTransceiverId:
            if (!x) {
                dest->addMesTransceiverId(*static_cast<MesTransceiverId*>(param->data), param->name,
                                          dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::BaseProcHandle:
            if (!x) {
                dest->addPointer(*static_cast<BaseProcHandle**>(param->data), param->name,
                                 AIDefParamType::BaseProcHandle, dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::Rail:
            dest->addPointer(*static_cast<Rail**>(param->data), param->name, AIDefParamType::Rail,
                             dest_idx);
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::AITreeVariablePointer:
        case AIDefParamType::Other:
            break;
        }
    }
}

void InlineParamPack::addString(const char* value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.cstr = value;
    param.type = AIDefParamType::String;
}

void InlineParamPack::addInt(s32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.i = value;
    param.type = AIDefParamType::Int;
}

void InlineParamPack::addFloat(f32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.f = value;
    param.type = AIDefParamType::Float;
}

void InlineParamPack::addVec3(const sead::Vector3f& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.vec3 = value;
    param.type = AIDefParamType::Vec3;
}

void InlineParamPack::addBool(bool value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.b = value;
    param.type = AIDefParamType::Bool;
}

void InlineParamPack::addUInt(u32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.u = value;
    param.type = AIDefParamType::UInt;
}

{
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink = value;
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::addMesTransceiverId(const MesTransceiverId& value,
                                          const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.mesTransceiverId = value;
    param.type = AIDefParamType::MesTransceiverId;
}

void ParamPack::getPairs(ParamNameTypePairs* pairs, bool update_use_count) const {
    for (auto* param = mParams; param; param = param->next) {
        if (param->data)
            pairs->addPair(param->type, param->name, update_use_count);
    }
}

void ParamNameTypePairs::addPair(AIDefParamType type, const sead::SafeString& name,
                                 bool update_use_count) {
    for (s32 i = 0; i < count; ++i) {
        auto& pair = pairs[i];
        if (pair.type == type && name == pair.name) {
            if (update_use_count)
                ++pair.use_count;
            return;
        }
    }

    if (count >= pairs.size())
        return;

    auto& pair = pairs[count];
    pair.type = type;
    pair.name = name.cstr();
    pair.use_count = 1;
    ++count;
}

bool ParamPack::getString(sead::SafeString* value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::SafeString>(key, AIDefParamType::String, false);
    if (!str)
        return false;
    *value = str->cstr();
    return true;
}

bool ParamPack::setString(const sead::SafeString& value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
    if (!str)
        return false;
    str->copy(value);
    return true;
}

bool ParamPack::getActor(BaseProc* proc, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    link->acquire(proc, false);
    return true;
}

bool ParamPack::setActor(const BaseProcLink& new_link, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    *link = new_link;
    return true;
}

bool ParamPack::load(const Actor& actor, const AIDef& def, sead::Heap* heap,
                     AIDefInstParamKind kind) {
    bool load_map_unit_params = false;
    bool used = false;

    if (kind == AIDefInstParamKind::AITree) {
        load_map_unit_params = false;
        used = true;
    } else if (kind == AIDefInstParamKind::MapUnit) {
        load_map_unit_params = def._24b == 0;
        used = true;
    }

    const auto& iter = actor.getMapObjIter();
    for (s32 i = 0; i < def.num_params; ++i) {
        const auto hash = agl::utl::ParameterBase::calcHash(def.param_names[i]);

        bool found = false;
        for (auto* entry = mParams; entry; entry = entry->next) {
            if (entry->hash == hash) {
                found = true;
                break;
            }
        }
        if (found)
            continue;

        // Otherwise, allocate a new entry.
        auto* entry = new (heap) Param;
        if (!entry)
            return false;
        entry->data = nullptr;
        entry->next = mParams;
        mParams = entry;
        switch (def.param_types[i]) {
        case AIDefParamType::String: {
            const char* value = def.param_values[i].str ? def.param_values[i].str : "";

            if (load_map_unit_params)
                iter.tryGetParamStringByKey(&value, def.param_names[i]);

            entry->data = new (heap) sead::FixedSafeString<80>(value);
            break;
        }
        case AIDefParamType::Int: {
            int value = def.param_values[i].i;
            if (load_map_unit_params)
                iter.tryGetParamIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) int(value);
            break;
        }
        case AIDefParamType::Float: {
            float value = def.param_values[i].f;
            if (load_map_unit_params)
                iter.tryGetParamFloatByKey(&value, def.param_names[i]);
            entry->data = new (heap) float(value);
            break;
        }
        case AIDefParamType::Vec3: {
            const auto& src = def.param_values[i].vec3;
            sead::Vector3f value{src.x, src.y, src.z};
            if (load_map_unit_params)
                iter.tryGetFloatArrayByKey(value.e.data(), def.param_names[i]);
            entry->data = new (heap) sead::Vector3f(value);
            break;
        }
        case AIDefParamType::Bool: {
            bool value = def.param_values[i].b;
            if (load_map_unit_params)
                iter.tryGetParamBoolByKey(&value, def.param_names[i]);
            entry->data = new (heap) bool(value);
            break;
        }
        case AIDefParamType::AITreeVariablePointer:
            entry->data = new (heap) void*();
            break;
        case AIDefParamType::UInt: {
            u32 value = def.param_values[i].u;
            if (load_map_unit_params)
                iter.tryGetParamUIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) u32(value);
            break;
        }
        case AIDefParamType::BaseProcLink:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcLink();
            break;
        case AIDefParamType::MesTransceiverId:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) MesTransceiverId();
            break;
        case AIDefParamType::BaseProcHandle:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcHandle*();
            break;
        case AIDefParamType::Rail:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) Rail*();
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::Other:
            break;
        }

        if (!entry->data)
            return false;

        entry->hash = hash;
        entry->name = def.param_names[i];
        entry->used = used;
        entry->_23 = def._24b;
        entry->type = def.param_types[i];
    }

    return true;
}

void InlineParamPack::addPointer(void* value, const sead::SafeString& key, AIDefParamType type,
                                 s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.ptr = value;
    param.type = type;
}

void InlineParamPack::acquireActor(BaseProc* proc, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink.acquire(proc, false);
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::copyToParamPack(ParamPack& pack) const {
    const u32 n = count >= 0x1F ? 0x1F : count;
    const InlineParam* param = params;
    for (u32 i = 0; i < n; ++i, ++param) {
        switch (param->type) {
        case AIDefParamType::String: {
            const sead::SafeString src = param->cstr;
            const sead::SafeString key = param->key;
            auto* dst = pack.getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
            if (dst)
                dst->copy(src);
            break;
        }
        case AIDefParamType::Int:
            pack.setVariable(param->key, AIDefParamType::Int, param->i);
            break;
        case AIDefParamType::Float:
            pack.setVariable(param->key, AIDefParamType::Float, param->f);
            break;
        case AIDefParamType::Vec3:
            if (auto* dst = pack.getVariable<sead::Vector3f>(param->key, AIDefParamType::Vec3)) {
                dst->x = param->vec3.x;
                dst->y = param->vec3.y;
                dst->z = param->vec3.z;
            }
            break;
        case AIDefParamType::Bool:
            pack.setVariable(param->key, AIDefParamType::Bool, param->b);
            break;
        case AIDefParamType::UInt:
            pack.setVariable(param->key, AIDefParamType::UInt, param->u);
            break;
        case AIDefParamType::BaseProcLink:
            pack.setVariable(param->key, AIDefParamType::BaseProcLink, param->baseProcLink);
            break;
        case AIDefParamType::MesTransceiverId:
            pack.setVariable(param->key, AIDefParamType::MesTransceiverId, param->mesTransceiverId);
            break;
        case AIDefParamType::BaseProcHandle: {
            auto* baseProcHandle = static_cast<BaseProcHandle*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::BaseProcHandle, baseProcHandle);
            break;
        }
        case AIDefParamType::Rail: {
            auto* rail = static_cast<Rail*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::Rail, rail);
            break;
        }
        default:
            break;
        }
    }
}

}  // namespace ksys::act::ai


{
    auto* str = getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
    if (!str)
        return false;
    str->copy(value);
    return true;
}

#include "KingSystem/ActorSystem/actAiParam.h"
#include <agl/Utils/aglParameter.h>
#include "KingSystem/ActorSystem/actActor.h"
#include "KingSystem/ActorSystem/actAiClassDef.h"
#include "KingSystem/ActorSystem/actAiInlineParam.h"

namespace ksys::act {
class BaseProcHandle;
}

namespace ksys::act::ai {

ParamPack::ParamPack() = default;

ParamPack::~ParamPack() {
    auto* param = mParams;
    while (param) {
        if (param->data) {
            switch (param->type) {
            case AIDefParamType::String:
                delete static_cast<sead::SafeString*>(param->data);
                break;
            case AIDefParamType::Int:
                delete static_cast<int*>(param->data);
                break;
            case AIDefParamType::Float:
                delete static_cast<float*>(param->data);
                break;
            case AIDefParamType::Vec3:
                delete static_cast<sead::Vector3f*>(param->data);
                break;
            case AIDefParamType::Bool:
                delete static_cast<bool*>(param->data);
                break;
            case AIDefParamType::AITreeVariablePointer:
                delete static_cast<void**>(param->data);
                break;
            case AIDefParamType::UInt:
                delete static_cast<u32*>(param->data);
                break;
            case AIDefParamType::MesTransceiverId:
                delete static_cast<MesTransceiverId*>(param->data);
                break;
            case AIDefParamType::BaseProcHandle:
                delete static_cast<BaseProcHandle**>(param->data);
                break;
            case AIDefParamType::Rail:
                delete static_cast<Rail**>(param->data);
                break;
            case AIDefParamType::BaseProcLink:
                delete static_cast<BaseProcLink*>(param->data);
                break;
            default:
                break;
            }
        }
        param = mParams->next;
        if (mParams)
            delete mParams;
        mParams = param;
    }
}

template <typename T>
T* ParamPack::getVariable(const sead::SafeString& key, AIDefParamType type, bool a4) const {
    const u32 hash = agl::utl::ParameterBase::calcHash(key);
    auto* param = mParams;
    if (!param)
        return nullptr;
    while (param->hash != hash || param->type != type) {
        param = param->next;
        if (!param)
            return nullptr;
    }
    if (a4)
        param->used = true;
    return static_cast<T*>(param->data);
}

bool ParamPack::load(const Actor& actor, const ParamNameTypePairs& pairs, s32 count,
                     sead::Heap* heap) {
    AIDef def;
    def.no_stop = false;
    def.trigger_action = false;
    def.dynamic_param_child = false;
    def._24b = false;
    def.num_params = 0;
    def.calc_timing = CalcTiming::AIAfter;

    for (s32 i = 0; i < pairs.count; ++i) {
        const auto& pair = pairs.pairs[i];
        if (pair.use_count < count) {
            def.param_names[def.num_params] = pair.name;
            def.param_types[def.num_params] = pair.type;
            def.param_values[def.num_params].vec3 = {0, 0, 0};
            def.param_values[def.num_params].variable_ptr = nullptr;
            ++def.num_params;
        }
    }

    return load(actor, def, heap, AIDefInstParamKind::Dynamic);
}

void* ParamPack::getAITreeVariablePointer(const sead::SafeString& key, AIDefParamType type,
                                          bool x) const {
    return getVariable<void>(key, type, x);
}

void ParamPack::copy(InlineParamPack* dest, bool x) const {
    for (auto* param = mParams; param; param = param->next) {
        if (!param->data || !param->used)
            continue;

        const s32 dest_idx = dest->findIndex(param->name, param->type);

        switch (param->type) {
        case AIDefParamType::String: {
            dest->addString(*static_cast<sead::SafeString*>(param->data), param->name, dest_idx);
            break;
        }
        case AIDefParamType::Int:
            dest->addInt(*static_cast<s32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Float:
            dest->addFloat(*static_cast<f32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Vec3:
            dest->addVec3(*static_cast<sead::Vector3f*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Bool:
            dest->addBool(*static_cast<bool*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::UInt:
            dest->addUInt(*static_cast<u32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::BaseProcLink:
            dest->addActor(*static_cast<BaseProcLink*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::MesTransceiverId:
            if (!x) {
                dest->addMesTransceiverId(*static_cast<MesTransceiverId*>(param->data), param->name,
                                          dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::BaseProcHandle:
            if (!x) {
                dest->addPointer(*static_cast<BaseProcHandle**>(param->data), param->name,
                                 AIDefParamType::BaseProcHandle, dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::Rail:
            dest->addPointer(*static_cast<Rail**>(param->data), param->name, AIDefParamType::Rail,
                             dest_idx);
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::AITreeVariablePointer:
        case AIDefParamType::Other:
            break;
        }
    }
}

void InlineParamPack::addString(const char* value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.cstr = value;
    param.type = AIDefParamType::String;
}

void InlineParamPack::addInt(s32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.i = value;
    param.type = AIDefParamType::Int;
}

void InlineParamPack::addFloat(f32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.f = value;
    param.type = AIDefParamType::Float;
}

void InlineParamPack::addVec3(const sead::Vector3f& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.vec3 = value;
    param.type = AIDefParamType::Vec3;
}

void InlineParamPack::addBool(bool value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.b = value;
    param.type = AIDefParamType::Bool;
}

void InlineParamPack::addUInt(u32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.u = value;
    param.type = AIDefParamType::UInt;
}

void InlineParamPack::addActor(const BaseProcLink& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink = value;
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::addMesTransceiverId(const MesTransceiverId& value,
                                          const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.mesTransceiverId = value;
    param.type = AIDefParamType::MesTransceiverId;
}

void ParamPack::getPairs(ParamNameTypePairs* pairs, bool update_use_count) const {
    for (auto* param = mParams; param; param = param->next) {
        if (param->data)
            pairs->addPair(param->type, param->name, update_use_count);
    }
}

void ParamNameTypePairs::addPair(AIDefParamType type, const sead::SafeString& name,
                                 bool update_use_count) {
    for (s32 i = 0; i < count; ++i) {
        auto& pair = pairs[i];
        if (pair.type == type && name == pair.name) {
            if (update_use_count)
                ++pair.use_count;
            return;
        }
    }

    if (count >= pairs.size())
        return;

    auto& pair = pairs[count];
    pair.type = type;
    pair.name = name.cstr();
    pair.use_count = 1;
    ++count;
}

bool ParamPack::getString(sead::SafeString* value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::SafeString>(key, AIDefParamType::String, false);
    if (!str)
        return false;
    *value = str->cstr();
    return true;
}

bool ParamPack::setString(const sead::SafeString& value, const sead::SafeString& key) const

bool ParamPack::getActor(BaseProc* proc, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    link->acquire(proc, false);
    return true;
}

bool ParamPack::setActor(const BaseProcLink& new_link, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    *link = new_link;
    return true;
}

bool ParamPack::load(const Actor& actor, const AIDef& def, sead::Heap* heap,
                     AIDefInstParamKind kind) {
    bool load_map_unit_params = false;
    bool used = false;

    if (kind == AIDefInstParamKind::AITree) {
        load_map_unit_params = false;
        used = true;
    } else if (kind == AIDefInstParamKind::MapUnit) {
        load_map_unit_params = def._24b == 0;
        used = true;
    }

    const auto& iter = actor.getMapObjIter();
    for (s32 i = 0; i < def.num_params; ++i) {
        const auto hash = agl::utl::ParameterBase::calcHash(def.param_names[i]);

        bool found = false;
        for (auto* entry = mParams; entry; entry = entry->next) {
            if (entry->hash == hash) {
                found = true;
                break;
            }
        }
        if (found)
            continue;

        // Otherwise, allocate a new entry.
        auto* entry = new (heap) Param;
        if (!entry)
            return false;
        entry->data = nullptr;
        entry->next = mParams;
        mParams = entry;
        switch (def.param_types[i]) {
        case AIDefParamType::String: {
            const char* value = def.param_values[i].str ? def.param_values[i].str : "";

            if (load_map_unit_params)
                iter.tryGetParamStringByKey(&value, def.param_names[i]);

            entry->data = new (heap) sead::FixedSafeString<80>(value);
            break;
        }
        case AIDefParamType::Int: {
            int value = def.param_values[i].i;
            if (load_map_unit_params)
                iter.tryGetParamIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) int(value);
            break;
        }
        case AIDefParamType::Float: {
            float value = def.param_values[i].f;
            if (load_map_unit_params)
                iter.tryGetParamFloatByKey(&value, def.param_names[i]);
            entry->data = new (heap) float(value);
            break;
        }
        case AIDefParamType::Vec3: {
            const auto& src = def.param_values[i].vec3;
            sead::Vector3f value{src.x, src.y, src.z};
            if (load_map_unit_params)
                iter.tryGetFloatArrayByKey(value.e.data(), def.param_names[i]);
            entry->data = new (heap) sead::Vector3f(value);
            break;
        }
        case AIDefParamType::Bool: {
            bool value = def.param_values[i].b;
            if (load_map_unit_params)
                iter.tryGetParamBoolByKey(&value, def.param_names[i]);
            entry->data = new (heap) bool(value);
            break;
        }
        case AIDefParamType::AITreeVariablePointer:
            entry->data = new (heap) void*();
            break;
        case AIDefParamType::UInt: {
            u32 value = def.param_values[i].u;
            if (load_map_unit_params)
                iter.tryGetParamUIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) u32(value);
            break;
        }
        case AIDefParamType::BaseProcLink:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcLink();
            break;
        case AIDefParamType::MesTransceiverId:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) MesTransceiverId();
            break;
        case AIDefParamType::BaseProcHandle:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcHandle*();
            break;
        case AIDefParamType::Rail:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) Rail*();
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::Other:
            break;
        }

        if (!entry->data)
            return false;

        entry->hash = hash;
        entry->name = def.param_names[i];
        entry->used = used;
        entry->_23 = def._24b;
        entry->type = def.param_types[i];
    }

    return true;
}

void InlineParamPack::addPointer(void* value, const sead::SafeString& key, AIDefParamType type,
                                 s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.ptr = value;
    param.type = type;
}

void InlineParamPack::acquireActor(BaseProc* proc, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink.acquire(proc, false);
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::copyToParamPack(ParamPack& pack) const {
    const u32 n = count >= 0x1F ? 0x1F : count;
    const InlineParam* param = params;
    for (u32 i = 0; i < n; ++i, ++param) {
        switch (param->type) {
        case AIDefParamType::String: {
            const sead::SafeString src = param->cstr;
            const sead::SafeString key = param->key;
            auto* dst = pack.getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
            if (dst)
                dst->copy(src);
            break;
        }
        case AIDefParamType::Int:
            pack.setVariable(param->key, AIDefParamType::Int, param->i);
            break;
        case AIDefParamType::Float:
            pack.setVariable(param->key, AIDefParamType::Float, param->f);
            break;
        case AIDefParamType::Vec3:
            if (auto* dst = pack.getVariable<sead::Vector3f>(param->key, AIDefParamType::Vec3)) {
                dst->x = param->vec3.x;
                dst->y = param->vec3.y;
                dst->z = param->vec3.z;
            }
            break;
        case AIDefParamType::Bool:
            pack.setVariable(param->key, AIDefParamType::Bool, param->b);
            break;
        case AIDefParamType::UInt:
            pack.setVariable(param->key, AIDefParamType::UInt, param->u);
            break;
        case AIDefParamType::BaseProcLink:
            pack.setVariable(param->key, AIDefParamType::BaseProcLink, param->baseProcLink);
            break;
        case AIDefParamType::MesTransceiverId:
            pack.setVariable(param->key, AIDefParamType::MesTransceiverId, param->mesTransceiverId);
            break;
        case AIDefParamType::BaseProcHandle: {
            auto* baseProcHandle = static_cast<BaseProcHandle*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::BaseProcHandle, baseProcHandle);
            break;
        }
        case AIDefParamType::Rail: {
            auto* rail = static_cast<Rail*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::Rail, rail);
            break;
        }
        default:
            break;
        }
    }
}

}  // namespace ksys::act::ai


#include "KingSystem/ActorSystem/actAiParam.h"
#include <agl/Utils/aglParameter.h>
#include "KingSystem/ActorSystem/actActor.h"
#include "KingSystem/ActorSystem/actAiClassDef.h"
#include "KingSystem/ActorSystem/actAiInlineParam.h"

namespace ksys::act {
class BaseProcHandle;
}

namespace ksys::act::ai {

ParamPack::ParamPack() = default;

ParamPack::~ParamPack() {
    auto* param = mParams;
    while (param) {
        if (param->data) {
            switch (param->type) {
            case AIDefParamType::String:
                delete static_cast<sead::SafeString*>(param->data);
                break;
            case AIDefParamType::Int:
                delete static_cast<int*>(param->data);
                break;
            case AIDefParamType::Float:
                delete static_cast<float*>(param->data);
                break;
            case AIDefParamType::Vec3:
                delete static_cast<sead::Vector3f*>(param->data);
                break;
            case AIDefParamType::Bool:
                delete static_cast<bool*>(param->data);
                break;
            case AIDefParamType::AITreeVariablePointer:
                delete static_cast<void**>(param->data);
                break;
            case AIDefParamType::UInt:
                delete static_cast<u32*>(param->data);
                break;
            case AIDefParamType::MesTransceiverId:
                delete static_cast<MesTransceiverId*>(param->data);
                break;
            case AIDefParamType::BaseProcHandle:
                delete static_cast<BaseProcHandle**>(param->data);
                break;
            case AIDefParamType::Rail:
                delete static_cast<Rail**>(param->data);
                break;
            case AIDefParamType::BaseProcLink:
                delete static_cast<BaseProcLink*>(param->data);
                break;
            default:
                break;
            }
        }
        param = mParams->next;
        if (mParams)
            delete mParams;
        mParams = param;
    }
}

template <typename T>
T* ParamPack::getVariable(const sead::SafeString& key, AIDefParamType type, bool a4) const {
    const u32 hash = agl::utl::ParameterBase::calcHash(key);
    auto* param = mParams;
    if (!param)
        return nullptr;
    while (param->hash != hash || param->type != type) {
        param = param->next;
        if (!param)
            return nullptr;
    }
    if (a4)
        param->used = true;
    return static_cast<T*>(param->data);
}

bool ParamPack::load(const Actor& actor, const ParamNameTypePairs& pairs, s32 count,
                     sead::Heap* heap) {
    AIDef def;
    def.no_stop = false;
    def.trigger_action = false;
    def.dynamic_param_child = false;
    def._24b = false;
    def.num_params = 0;
    def.calc_timing = CalcTiming::AIAfter;

    for (s32 i = 0; i < pairs.count; ++i) {
        const auto& pair = pairs.pairs[i];
        if (pair.use_count < count) {
            def.param_names[def.num_params] = pair.name;
            def.param_types[def.num_params] = pair.type;
            def.param_values[def.num_params].vec3 = {0, 0, 0};
            def.param_values[def.num_params].variable_ptr = nullptr;
            ++def.num_params;
        }
    }

    return load(actor, def, heap, AIDefInstParamKind::Dynamic);
}

void* ParamPack::getAITreeVariablePointer(const sead::SafeString& key, AIDefParamType type,
                                          bool x) const {
    return getVariable<void>(key, type, x);
}

void ParamPack::copy(InlineParamPack* dest, bool x) const {
    for (auto* param = mParams; param; param = param->next) {
        if (!param->data || !param->used)
            continue;

        const s32 dest_idx = dest->findIndex(param->name, param->type);

        switch (param->type) {
        case AIDefParamType::String: {
            dest->addString(*static_cast<sead::SafeString*>(param->data), param->name, dest_idx);
            break;
        }
        case AIDefParamType::Int:
            dest->addInt(*static_cast<s32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Float:
            dest->addFloat(*static_cast<f32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Vec3:
            dest->addVec3(*static_cast<sead::Vector3f*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Bool:
            dest->addBool(*static_cast<bool*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::UInt:
            dest->addUInt(*static_cast<u32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::BaseProcLink:
            dest->addActor(*static_cast<BaseProcLink*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::MesTransceiverId:
            if (!x) {
                dest->addMesTransceiverId(*static_cast<MesTransceiverId*>(param->data), param->name,
                                          dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::BaseProcHandle:
            if (!x) {
                dest->addPointer(*static_cast<BaseProcHandle**>(param->data), param->name,
                                 AIDefParamType::BaseProcHandle, dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::Rail:
            dest->addPointer(*static_cast<Rail**>(param->data), param->name, AIDefParamType::Rail,
                             dest_idx);
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::AITreeVariablePointer:
        case AIDefParamType::Other:
            break;
        }
    }
}

void InlineParamPack::addString(const char* value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.cstr = value;
    param.type = AIDefParamType::String;
}

void InlineParamPack::addInt(s32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.i = value;
    param.type = AIDefParamType::Int;
}

void InlineParamPack::addFloat(f32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.f = value;
    param.type = AIDefParamType::Float;
}

void InlineParamPack::addVec3(const sead::Vector3f& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.vec3 = value;
    param.type = AIDefParamType::Vec3;
}

void InlineParamPack::addBool(bool value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.b = value;
    param.type = AIDefParamType::Bool;
}

void InlineParamPack::addUInt(u32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    pa

    param.type = AIDefParamType::UInt;
}

void InlineParamPack::addActor(const BaseProcLink& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink = value;
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::addMesTransceiverId(const MesTransceiverId& value,
                                          const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.mesTransceiverId = value;
    param.type = AIDefParamType::MesTransceiverId;
}

void ParamPack::getPairs(ParamNameTypePairs* pairs, bool update_use_count) const {
    for (auto* param = mParams; param; param = param->next) {
        if (param->data)
            pairs->addPair(param->type, param->name, update_use_count);
    }
}

void ParamNameTypePairs::addPair(AIDefParamType type, const sead::SafeString& name,
                                 bool update_use_count) {
    for (s32 i = 0; i < count; ++i) {
        auto& pair = pairs[i];
        if (pair.type == type && name == pair.name) {
            if (update_use_count)
                ++pair.use_count;
            return;
        }
    }

    if (count >= pairs.size())
        return;

    auto& pair = pairs[count];
    pair.type = type;
    pair.name = name.cstr();
    pair.use_count = 1;
    ++count;
}

bool ParamPack::getString(sead::SafeString* value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::SafeString>(key, AIDefParamType::String, false);
    if (!str)
        return false;
    *value = str->cstr();
    return true;
}

bool ParamPack::setString(const sead::SafeString& value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
    if (!str)
        return false;
    str->copy(value);
    return true;
}

bool ParamPack::getActor(BaseProc* proc, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    link->acquire(proc, false);
    return true;
}

bool ParamPack::setActor(const BaseProcLink& new_link, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    *link = new_link;
    return true;
}

bool ParamPack::load(const Actor& actor, const AIDef& def, sead::Heap* heap,
                     AIDefInstParamKind kind) {
    bool load_map_unit_params = false;
    bool used = false;

    if (kind == AIDefInstParamKind::AITree) {
        load_map_unit_params = false;
        used = true;
    } else if (kind == AIDefInstParamKind::MapUnit) {
        load_map_unit_params = def._24b == 0;
        used = true;
    }

    const auto& iter = actor.getMapObjIter();
    for (s32 i = 0; i < def.num_params; ++i) {
        const auto hash = agl::utl::ParameterBase::calcHash(def.param_names[i]);

        bool found = false;
        for (auto* entry = mParams; entry; entry = entry->next) {
            if (entry->hash == hash) {
                found = true;
                break;
            }
        }
        if (found)
            continue;

        // Otherwise, allocate a new entry.
        auto* entry = new (heap) Param;
        if (!entry)
            return false;
        entry->data = nullptr;
        entry->next = mParams;
        mParams = entry;
        switch (def.param_types[i]) {
        case AIDefParamType::String: {
            const char* value = def.param_values[i].str ? def.param_values[i].str : "";

            if (load_map_unit_params)
                iter.tryGetParamStringByKey(&value, def.param_names[i]);

            entry->data = new (heap) sead::FixedSafeString<80>(value);
            break;
        }
        case AIDefParamType::Int: {
            int value = def.param_values[i].i;
            if (load_map_unit_params)
                iter.tryGetParamIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) int(value);
            break;
        }
        case AIDefParamType::Float: {
            float value = def.param_values[i].f;
            if (load_map_unit_params)
                iter.tryGetParamFloatByKey(&value, def.param_names[i]);
            entry->data = new (heap) float(value);
            break;
        }
        case AIDefParamType::Vec3: {
            const auto& src = def.param_values[i].vec3;
            sead::Vector3f value{src.x, src.y, src.z};
            if (load_map_unit_params)
                iter.tryGetFloatArrayByKey(value.e.data(), def.param_names[i]);
            entry->data = new (heap) sead::Vector3f(value);
            break;
        }
        case AIDefParamType::Bool: {
            bool value = def.param_values[i].b;
            if (load_map_unit_params)
                iter.tryGetParamBoolByKey(&value, def.param_names[i]);
            entry->data = new (heap) bool(value);
            break;
        }
        case AIDefParamType::AITreeVariablePointer:
            entry->data = new (heap) void*();
            break;
        case AIDefParamType::UInt: {
            u32 value = def.param_values[i].u;
            if (load_map_unit_params)
                iter.tryGetParamUIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) u32(value);
            break;
        }
        case AIDefParamType::BaseProcLink:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcLink();
            break;
        case AIDefParamType::MesTransceiverId:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) MesTransceiverId();
            break;
        case AIDefParamType::BaseProcHandle:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcHandle*();
            break;
        case AIDefParamType::Rail:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) Rail*();
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::Other:
            break;
        }

        if (!entry->data)
            return false;

        entry->hash = hash;
        entry->name = def.param_names[i];
        entry->used = used;
        entry->_23 = def._24b;
        entry->type = def.param_types[i];
    }

    return true;
}

void InlineParamPack::addPointer(void* value, const sead::SafeString& key, AIDefParamType type,
                                 s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.ptr = value;
    param.type = type;
}

void InlineParamPack::acquireActor(BaseProc* proc, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink.acquire(proc, false);
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::copyToParamPack(ParamPack& pack) const {
    const u32 n = count >= 0x1F ? 0x1F : count;
    const InlineParam* param = params;
    for (u32 i = 0; i < n; ++i, ++param) {
        switch (param->type) {
        case AIDefParamType::String: {
            const sead::SafeString src = param->cstr;
            const sead::SafeString key = param->key;
            auto* dst = pack.getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
            if (dst)
                dst->copy(src);
            break;
        }
        case AIDefParamType::Int:
            pack.setVariable(param->key, AIDefParamType::Int, param->i);
            break;
        case AIDefParamType::Float:
            pack.setVariable(param->key, AIDefParamType::Float, param->f);
            break;
        case AIDefParamType::Vec3:
            if (auto* dst = pack.getVariable<sead::Vector3f>(param->key, AIDefParamType::Vec3)) {
                dst->x = param->vec3.x;
                dst->y = param->vec3.y;
                dst->z = param->vec3.z;
            }
            break;
        case AIDefParamType::Bool:
            pack.setVariable(param->key, AIDefParamType::Bool, param->b);
            break;
        case AIDefParamType::UInt:
            pack.setVariable(param->key, AIDefParamType::UInt, param->u);
            break;
        case AIDefParamType::BaseProcLink:
            pack.setVariable(param->key, AIDefParamType::BaseProcLink, param->baseProcLink);
            break;
        case AIDefParamType::MesTransceiverId:
            pack.setVariable(param->key, AIDefParamType::MesTransceiverId, param->mesTransceiverId);
            break;
        case AIDefParamType::BaseProcHandle: {
            auto* baseProcHandle = static_cast<BaseProcHandle*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::BaseProcHandle, baseProcHandle);
            break;
        }
        case AIDefParamType::Rail: {
            auto* rail = static_cast<Rail*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::Rail, rail);
            break;
        }
        default:
            break;
        }
    }
}

}  // namespace ksys::act::ai


while (param->hash != hash || param->type != type) {
        param = param->next;
        if (!param)
            return nullptr;
    }

#include "KingSystem/ActorSystem/actAiParam.h"
#include <agl/Utils/aglParameter.h>
#include "KingSystem/ActorSystem/actActor.h"
#include "KingSystem/ActorSystem/actAiClassDef.h"
#include "KingSystem/ActorSystem/actAiInlineParam.h"

namespace ksys::act {
class BaseProcHandle;
}

namespace ksys::act::ai {

ParamPack::ParamPack() = default;

ParamPack::~ParamPack() {
    auto* param = mParams;
    while (param) {
        if (param->data) {
            switch (param->type) {
            case AIDefParamType::String:
                delete static_cast<sead::SafeString*>(param->data);
                break;
            case AIDefParamType::Int:
                delete static_cast<int*>(param->data);
                break;
            case AIDefParamType::Float:
                delete static_cast<float*>(param->data);
                break;
            case AIDefParamType::Vec3:
                delete static_cast<sead::Vector3f*>(param->data);
                break;
            case AIDefParamType::Bool:
                delete static_cast<bool*>(param->data);
                break;
            case AIDefParamType::AITreeVariablePointer:
                delete static_cast<void**>(param->data);
                break;
            case AIDefParamType::UInt:
                delete static_cast<u32*>(param->data);
                break;
            case AIDefParamType::MesTransceiverId:
                delete static_cast<MesTransceiverId*>(param->data);
                break;
            case AIDefParamType::BaseProcHandle:
                delete static_cast<BaseProcHandle**>(param->data);
                break;
            case AIDefParamType::Rail:
                delete static_cast<Rail**>(param->data);
                break;
            case AIDefParamType::BaseProcLink:
                delete static_cast<BaseProcLink*>(param->data);
                break;
            default:
                break;
            }
        }
        param = mParams->next;
        if (mParams)
            delete mParams;
        mParams = param;
    }
}

template <typename T>
T* ParamPack::getVariable(const sead::SafeString& key, AIDefParamType type, bool a4) const {
    const u32 hash = agl::utl::ParameterBase::calcHash(key);
    auto* param = mParams;
    if (!param)
        return nullptr;

    if (a4)
        param->used = true;
    return static_cast<T*>(param->data);
}

bool ParamPack::load(const Actor& actor, const ParamNameTypePairs& pairs, s32 count,
                     sead::Heap* heap) {
    AIDef def;
    def.no_stop = false;
    def.trigger_action = false;
    def.dynamic_param_child = false;
    def._24b = false;
    def.num_params = 0;
    def.calc_timing = CalcTiming::AIAfter;

    for (s32 i = 0; i < pairs.count; ++i) {
        const auto& pair = pairs.pairs[i];
        if (pair.use_count < count) {
            def.param_names[def.num_params] = pair.name;
            def.param_types[def.num_params] = pair.type;
            def.param_values[def.num_params].vec3 = {0, 0, 0};
            def.param_values[def.num_params].variable_ptr = nullptr;
            ++def.num_params;
        }
    }

    return load(actor, def, heap, AIDefInstParamKind::Dynamic);
}

void* ParamPack::getAITreeVariablePointer(const sead::SafeString& key, AIDefParamType type,
                                          bool x) const {
    return getVariable<void>(key, type, x);
}

void ParamPack::copy(InlineParamPack* dest, bool x) const {
    for (auto* param = mParams; param; param = param->next) {
        if (!param->data || !param->used)
            continue;

        const s32 dest_idx = dest->findIndex(param->name, param->type);

        switch (param->type) {
        case AIDefParamType::String: {
            dest->addString(*static_cast<sead::SafeString*>(param->data), param->name, dest_idx);
            break;
        }
        case AIDefParamType::Int:
            dest->addInt(*static_cast<s32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Float:
            dest->addFloat(*static_cast<f32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Vec3:
            dest->addVec3(*static_cast<sead::Vector3f*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::Bool:
            dest->addBool(*static_cast<bool*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::UInt:
            dest->addUInt(*static_cast<u32*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::BaseProcLink:
            dest->addActor(*static_cast<BaseProcLink*>(param->data), param->name, dest_idx);
            break;
        case AIDefParamType::MesTransceiverId:
            if (!x) {
                dest->addMesTransceiverId(*static_cast<MesTransceiverId*>(param->data), param->name,
                                          dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::BaseProcHandle:
            if (!x) {
                dest->addPointer(*static_cast<BaseProcHandle**>(param->data), param->name,
                                 AIDefParamType::BaseProcHandle, dest_idx);
                break;
            }
            [[fallthrough]];
        case AIDefParamType::Rail:
            dest->addPointer(*static_cast<Rail**>(param->data), param->name, AIDefParamType::Rail,
                             dest_idx);
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::AITreeVariablePointer:
        case AIDefParamType::Other:
            break;
        }
    }
}

void InlineParamPack::addString(const char* value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.cstr = value;
    param.type = AIDefParamType::String;
}

void InlineParamPack::addInt(s32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.i = value;
    param.type = AIDefParamType::Int;
}

void InlineParamPack::addFloat(f32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.f = value;
    param.type = AIDefParamType::Float;
}

void InlineParamPack::addVec3(const sead::Vector3f& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.vec3 = value;
    param.type = AIDefParamType::Vec3;
}

void InlineParamPack::addBool(bool value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.b = value;
    param.type = AIDefParamType::Bool;
}

void InlineParamPack::addUInt(u32 value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.u = value;
    param.type = AIDefParamType::UInt;
}

void InlineParamPack::addActor(const BaseProcLink& value, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink = value;
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::addMesTransceiverId(const MesTransceiverId& value,
                                          const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.mesTransceiverId = value;
    param.type = AIDefParamType::MesTransceiverId;
}

void ParamPack::getPairs(ParamNameTypePairs* pairs, bool update_use_count) const {
    for (auto* param = mParams; param; param = param->next) {
        if (param->data)
            pairs->addPair(param->type, param->name, update_use_count);
    }
}

void ParamNameTypePairs::addPair(AIDefParamType type, const sead::SafeString& name,
                                 bool update_use_count) {
    for (s32 i = 0; i < count; ++i) {
        auto& pair = pairs[i];
        if (pair.type == type && name == pair.name) {
            if (update_use_count)
                ++pair.use_count;
            return;
        }
    }

    if (count >= pairs.size())
        return;

    auto& pair = pairs[count];
    pair.type = type;
    pair.name = name.cstr();
    pair.use_count = 1;
    ++count;
}

bool ParamPack::getString(sead::SafeString* value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::SafeString>(key, AIDefParamType::String, false);
    if (!str)
        return false;
    *value = str->cstr();
    return true;
}

bool ParamPack::setString(const sead::SafeString& value, const sead::SafeString& key) const {
    auto* str = getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
    if (!str)
        return false;
    str->copy(value);
    return true;
}

bool ParamPack::getActor(BaseProc* proc, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    link->acquire(proc, false);
    return true;
}

bool ParamPack::setActor(const BaseProcLink& new_link, const sead::SafeString& key) const {
    auto* link = getVariable<BaseProcLink>(key, AIDefParamType::BaseProcLink);
    if (!link)
        return false;
    *link = new_link;
    return true;
}

bool ParamPack::load(const Actor& actor, const AIDef& def, sead::Heap* heap,
                     AIDefInstParamKind kind) {
    bool load_map_unit_params = false;
    bool used = false;

    if (kind == AIDefInstParamKind::AITree) {
        load_map_unit_params = false;
        used = true;
    } else if (kind == AIDefInstParamKind::MapUnit) {
        load_map_unit_params = def._24b == 0;
        used = true;
    }

    const auto& iter = actor.getMapObjIter();
    for (s32 i = 0; i < def.num_params; ++i) {
        const auto hash = agl::utl::ParameterBase::calcHash(def.param_names[i]);

        bool found = false;
        for (auto* entry = mParams; entry; entry = entry->next) {
            if (entry->hash == hash) {
                found = true;
                break;
            }
        }
        if (found)
            continue;

        // Otherwise, allocate a new entry.
        auto* entry = new (heap) Param;
        if (!entry)
            return false;
        entry->data = nullptr;
        entry->next = mParams;
        mParams = entry;
        switch (def.param_types[i]) {
        case AIDefParamType::String: {
            const char* value = def.param_values[i].str ? def.param_values[i].str : "";

            if (load_map_unit_params)
                iter.tryGetParamStringByKey(&value, def.param_names[i]);

            entry->data = new (heap) sead::FixedSafeString<80>(value);
            break;
        }
        case AIDefParamType::Int: {
            int value = def.param_values[i].i;
            if (load_map_unit_params)
                iter.tryGetParamIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) int(value);
            break;
        }
        case AIDefParamType::Float: {
            float value = def.param_values[i].f;
            if (load_map_unit_params)
                iter.tryGetParamFloatByKey(&value, def.param_names[i]);
            entry->data = new (heap) float(value);
            break;
        }
        case AIDefParamType::Vec3: {
            const auto& src = def.param_values[i].vec3;
            sead::Vector3f value{src.x, src.y, src.z};
            if (load_map_unit_params)
                iter.tryGetFloatArrayByKey(value.e.data(), def.param_names[i]);
            entry->data = new (heap) sead::Vector3f(value);
            break;
        }
        case AIDefParamType::Bool: {
            bool value = def.param_values[i].b;
            if (load_map_unit_params)
                iter.tryGetParamBoolByKey(&value, def.param_names[i]);
            entry->data = new (heap) bool(value);
            break;
        }
        case AIDefParamType::AITreeVariablePointer:
            entry->data = new (heap) void*();
            break;
        case AIDefParamType::UInt: {
            u32 value = def.param_values[i].u;
            if (load_map_unit_params)
                iter.tryGetParamUIntByKey(&value, def.param_names[i]);
            entry->data = new (heap) u32(value);
            break;
        }
        case AIDefParamType::BaseProcLink:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcLink();
            break;
        case AIDefParamType::MesTransceiverId:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) MesTransceiverId();
            break;
        case AIDefParamType::BaseProcHandle:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) BaseProcHandle*();
            break;
        case AIDefParamType::Rail:
            if (kind == AIDefInstParamKind::Dynamic)
                entry->data = new (heap) Rail*();
            break;
        case AIDefParamType::Tree:
        case AIDefParamType::Other:
            break;
        }

        if (!entry->data)
            return false;

        entry->hash = hash;
        entry->name = def.param_names[i];
        entry->used = used;
        entry->_23 = def._24b;
        entry->type = def.param_types[i];
    }

    return true;
}

void InlineParamPack::addPointer(void* value, const sead::SafeString& key, AIDefParamType type,
                                 s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.ptr = value;
    param.type = type;
}

void InlineParamPack::acquireActor(BaseProc* proc, const sead::SafeString& key, s32 idx) {
    auto& param = getParam(idx);
    param.key = key.cstr();
    param.baseProcLink.acquire(proc, false);
    param.type = AIDefParamType::BaseProcLink;
}

void InlineParamPack::copyToParamPack(ParamPack& pack) const {
    const u32 n = count >= 0x1F ? 0x1F : count;
    const InlineParam* param = params;
    for (u32 i = 0; i < n; ++i, ++param) {
        switch (param->type) {
        case AIDefParamType::String: {
            const sead::SafeString src = param->cstr;
            const sead::SafeString key = param->key;
            auto* dst = pack.getVariable<sead::BufferedSafeString>(key, AIDefParamType::String);
            if (dst)
                dst->copy(src);
            break;
        }
        case AIDefParamType::Int:
            pack.setVariable(param->key, AIDefParamType::Int, param->i);
            break;
        case AIDefParamType::Float:
            pack.setVariable(param->key, AIDefParamType::Float, param->f);
            break;
        case AIDefParamType::Vec3:
            if (auto* dst = pack.getVariable<sead::Vector3f>(param->key, AIDefParamType::Vec3)) {
                dst->x = param->vec3.x;
                dst->y = param->vec3.y;
                dst->z = param->vec3.z;
            }
            break;
        case AIDefParamType::Bool:
            pack.setVariable(param->key, AIDefParamType::Bool, param->b);
            break;
        case AIDefParamType::UInt:
            pack.setVariable(param->key, AIDefParamType::UInt, param->u);
            break;
        case AIDefParamType::BaseProcLink:
            pack.setVariable(param->key, AIDefParamType::BaseProcLink, param->baseProcLink);
            break;
        case AIDefParamType::MesTransceiverId:
            pack.setVariable(param->key, AIDefParamType::MesTransceiverId, param->mesTransceiverId);
            break;
        case AIDefParamType::BaseProcHandle: {
            auto* baseProcHandle = static_cast<BaseProcHandle*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::BaseProcHandle, baseProcHandle);
            break;
        }
        case AIDefParamType::Rail: {
            auto* rail = static_cast<Rail*>(param->ptr);
            pack.setVariable(param->key, AIDefParamType::Rail, rail);
            break;
        }
        default:
            break;
        }
    }
}

}  // namespace ksys::act::ai


#include <iostream>
#include "pinocchio/utils/timer.hpp"
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <Eigen/StdVector>

using namespace Eigen;

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaternion<double>)

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,1,1,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,2,2,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,3,3,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,4,4,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,5,5,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,6,6,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,7,7,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,8,8,RowMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,9,9,RowMajor>)

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,1,1,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,2,2,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,3,3,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,4,4,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,5,5,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,6,6,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,7,7,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,8,8,ColMajor>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,9,9,ColMajor>)

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,2,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,3,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,4,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,5,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,6,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,7,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,8,1>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix<double,9,1>)

template<int NBT>
void checkQuaternionToMatrix(std::string label)
{

  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);

  /* Random pre-initialization of all matrices in the stack. */
  std::vector< Quaterniond > q1s     (NBT);
  std::vector< Matrix3d > R3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      q1s[i]     = Quaterniond(Vector4d::Random()).normalized();
      R3s[i]     = Matrix3d::Random();
    }

  /* Timed product. */
  timer.tic();
  SMOOTH(NBT)
  {
    R3s[_smooth] = q1s[_smooth].toRotationMatrix();
  }

  std::cout << label << " = \t\t" ; timer.toc(std::cout,NBT);
}

template<int NBT>
void checkQuaternion(std::string label)
{

  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);

  /* Random pre-initialization of all matrices in the stack. */
  std::vector< Quaterniond > q1s     (NBT);
  std::vector< Vector3d > v2s     (NBT);
  std::vector< Vector3d > v3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      q1s[i]     = Quaterniond(Vector4d::Random()).normalized();
      v2s[i]     = Vector3d::Random();
      v3s[i]     = Vector3d::Random();
    }

  /* Timed product. */
  timer.tic();
  SMOOTH(NBT)
  {
    v3s[_smooth] = q1s[_smooth]*v2s[_smooth];
  }

  std::cout << label << " = \t\t" ; timer.toc(std::cout,NBT);
}

template<int NBT>
void checkQuaternionQuaternion(std::string label)
{

  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);

  /* Random pre-initialization of all matrices in the stack. */
  std::vector< Quaterniond > q1s     (NBT);
  std::vector< Quaterniond > q2s     (NBT);
  std::vector< Quaterniond > q3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      q1s[i]     = Quaterniond(Vector4d::Random()).normalized();
      q2s[i]     = Quaterniond(Vector4d::Random()).normalized();
      q3s[i]     = Quaterniond(Vector4d::Random()).normalized();
    }

  /* Timed product. */
  timer.tic();
  SMOOTH(NBT)
  {
    q3s[_smooth] = q1s[_smooth]*q2s[_smooth];
  }

  std::cout << label << " = \t\t" ; timer.toc(std::cout,NBT);
}

template<int NBT>
void checkQuaternionD(std::string label)
{

  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);

  /* Random pre-initialization of all matrices in the stack. */
  std::vector< Quaterniond > q1s     (NBT);
  std::vector< VectorXd > v2s     (NBT);
  std::vector< VectorXd > v3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      q1s[i]     = Quaterniond(Vector4d::Random()).normalized();
      v2s[i]     = VectorXd::Random(3);
      v3s[i]     = VectorXd::Random(3);
    }

  /* Timed product. */
  timer.tic();
  SMOOTH(NBT)
  {
    v3s[_smooth] = q1s[_smooth]*v2s[_smooth];
  }

  std::cout << label << " = \t\t" ; timer.toc(std::cout,NBT);
}

template<int MSIZE,int NBT>
void checkMatrix(std::string label)
{
  /* Row/Col organization of the three matrices M3=M1*M2 */
  #define RC1 RowMajor
  #define RC2 RowMajor
  #define RC3 RowMajor

  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);

  /* Random pre-initialization of all matrices in the stack. */
  std::vector< Matrix<double,MSIZE,MSIZE,RC1> > R1s     (NBT);
  std::vector< Matrix<double,MSIZE,MSIZE,RC2> > R2s     (NBT);
  std::vector< Matrix<double,MSIZE,MSIZE,RC3> > R3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      R1s[i]     = Matrix<double,MSIZE,MSIZE,RC1>::Random();
      R2s[i]     = Matrix<double,MSIZE,MSIZE,RC2>::Random();
      R3s[i]     = Matrix<double,MSIZE,MSIZE,RC3>::Random();
    }

  /* Timed product. */
  timer.tic();
  SMOOTH(NBT)
  {
    R3s[_smooth] = R1s[_smooth]*R2s[_smooth];
  }

  std::cout << label << " = \t\t" ; timer.toc(std::cout,NBT);
}

template<int MSIZE,int NBT>
void checkVector(std::string label)
{
  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);
  std::vector< Matrix<double,MSIZE,MSIZE> > R1s     (NBT);
  std::vector< Matrix<double,MSIZE,1> > v2s     (NBT);
  std::vector< Matrix<double,MSIZE,1> > v3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      R1s[i]     = Matrix<double,MSIZE,MSIZE>::Random();
      v2s[i]     = Matrix<double,MSIZE,1>::Random();
      v3s[i]     = Matrix<double,MSIZE,1>::Random();
    }

   timer.tic();
   SMOOTH(NBT)
    {
      v3s[_smooth] = R1s[_smooth]*v2s[_smooth];
    }

   std::cout << label << " = \t\t"; timer.toc(std::cout,NBT);
}

template<int NBT>
void checkDMatrix(int MSIZE,std::string label)
{
  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);
  std::vector< MatrixXd > R1s     (NBT);
  std::vector< MatrixXd > R2s     (NBT);
  std::vector< MatrixXd > R3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      R1s[i]     = MatrixXd::Random(MSIZE,MSIZE);
      R2s[i]     = MatrixXd::Random(MSIZE,MSIZE);
      R3s[i]     = MatrixXd::Random(MSIZE,MSIZE);
    }

   timer.tic();
   SMOOTH(NBT)
    {
      R3s[_smooth] = R1s[_smooth]*R2s[_smooth];
    }

   std::cout << label << " = \t\t"; timer.toc(std::cout,NBT);
}

template<int NBT>
void checkDVector(int MSIZE,std::string label)
{
  using namespace Eigen;

  PinocchioTicToc timer(PinocchioTicToc::NS);
  std::vector< MatrixXd > R1s     (NBT);
  std::vector< MatrixXd > v2s     (NBT);
  std::vector< MatrixXd > v3s     (NBT);
  for(size_t i=0;i<NBT;++i)
    {
      R1s[i]     = MatrixXd::Random(MSIZE,MSIZE);
      v2s[i]     = MatrixXd::Random(MSIZE,1);
      v3s[i]     = MatrixXd::Random(MSIZE,1);
    }

   timer.tic();

{
      v3s[_smooth] = R1s[_smooth]*v2s[_smooth];
    }

   std::cout << label << " = \t\t"; timer.toc(std::cout,NBT);
}

int main()
{

  #ifdef NDEBUG
  const int NBT = 1000*1000;
  #else
    const int NBT = 1;
    std::cout << "(the time score in debug mode is not relevant) " << std::endl;
  #endif
    checkQuaternion<NBT>(  "quaternion-vector static ");
    checkQuaternionD<NBT>(  "quaternion-vector dynamic");
    checkQuaternionQuaternion<NBT>(  "quaternion-quaternion    ");
    checkQuaternionToMatrix<NBT>(  "quaternion->matrix static");
    std::cout << std::endl;

    checkVector<3,NBT> (  "matrix-vector static  3x3");
    checkDVector<NBT>  (3,"matrix-vector dynamic 3x3");
    checkMatrix<3,NBT> (  "matrix-matrix static  3x3");
    checkDMatrix<NBT>  (3,"matrix-matrix dynamic 3x3");
    std::cout << std::endl;

    checkVector<4,NBT> (  "matrix-vector static  4x4");
    checkDVector<NBT>  (4,"matrix-vector dynamic 4x4");
    checkMatrix<4,NBT> (  "matrix-matrix static  4x4");
    checkDMatrix<NBT>  (4,"matrix-matrix dynamic 4x4");
    std::cout << std::endl;

    std::cout << "--" << std::endl;
  return 0;
}