/*
  *
  *
  * If you modify this Program, or any covered work, by linking or combining
  * it with OpenSSL (or a modified version of that library), containing parts
  * of this Program grant you additional permission to convey the resulting work.
  *
  */

#include "jconf.h"
#include "console.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
#define strcasecmp _stricmp
#include <intrin.h>
#else
#include <cpuid.h>
#endif

#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "jext.h"
#include "console.h"

using namespace rapidjson;

/*
 * This enum needs to match index in oConfigValues, otherwise we will get a runtime error
 */
enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx,
	bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
	iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
	bDaemonMode, sOutputFile, iHttpdPort, bPreferIpv4 };

struct configVal {
	configEnum iName;
	const char* sName;
	Type iType;
};

//Same order as in configEnum, as per comment above
configVal oConfigValues[] = {
	{ iGpuThreadNum, "gpu_thread_num", kNumberType },
	{ aGpuThreadsConf, "gpu_threads_conf", kArrayType },
	{ iPlatformIdx, "platform_index", kNumberType },
	{ bTlsMode, "use_tls", kTrueType },
	{ bTlsSecureAlgo, "tls_secure_algo", kTrueType },
	{ sTlsFingerprint, "tls_fingerprint", kStringType },
	{ sPoolAddr, "pool_address", kStringType },
	{ sWalletAddr, "wallet_address", kStringType },
	{ sPoolPwd, "pool_password", kStringType },
	{ iCallTimeout, "call_timeout", kNumberType },
	{ iNetRetry, "retry_time", kNumberType },
	{ iGiveUpLimit, "giveup_limit", kNumberType },
	{ iVerboseLevel, "verbose_level", kNumberType },
	{ iAutohashTime, "h_print_time", kNumberType },
	{ bDaemonMode, "daemon_mode", kTrueType },
	{ sOutputFile, "output_file", kStringType },
	{ iHttpdPort, "httpd_port", kNumberType },
	{ bPreferIpv4, "prefer_ipv4", kTrueType }
};

constexpr size_t iConfigCnt = (sizeof(oConfigValues)/sizeof(oConfigValues[0]));

inline bool checkType(Type have, Type want)
{
	if(want == have)
		return true;
	else if(want == kTrueType && have == kFalseType)
		return true;
	else if(want == kFalseType && have == kTrueType)
		return true;
	else
		return false;
}

struct jconf::opaque_private
{
	Document jsonDoc;
	const Value* configValues[iConfigCnt]; //Compile time constant

};

jconf* jconf::oInst = nullptr;

jconf::jconf()
{
	prv = new opaque_private();
}

bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
{
	if(id >= prv->configValues[aGpuThreadsConf]->Size())
		return false;

	const Value& oThdConf = prv->configValues[aGpuThreadsConf]->GetArray()[id];

	if(!oThdConf.IsObject())
		return false;

	const Value *idx, *intensity, *w_size, *aff;
	idx = GetObjectMember(oThdConf, "index");
	intensity = GetObjectMember(oThdConf, "intensity");
	w_size = GetObjectMember(oThdConf, "worksize");
	aff = GetObjectMember(oThdConf, "affine_to_cpu");

	if(idx == nullptr || intensity == nullptr || w_size == nullptr || aff == nullptr)
		return false;

	if(!idx->IsUint64() || !intensity->IsUint64() || !w_size->IsUint64())
		return false;

	if(!aff->IsUint64() && !aff->IsBool())
		return false;

	cfg.index = idx->GetUint64();
	cfg.intensity = intensity->GetUint64();
	cfg.w_size = w_size->GetUint64();

	if(aff->IsNumber())
		cfg.cpu_aff = aff->GetInt64();
	else
		cfg.cpu_aff = -1;

	return true;
}

size_t jconf::GetPlatformIdx()
{
	return prv->configValues[iPlatformIdx]->GetUint64();
}

bool jconf::GetTlsSetting()
{
	return prv->configValues[bTlsMode]->GetBool();
}

bool jconf::TlsSecureAlgos()
{
	return prv->configValues[bTlsSecureAlgo]->GetBool();
}

const char* jconf::GetTlsFingerprint()
{
	return prv->configValues[sTlsFingerprint]->GetString();
}

const char* jconf::GetPoolAddress()
{
	return prv->configValues[sPoolAddr]->GetString();
}

const char* jconf::GetPoolPwd()
{
	return prv->configValues[sPoolPwd]->GetString();
}

const char* jconf::GetWalletAddress()
{
	return prv->configValues[sWalletAddr]->GetString();
}

bool jconf::PreferIpv4()
{
	return prv->configValues[bPreferIpv4]->GetBool();
}

size_t jconf::GetThreadCount()
{
	return prv->configValues[aGpuThreadsConf]->Size();
}

uint64_t jconf::GetCallTimeout()
{
	return prv->configValues[iCallTimeout]->GetUint64();
}

uint64_t jconf::GetNetRetry()
{
	return prv->configValues[iNetRetry]->GetUint64();
}

uint64_t jconf::GetGiveUpLimit()
{
	return prv->configValues[iGiveUpLimit]->GetUint64();
}

uint64_t jconf::GetVerboseLevel()
{
	return prv->configValues[iVerboseLevel]->GetUint64();
}

uint64_t jconf::GetAutohashTime()
{
	return prv->configValues[iAutohashTime]->GetUint64();
}

uint16_t jconf::GetHttpdPort()
{
	return prv->configValues[iHttpdPort]->GetUint();
}

bool jconf::DaemonMode()
{
	return prv->configValues[bDaemonMode]->GetBool();
}

const char* jconf::GetOutputFile()
{
	return prv->configValues[sOutputFile]->GetString();
}

bool jconf::check_cpu_features()
{
	constexpr int AESNI_BIT = 1 << 25;
	constexpr int SSE2_BIT = 1 << 26;

	int cpu_info[4];
#ifdef _WIN32
	__cpuid(cpu_info, 1);
#else
	__cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
#endif

	bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
	return (cpu_info[3] & SSE2_BIT) != 0;
}

bool jconf::parse_config(const char* sFilename)
{
	FILE * pFile;
	char * buffer;
	size_t flen;

	if(!check_cpu_features())
	{
		printer::inst()->print_msg(L0, "CPU support of SSE2 is required.");
		return false;
	}

	pFile = fopen(sFilename, "rb");
	if (pFile == NULL)
	{
		printer::inst()->print_msg(L0, "Failed to open config file %s.", sFilename);
		return false;
	}

	fseek(pFile,0,SEEK_END);
	flen = ftell(pFile);
	rewind(pFile);

	if(flen >= 64*1024)
	{
		fclose(pFile);
		printer::inst()->print_msg(L0, "Oversized config file - %s.", sFilename);
		return false;
	}

	if(flen <= 16)
	{
		printer::inst()->print_msg(L0, "File is empty or too short - %s.", sFilename);
		return false;
	}

	buffer = (char*)malloc(flen + 3);
	if(fread(buffer+1, flen, 1, pFile) != 1)
	{
		free(buffer);
		fclose(pFile);
		printer::inst()->print_msg(L0, "Read error while reading %s.", sFilename);
		return false;
	}
	fclose(pFile);

	//Replace Unicode BOM with spaces - we always use UTF-8
	unsigned char* ubuffer = (unsigned char*)buffer;
	if(ubuffer[1] == 0xEF && ubuffer[2] == 0xBB && ubuffer[3] == 0xBF)
	{
		buffer[1] = ' ';
		buffer[2] = ' ';
		buffer[3] = ' ';
	}

	buffer[0] = '{';
	buffer[flen] = '}';
	buffer[flen + 1] = '\0';

	prv->jsonDoc.Parse<kParseCommentsFlag|kParseTrailingCommasFlag>(buffer, flen+2);
	free(buffer);

	if(prv->jsonDoc.HasParseError())
	{
		printer::inst()->print_msg(L0, "JSON config parse error(offset %llu): %s",
			int_port(prv->jsonDoc.GetErrorOffset()), GetParseError_En(prv->jsonDoc.GetParseError()));
		return false;
	}

	if(!prv->jsonDoc.IsObject())
	{ //This should never happen as we created the root ourselves
		printer::inst()->print_msg(L0, "Invalid config file. No root?\n");
		return false;
	}

	for(size_t i = 0; i < iConfigCnt; i++)
	{
		if(oConfigValues[i].iName != i)
		{
			printer::inst()->print_msg(L0, "Code error. oConfigValues are not in order.");
			return false;
		}

		prv->configValues[i] = GetObjectMember(prv->jsonDoc, oConfigValues[i].sName);

		if(prv->configValues[i] == nullptr)
		{
			printer::inst()->print_msg(L0, "Invalid config file. Missing value \"%s\".", oConfigValues[i].sName);
			return false;
		}

		if(!checkType(prv->configValues[i]->GetType(), oConfigValues[i].iType))
		{
			printer::inst()->print_msg(L0, "Invalid config file. Value \"%s\" has unexpected type.", oConfigValues[i].sName);
			return false;
		}
	}

	size_t n_thd = prv->configValues[aGpuThreadsConf]->Size();
	if(prv->configValues[iGpuThreadNum]->GetUint64() != n_thd)
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. Your GPU config array has %llu members, while you want to use %llu threads.",
			int_port(n_thd), int_port(prv->configValues[iGpuThreadNum]->GetUint64()));
		return false;
	}

	thd_cfg c;
	for(size_t i=0; i < n_thd; i++)
	{
		if(!GetThreadConfig(i, c))
		{
			printer::inst()->print_msg(L0, "Thread %llu has invalid config.", int_port(i));
			return false;
		}
	}

	if(!prv->configValues[iCallTimeout]->IsUint64() ||
		!prv->configValues[iNetRetry]->IsUint64() ||
		!prv->configValues[iGiveUpLimit]->IsUint64())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. call_timeout, retry_time and giveup_limit need to be positive integers.");
		return false;
	}

	if(!prv->configValues[iVerboseLevel]->IsUint64() || !prv->configValues[iAutohashTime]->IsUint64())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. verbose_level and h_print_time need to be positive integers.");
		return false;
	}

	if(!prv->configValues[iHttpdPort]->IsUint() || prv->configValues[iHttpdPort]->GetUint() > 0xFFFF)
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. httpd_port has to be in the range 0 to 65535.");
		return false;
	}

#ifdef CONF_NO_TLS
	if(prv->configValues[bTlsMode]->GetBool())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. TLS enabled while the application has been compiled without TLS support.");
		return false;
	}
#endif // CONF_NO_TLS

	printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
	return true;
}


for(size_t i=0; i < n_thd; i++)
	{
		if(!GetThreadConfig(i, c))
		{
			printer::inst()->print_msg(L0, "Thread %llu has invalid config.", int_port(i));
			return false;
		}
	}

/*
  *
  *
  * If you modify this Program, or any covered work, by linking or combining
  * it with OpenSSL (or a modified version of that library), containing parts
  * of this Program grant you additional permission to convey the resulting work.
  *
  */

#include "jconf.h"
#include "console.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
#define strcasecmp _stricmp
#include <intrin.h>
#else
#include <cpuid.h>
#endif

#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "jext.h"
#include "console.h"

using namespace rapidjson;

/*
 * This enum needs to match index in oConfigValues, otherwise we will get a runtime error
 */
enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx,
	bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
	iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
	bDaemonMode, sOutputFile, iHttpdPort, bPreferIpv4 };

struct configVal {
	configEnum iName;
	const char* sName;
	Type iType;
};

//Same order as in configEnum, as per comment above
configVal oConfigValues[] = {
	{ iGpuThreadNum, "gpu_thread_num", kNumberType },
	{ aGpuThreadsConf, "gpu_threads_conf", kArrayType },
	{ iPlatformIdx, "platform_index", kNumberType },
	{ bTlsMode, "use_tls", kTrueType },
	{ bTlsSecureAlgo, "tls_secure_algo", kTrueType },
	{ sTlsFingerprint, "tls_fingerprint", kStringType },
	{ sPoolAddr, "pool_address", kStringType },
	{ sWalletAddr, "wallet_address", kStringType },
	{ sPoolPwd, "pool_password", kStringType },
	{ iCallTimeout, "call_timeout", kNumberType },
	{ iNetRetry, "retry_time", kNumberType },
	{ iGiveUpLimit, "giveup_limit", kNumberType },
	{ iVerboseLevel, "verbose_level", kNumberType },
	{ iAutohashTime, "h_print_time", kNumberType },
	{ bDaemonMode, "daemon_mode", kTrueType },
	{ sOutputFile, "output_file", kStringType },
	{ iHttpdPort, "httpd_port", kNumberType },
	{ bPreferIpv4, "prefer_ipv4", kTrueType }
};

constexpr size_t iConfigCnt = (sizeof(oConfigValues)/sizeof(oConfigValues[0]));

inline bool checkType(Type have, Type want)
{
	if(want == have)
		return true;
	else if(want == kTrueType && have == kFalseType)
		return true;
	else if(want == kFalseType && have == kTrueType)
		return true;
	else
		return false;
}

struct jconf::opaque_private
{
	Document jsonDoc;
	const Value* configValues[iConfigCnt]; //Compile time constant

	opaque_private()
	{
	}
};

jconf* jconf::oInst = nullptr;

jconf::jconf()
{
	prv = new opaque_private();
}

bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
{
	if(id >= prv->configValues[aGpuThreadsConf]->Size())
		return false;

	const Value& oThdConf = prv->configValues[aGpuThreadsConf]->GetArray()[id];

	if(!oThdConf.IsObject())
		return false;

	const Value *idx, *intensity, *w_size, *aff;
	idx = GetObjectMember(oThdConf, "index");
	intensity = GetObjectMember(oThdConf, "intensity");
	w_size = GetObjectMember(oThdConf, "worksize");
	aff = GetObjectMember(oThdConf, "affine_to_cpu");

	if(idx == nullptr || intensity == nullptr || w_size == nullptr || aff == nullptr)
		return false;

	if(!idx->IsUint64() || !intensity->IsUint64() || !w_size->IsUint64())
		return false;

	if(!aff->IsUint64() && !aff->IsBool())
		return false;

	cfg.index = idx->GetUint64();
	cfg.intensity = intensity->GetUint64();
	cfg.w_size = w_size->GetUint64();

	if(aff->IsNumber())
		cfg.cpu_aff = aff->GetInt64();
	else
		cfg.cpu_aff = -1;

	return true;
}

size_t jconf::GetPlatformIdx()
{
	return prv->configValues[iPlatformIdx]->GetUint64();
}

bool jconf::GetTlsSetting()
{
	return prv->configValues[bTlsMode]->GetBool();
}

bool jconf::TlsSecureAlgos()
{
	return prv->configValues[bTlsSecureAlgo]->GetBool();
}

const char* jconf::GetTlsFingerprint()
{
	return prv->configValues[sTlsFingerprint]->GetString();
}

const char* jconf::GetPoolAddress()
{
	return prv->configValues[sPoolAddr]->GetString();
}

const char* jconf::GetPoolPwd()
{
	return prv->configValues[sPoolPwd]->GetString();
}

const char* jconf::GetWalletAddress()
{
	return prv->configValues[sWalletAddr]->GetString();
}

bool jconf::PreferIpv4()
{
	return prv->configValues[bPreferIpv4]->GetBool();
}

size_t jconf::GetThreadCount()
{
	return prv->configValues[aGpuThreadsConf]->Size();
}

uint64_t jconf::GetCallTimeout()
{
	return prv->configValues[iCallTimeout]->GetUint64();
}

uint64_t jconf::GetNetRetry()
{
	return prv->configValues[iNetRetry]->GetUint64();
}

uint64_t jconf::GetGiveUpLimit()
{
	return prv->configValues[iGiveUpLimit]->GetUint64();
}

uint64_t jconf::GetVerboseLevel()
{
	return prv->configValues[iVerboseLevel]->GetUint64();
}

uint64_t jconf::GetAutohashTime()
{
	return prv->configValues[iAutohashTime]->GetUint64();
}

uint16_t jconf::GetHttpdPort()
{
	return prv->configValues[iHttpdPort]->GetUint();
}

bool jconf::DaemonMode()
{
	return prv->configValues[bDaemonMode]->GetBool();
}

const char* jconf::GetOutputFile()
{
	return prv->configValues[sOutputFile]->GetString();
}

bool jconf::check_cpu_features()
{
	constexpr int AESNI_BIT = 1 << 25;
	constexpr int SSE2_BIT = 1 << 26;

	int cpu_info[4];
#ifdef _WIN32
	__cpuid(cpu_info, 1);
#else
	__cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
#endif

	bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
	return (cpu_info[3] & SSE2_BIT) != 0;
}

bool jconf::parse_config(const char* sFilename)
{
	FILE * pFile;
	char * buffer;
	size_t flen;

	if(!check_cpu_features())
	{
		printer::inst()->print_msg(L0, "CPU support of SSE2 is required.");
		return false;
	}

	pFile = fopen(sFilename, "rb");
	if (pFile == NULL)
	{
		printer::inst()->print_msg(L0, "Failed to open config file %s.", sFilename);
		return false;
	}

	fseek(pFile,0,SEEK_END);
	flen = ftell(pFile);
	rewind(pFile);

	if(flen >= 64*1024)
	{
		fclose(pFile);
		printer::inst()->print_msg(L0, "Oversized config file - %s.", sFilename);
		return false;
	}

	if(flen <= 16)
	{
		printer::inst()->print_msg(L0, "File is empty or too short - %s.", sFilename);
		return false;
	}

	buffer = (char*)malloc(flen + 3);
	if(fread(buffer+1, flen, 1, pFile) != 1)
	{
		free(buffer);
		fclose(pFile);
		printer::inst()->print_msg(L0, "Read error while reading %s.", sFilename);
		return false;
	}
	fclose(pFile);

	//Replace Unicode BOM with spaces - we always use UTF-8
	unsigned char* ubuffer = (unsigned char*)buffer;
	if(ubuffer[1] == 0xEF && ubuffer[2] == 0xBB && ubuffer[3] == 0xBF)
	{
		buffer[1] = ' ';
		buffer[2] = ' ';
		buffer[3] = ' ';
	}

	buffer[0] = '{';
	buffer[flen] = '}';
	buffer[flen + 1] = '\0';

	prv->jsonDoc.Parse<kParseCommentsFlag|kParseTrailingCommasFlag>(buffer, flen+2);
	free(buffer);

	if(prv->jsonDoc.HasParseError())
	{
		printer::inst()->print_msg(L0, "JSON config parse error(offset %llu): %s",
			int_port(prv->jsonDoc.GetErrorOffset()), GetParseError_En(prv->jsonDoc.GetParseError()));
		return false;
	}

	if(!prv->jsonDoc.IsObject())
	{ //This should never happen as we created the root ourselves
		printer::inst()->print_msg(L0, "Invalid config file. No root?\n");
		return false;
	}

	for(size_t i = 0; i < iConfigCnt; i++)
	{
		if(oConfigValues[i].iName != i)
		{
			printer::inst()->print_msg(L0, "Code error. oConfigValues are not in order.");
			return false;
		}

		prv->configValues[i] = GetObjectMember(prv->jsonDoc, oConfigValues[i].sName);

		if(prv->configValues[i] == nullptr)
		{
			printer::inst()->print_msg(L0, "Invalid config file. Missing value \"%s\".", oConfigValues[i].sName);
			return false;
		}

		if(!checkType(prv->configValues[i]->GetType(), oConfigValues[i].iType))
		{
			printer::inst()->print_msg(L0, "Invalid config file. Value \"%s\" has unexpected type.", oConfigValues[i].sName);
			return false;
		}
	}

	size_t n_thd = prv->configValues[aGpuThreadsConf]->Size();
	if(prv->configValues[iGpuThreadNum]->GetUint64() != n_thd)
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. Your GPU config array has %llu members, while you want to use %llu threads.",
			int_port(n_thd), int_port(prv->configValues[iGpuThreadNum]->GetUint64()));
		return false;
	}

	thd_cfg c;

	if(!prv->configValues[iCallTimeout]->IsUint64() ||
		!prv->configValues[iNetRetry]->IsUint64() ||
		!prv->configValues[iGiveUpLimit]->IsUint64())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. call_timeout, retry_time and giveup_limit need to be positive integers.");
		return false;
	}

	if(!prv->configValues[iVerboseLevel]->IsUint64() || !prv->configValues[iAutohashTime]->IsUint64())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. verbose_level and h_print_time need to be positive integers.");
		return false;
	}

	if(!prv->configValues[iHttpdPort]->IsUint() || prv->configValues[iHttpdPort]->GetUint() > 0xFFFF)
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. httpd_port has to be in the range 0 to 65535.");
		return false;
	}

#ifdef CONF_NO_TLS
	if(prv->configValues[bTlsMode]->GetBool())
	{
		printer::inst()->print_msg(L0,
			"Invalid config file. TLS enabled while the application has been compiled without TLS support.");
		return false;
	}
#endif // CONF_NO_TLS

	printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
	return true;
}


/****************************************************************************
**
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/
#include <QtCore>
#include <qtest.h>
#include "object.h"
#include <qcoreapplication.h>
#include <qdatetime.h>

enum {
    CreationDeletionBenckmarkConstant = 34567,
    SignalsAndSlotsBenchmarkConstant = 456789
};

class QObjectBenchmark : public QObject
{
Q_OBJECT
private slots:
    void signal_slot_benchmark();
    void signal_slot_benchmark_data();

    void connect_disconnect_benchmark_data();
    void connect_disconnect_benchmark();
};

struct Functor {
    void operator()(){}
};

void QObjectBenchmark::signal_slot_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");
    QTest::newRow("simple function") << 0    << false;
    QTest::newRow("single signal/slot") << 1 << false;
    QTest::newRow("multi signal/slot") << 2  << false;
    QTest::newRow("unconnected signal") << 3 << false;
    QTest::newRow("single signal/ptr") << 4  << false;
    QTest::newRow("functor") << 5            << false;

    QTest::newRow("w simple function") << 0    << true;
    QTest::newRow("w single signal/slot") << 1 << true;
    QTest::newRow("w multi signal/slot") << 2  << true;
    QTest::newRow("w unconnected signal") << 3 << true;
    QTest::newRow("w single signal/ptr") << 4  << true;
    QTest::newRow("w functor") << 5            << true;

}

template<typename Object>
void signal_slot_benchmark()
{
    QFETCH(int, type);

    Object singleObject;
    Object multiObject;
    Functor functor;
    singleObject.setObjectName("single");
    multiObject.setObjectName("multi");

    if (type == 5) {
        QObject::connect(&singleObject, &Object::signal0, functor);
    } else if (type == 4) {
        QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0);
    } else {
        singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0()));
    }

    multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0()));
    multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1()));
    multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2()));
    multiObject.connect(&multiObject, SIGNAL(signal3()), SLOT(slot3()));
    multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4()));
    multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5()));
    multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6()));
    multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7()));
    multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8()));
    multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9()));

    if (type == 0) {
        QBENCHMARK {
            singleObject.slot0();
        }
    } else if (type == 1) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    } else if (type == 2) {
        QBENCHMARK {
            multiObject.emitSignal0();
        }
    } else if (type == 3) {
        QBENCHMARK {
            singleObject.emitSignal1();
        }
    } else if (type == 4 || type == 5) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    }
}

{
    QFETCH(bool, w);
    if (w) ::signal_slot_benchmark<ObjectW>();
    else ::signal_slot_benchmark<Object>();
}

void QObjectBenchmark::connect_disconnect_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");

    QTest::newRow("normalized signature") << 0          << false;
    QTest::newRow("unormalized signature") << 1         << false;
    QTest::newRow("function pointer") << 2              << false;
    QTest::newRow("normalized signature/handle") << 3   << false;
    QTest::newRow("unormalized signature/handle") << 4  << false;
    QTest::newRow("function pointer/handle") << 5       << false;
    QTest::newRow("functor/handle") << 6                << false;

    QTest::newRow("w normalized signature") << 0          << true;
    QTest::newRow("w unormalized signature") << 1         << true;
    QTest::newRow("w function pointer") << 2              << true;
    QTest::newRow("w normalized signature/handle") << 3   << true;
    QTest::newRow("w unormalized signature/handle") << 4  << true;
    QTest::newRow("w function pointer/handle") << 5       << true;
    QTest::newRow("w functor/handle") << 6                << true;

}

template<typename Object>
void connect_disconnect_benchmark()
{
    QFETCH(int, type);
    switch (type) {
        case 0: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
                QObject::disconnect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
            }
        } break;
        case 1: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
                QObject::disconnect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
            }
        } break;
        case 2: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, &Object::signal5, &obj, &Object::slot5);
                QObject::disconnect(&obj, &Object::signal5, &obj, &Object::slot5);
            }
        } break;
        case 3: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5())));
            }
        } break;
        case 4: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  )))); // sic: non-normalised
            }
        } break;
        case 5: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, &obj, &Object::slot5));
            }
        } break;
        case 6: {
            Object obj;
            Functor functor;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, functor));
            }
        } break;
    }
}

void QObjectBenchmark::connect_disconnect_benchmark()
{
    QFETCH(bool, w);
    if (w) ::connect_disconnect_benchmark<ObjectW>();
    else ::connect_disconnect_benchmark<Object>();
}

QTEST_MAIN(QObjectBenchmark)

#include "main.moc"


{
            singleObject.emitSignal0();
        }

/****************************************************************************
**
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/
#include <QtCore>
#include <qtest.h>
#include "object.h"
#include <qcoreapplication.h>
#include <qdatetime.h>

enum {
    CreationDeletionBenckmarkConstant = 34567,
    SignalsAndSlotsBenchmarkConstant = 456789
};

class QObjectBenchmark : public QObject
{
Q_OBJECT
private slots:
    void signal_slot_benchmark();
    void signal_slot_benchmark_data();

    void connect_disconnect_benchmark_data();
    void connect_disconnect_benchmark();
};

struct Functor {
    void operator()(){}
};

void QObjectBenchmark::signal_slot_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");
    QTest::newRow("simple function") << 0    << false;
    QTest::newRow("single signal/slot") << 1 << false;
    QTest::newRow("multi signal/slot") << 2  << false;
    QTest::newRow("unconnected signal") << 3 << false;
    QTest::newRow("single signal/ptr") << 4  << false;
    QTest::newRow("functor") << 5            << false;

    QTest::newRow("w simple function") << 0    << true;
    QTest::newRow("w single signal/slot") << 1 << true;
    QTest::newRow("w multi signal/slot") << 2  << true;
    QTest::newRow("w unconnected signal") << 3 << true;
    QTest::newRow("w single signal/ptr") << 4  << true;
    QTest::newRow("w functor") << 5            << true;

}

template<typename Object>
void signal_slot_benchmark()
{
    QFETCH(int, type);

    Object singleObject;
    Object multiObject;
    Functor functor;
    singleObject.setObjectName("single");
    multiObject.setObjectName("multi");

    if (type == 5) {
        QObject::connect(&singleObject, &Object::signal0, functor);
    } else if (type == 4) {
        QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0);
    } else {
        singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0()));
    }

    multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0()));
    multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1()));
    multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2()));
    multiObject.connect(&multiObject, SIGNAL(signal3()), SLOT(slot3()));
    multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4()));
    multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5()));
    multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6()));
    multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7()));
    multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8()));
    multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9()));

    if (type == 0) {
        QBENCHMARK {
            singleObject.slot0();
        }
    } else if (type == 1) {
        QBENCHMARK

    } else if (type == 2) {
        QBENCHMARK {
            multiObject.emitSignal0();
        }
    } else if (type == 3) {
        QBENCHMARK {
            singleObject.emitSignal1();
        }
    } else if (type == 4 || type == 5) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    }
}

void QObjectBenchmark::signal_slot_benchmark()
{
    QFETCH(bool, w);
    if (w) ::signal_slot_benchmark<ObjectW>();
    else ::signal_slot_benchmark<Object>();
}

void QObjectBenchmark::connect_disconnect_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");

    QTest::newRow("normalized signature") << 0          << false;
    QTest::newRow("unormalized signature") << 1         << false;
    QTest::newRow("function pointer") << 2              << false;
    QTest::newRow("normalized signature/handle") << 3   << false;
    QTest::newRow("unormalized signature/handle") << 4  << false;
    QTest::newRow("function pointer/handle") << 5       << false;
    QTest::newRow("functor/handle") << 6                << false;

    QTest::newRow("w normalized signature") << 0          << true;
    QTest::newRow("w unormalized signature") << 1         << true;
    QTest::newRow("w function pointer") << 2              << true;
    QTest::newRow("w normalized signature/handle") << 3   << true;
    QTest::newRow("w unormalized signature/handle") << 4  << true;
    QTest::newRow("w function pointer/handle") << 5       << true;
    QTest::newRow("w functor/handle") << 6                << true;

}

template<typename Object>
void connect_disconnect_benchmark()
{
    QFETCH(int, type);
    switch (type) {
        case 0: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
                QObject::disconnect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
            }
        } break;
        case 1: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
                QObject::disconnect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
            }
        } break;
        case 2: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, &Object::signal5, &obj, &Object::slot5);
                QObject::disconnect(&obj, &Object::signal5, &obj, &Object::slot5);
            }
        } break;
        case 3: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5())));
            }
        } break;
        case 4: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  )))); // sic: non-normalised
            }
        } break;
        case 5: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, &obj, &Object::slot5));
            }
        } break;
        case 6: {
            Object obj;
            Functor functor;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, functor));
            }
        } break;
    }
}

void QObjectBenchmark::connect_disconnect_benchmark()
{
    QFETCH(bool, w);
    if (w) ::connect_disconnect_benchmark<ObjectW>();
    else ::connect_disconnect_benchmark<Object>();
}

QTEST_MAIN(QObjectBenchmark)

#include "main.moc"


/****************************************************************************
**
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/
#include <QtCore>
#include <qtest.h>
#include "object.h"
#include <qcoreapplication.h>
#include <qdatetime.h>

enum {
    CreationDeletionBenckmarkConstant = 34567,
    SignalsAndSlotsBenchmarkConstant = 456789
};

class QObjectBenchmark : public QObject
{
Q_OBJECT
private slots:
    void signal_slot_benchmark();
    void signal_slot_benchmark_data();

    void connect_disconnect_benchmark_data();
    void connect_disconnect_benchmark();
};

struct Functor {
    void operator()(){}
};

void QObjectBenchmark::signal_slot_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");
    QTest::newRow("simple function") << 0    << false;
    QTest::newRow("single signal/slot") << 1 << false;
    QTest::newRow("multi signal/slot") << 2  << false;
    QTest::newRow("unconnected signal") << 3 << false;
    QTest::newRow("single signal/ptr") << 4  << false;
    QTest::newRow("functor") << 5            << false;

    QTest::newRow("w simple function") << 0    << true;
    QTest::newRow("w single signal/slot") << 1 << true;
    QTest::newRow("w multi signal/slot") << 2  << true;
    QTest::newRow("w unconnected signal") << 3 << true;
    QTest::newRow("w single signal/ptr") << 4  << true;
    QTest::newRow("w functor") << 5            << true;

}

template<typename Object>
void signal_slot_benchmark()
{
    QFETCH(int, type);

    Object singleObject;
    Object multiObject;
    Functor functor;
    singleObject.setObjectName("single");
    multiObject.setObjectName("multi");

    if (type == 5) {
        QObject::connect(&singleObject, &Object::signal0, functor);
    } else if (type == 4) {
        QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0);
    } else {
        singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0()));
    }

    multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0()));
    multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1()));
    multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2()));
    multiObject.connect(&multiObject, SIGNA

    multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4()));
    multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5()));
    multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6()));
    multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7()));
    multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8()));
    multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9()));

    if (type == 0) {
        QBENCHMARK {
            singleObject.slot0();
        }
    } else if (type == 1) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    } else if (type == 2) {
        QBENCHMARK {
            multiObject.emitSignal0();
        }
    } else if (type == 3) {
        QBENCHMARK {
            singleObject.emitSignal1();
        }
    } else if (type == 4 || type == 5) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    }
}

void QObjectBenchmark::signal_slot_benchmark()
{
    QFETCH(bool, w);
    if (w) ::signal_slot_benchmark<ObjectW>();
    else ::signal_slot_benchmark<Object>();
}

void QObjectBenchmark::connect_disconnect_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");

    QTest::newRow("normalized signature") << 0          << false;
    QTest::newRow("unormalized signature") << 1         << false;
    QTest::newRow("function pointer") << 2              << false;
    QTest::newRow("normalized signature/handle") << 3   << false;
    QTest::newRow("unormalized signature/handle") << 4  << false;
    QTest::newRow("function pointer/handle") << 5       << false;
    QTest::newRow("functor/handle") << 6                << false;

    QTest::newRow("w normalized signature") << 0          << true;
    QTest::newRow("w unormalized signature") << 1         << true;
    QTest::newRow("w function pointer") << 2              << true;
    QTest::newRow("w normalized signature/handle") << 3   << true;
    QTest::newRow("w unormalized signature/handle") << 4  << true;
    QTest::newRow("w function pointer/handle") << 5       << true;
    QTest::newRow("w functor/handle") << 6                << true;

}

template<typename Object>
void connect_disconnect_benchmark()
{
    QFETCH(int, type);
    switch (type) {
        case 0: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
                QObject::disconnect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
            }
        } break;
        case 1: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
                QObject::disconnect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
            }
        } break;
        case 2: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, &Object::signal5, &obj, &Object::slot5);
                QObject::disconnect(&obj, &Object::signal5, &obj, &Object::slot5);
            }
        } break;
        case 3: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5())));
            }
        } break;
        case 4: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  )))); // sic: non-normalised
            }
        } break;
        case 5: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, &obj, &Object::slot5));
            }
        } break;
        case 6: {
            Object obj;
            Functor functor;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, functor));
            }
        } break;
    }
}

void QObjectBenchmark::connect_disconnect_benchmark()
{
    QFETCH(bool, w);
    if (w) ::connect_disconnect_benchmark<ObjectW>();
    else ::connect_disconnect_benchmark<Object>();
}

QTEST_MAIN(QObjectBenchmark)

#include "main.moc"


switch (type) {
        case 0: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
                QObject::disconnect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5()));
            }
        }

/****************************************************************************
**
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/
#include <QtCore>
#include <qtest.h>
#include "object.h"
#include <qcoreapplication.h>
#include <qdatetime.h>

enum {
    CreationDeletionBenckmarkConstant = 34567,
    SignalsAndSlotsBenchmarkConstant = 456789
};

class QObjectBenchmark : public QObject
{
Q_OBJECT
private slots:
    void signal_slot_benchmark();
    void signal_slot_benchmark_data();

    void connect_disconnect_benchmark_data();
    void connect_disconnect_benchmark();
};

struct Functor {
    void operator()(){}
};

void QObjectBenchmark::signal_slot_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");
    QTest::newRow("simple function") << 0    << false;
    QTest::newRow("single signal/slot") << 1 << false;
    QTest::newRow("multi signal/slot") << 2  << false;
    QTest::newRow("unconnected signal") << 3 << false;
    QTest::newRow("single signal/ptr") << 4  << false;
    QTest::newRow("functor") << 5            << false;

    QTest::newRow("w simple function") << 0    << true;
    QTest::newRow("w single signal/slot") << 1 << true;
    QTest::newRow("w multi signal/slot") << 2  << true;
    QTest::newRow("w unconnected signal") << 3 << true;
    QTest::newRow("w single signal/ptr") << 4  << true;
    QTest::newRow("w functor") << 5            << true;

}

template<typename Object>
void signal_slot_benchmark()
{
    QFETCH(int, type);

    Object singleObject;
    Object multiObject;
    Functor functor;
    singleObject.setObjectName("single");
    multiObject.setObjectName("multi");

    if (type == 5) {
        QObject::connect(&singleObject, &Object::signal0, functor);
    } else if (type == 4) {
        QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0);
    } else {
        singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0()));
    }

    multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0()));
    multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1()));
    multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2()));
    multiObject.connect(&multiObject, SIGNAL(signal3()), SLOT(slot3()));
    multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4()));
    multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5()));
    multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6()));
    multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7()));
    multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8()));
    multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9()));

    if (type == 0) {
        QBENCHMARK {
            singleObject.slot0();
        }
    } else if (type == 1) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    } else if (type == 2) {
        QBENCHMARK {
            multiObject.emitSignal0();
        }
    } else if (type == 3) {
        QBENCHMARK {
            singleObject.emitSignal1();
        }
    } else if (type == 4 || type == 5) {
        QBENCHMARK {
            singleObject.emitSignal0();
        }
    }
}

void QObjectBenchmark::signal_slot_benchmark()
{
    QFETCH(bool, w);
    if (w) ::signal_slot_benchmark<ObjectW>();
    else ::signal_slot_benchmark<Object>();
}

void QObjectBenchmark::connect_disconnect_benchmark_data()
{
    QTest::addColumn<int>("type");
    QTest::addColumn<bool>("w");

    QTest::newRow("normalized signature") << 0          << false;
    QTest::newRow("unormalized signature") << 1         << false;
    QTest::newRow("function pointer") << 2              << false;
    QTest::newRow("normalized signature/handle") << 3   << false;
    QTest::newRow("unormalized signature/handle") << 4  << false;
    QTest::newRow("function pointer/handle") << 5       << false;
    QTest::newRow("functor/handle") << 6                << false;

    QTest::newRow("w normalized signature") << 0          << true;
    QTest::newRow("w unormalized signature") << 1         << true;
    QTest::newRow("w function pointer") << 2              << true;
    QTest::newRow("w normalized signature/handle") << 3   << true;
    QTest::newRow("w unormalized signature/handle") << 4  << true;
    QTest::newRow("w function pointer/handle") << 5       << true;
    QTest::newRow("w functor/handle") << 6                << true;

}

template<typename Object>
void connect_disconnect_benchmark()
{
    QFETCH(int, type);

 break;
        case 1: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
                QObject::disconnect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  ))); // sic: non-normalised
            }
        } break;
        case 2: {
            Object obj;
            QBENCHMARK {
                QObject::connect   (&obj, &Object::signal5, &obj, &Object::slot5);
                QObject::disconnect(&obj, &Object::signal5, &obj, &Object::slot5);
            }
        } break;
        case 3: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5())));
            }
        } break;
        case 4: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5(  )), &obj, SLOT(slot5(  )))); // sic: non-normalised
            }
        } break;
        case 5: {
            Object obj;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, &obj, &Object::slot5));
            }
        } break;
        case 6: {
            Object obj;
            Functor functor;
            QBENCHMARK {
                QObject::disconnect(QObject::connect(&obj, &Object::signal5, functor));
            }
        } break;
    }
}

void QObjectBenchmark::connect_disconnect_benchmark()
{
    QFETCH(bool, w);
    if (w) ::connect_disconnect_benchmark<ObjectW>();
    else ::connect_disconnect_benchmark<Object>();
}

QTEST_MAIN(QObjectBenchmark)

#include "main.moc"


while (getline(in,line)) {
        ++lineno;
        boost::smatch matches;    // matched strings go here
        if (boost::regex_search(line, matches, pat)) {
            cout << lineno << ": " << matches[0] << '\n';
            if (1<matches.size() && matches[1].matched)
                cout  << "\t: " << matches[1] << '\n';    // sub-match
        }
    }

// This is example code from Chapter 23.7 "Searching with regular expressions" of
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup

#include <boost/regex.hpp>
#include <iostream>
#include <stdexcept>
#include <string>
#include <fstream>

using namespace std;

int main()
try
{
    ifstream in("file.txt");    // input file
    if (!in) cerr << "no file\n";

    boost::regex pat ("\\w{2}\\s*\\d{5}(-\\d{4})?");    // ZIP code pattern
    cout << "pattern: " << pat << '\n';

    int lineno = 0;
    string line;    // input buffer

}
catch (std::exception& e) {
    cerr << "error: " << e.what() << '\n';
    return 1;
}
catch (...) {
    cerr << "Oops: unknown exception!\n";
    return 2;
};


unsigned int BlockMiner::NumOfMined(string addr, unsigned int nAlliance) const

#include "cache.h"
#include "main.h"
#include "policy/licenseinfo.h"
#include "util.h"
#include "utilerror.h"

using std::set;
using std::string;
using std::map;
using std::pair;
using std::list;
using std::exception;
using std::vector;

alliance_member::AllianceMember *palliance = NULL;
color_license::ColorLicense *plicense = NULL;
block_miner::BlockMiner *pblkminer = NULL;
miner::Miner *pminer = NULL;

// Namespace for cache of license structure.
namespace color_license
{

bool ColorLicense::SetOwner(const type_Color &color, const string addr, const CLicenseInfo *pinfo)
{
    // If the owner is assigned for the first time, license info should be assigned at the same time.
    // If the license already exists, license info should not be assigned.
    if (IsColorExist(color)) {
        if (pinfo)
            return false;
    } else {
        if (pinfo)
            (*pcontainer_)[color].info_ = *pinfo;
        else
            return false;
    }
    (*pcontainer_)[color].address_ = addr;
    return true;
}

string ColorLicense::GetOwner(const type_Color &color) const
{
    return (*pcontainer_)[color].address_;
}

bool ColorLicense::IsColorExist(const type_Color &color) const
{
    if (color == DEFAULT_ADMIN_COLOR)
        return true;
    return (pcontainer_->find(color) != pcontainer_->end());
}

int64_t ColorLicense::NumOfCoins(const type_Color &color) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it == pcontainer_->end()) {
        return 0;
    }
    return it->second.num_of_coins_;
}

map<type_Color, pair<string, int64_t> > ColorLicense::ListLicense() const
{
    map<type_Color, pair<string, int64_t> > list;
    for (Tc_t::const_iterator it = pcontainer_->begin(); it != pcontainer_->end(); it++) {
        list[it->first] = make_pair(it->second.address_, it->second.num_of_coins_);
    }
    return list;
}

bool ColorLicense::GetLicenseInfo(const type_Color &color, CLicenseInfo &info) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it != pcontainer_->end()) {
        info = it->second.info_;
        return true;
    } else
        return false;
}

}

// Namespace for cache of block miners.
namespace block_miner
{
bool BlockMiner::Add(const string &addr)
{
    while (pcontainer_->size() >= 100) pcontainer_->pop_back();
    pcontainer_->push_front(make_pair(addr, pminer->NumOfMiners()));
    return true;
}

{
    unsigned int count = 1, nSameMiner = 0;
    for (list<pair<string, unsigned int> >::iterator it = pcontainer_->begin();
         count <= Params().DynamicMiner() && count < nAlliance && it != pcontainer_->end(); it++) {
        if (it->first == addr) nSameMiner++;
        count++;
    }
    return nSameMiner;
}
}


{
    map<type_Color, pair<string, int64_t> > list;
    for (Tc_t::const_iterator it = pcontainer_->begin(); it != pcontainer_->end(); it++) {
        list[it->first] = make_pair(it->second.address_, it->second.num_of_coins_);
    }
    return list;
}

#include "cache.h"
#include "main.h"
#include "policy/licenseinfo.h"
#include "util.h"
#include "utilerror.h"

using std::set;
using std::string;
using std::map;
using std::pair;
using std::list;
using std::exception;
using std::vector;

alliance_member::AllianceMember *palliance = NULL;
color_license::ColorLicense *plicense = NULL;
block_miner::BlockMiner *pblkminer = NULL;
miner::Miner *pminer = NULL;

// Namespace for cache of license structure.
namespace color_license
{

bool ColorLicense::SetOwner(const type_Color &color, const string addr, const CLicenseInfo *pinfo)
{
    // If the owner is assigned for the first time, license info should be assigned at the same time.
    // If the license already exists, license info should not be assigned.
    if (IsColorExist(color)) {
        if (pinfo)
            return false;
    } else {
        if (pinfo)
            (*pcontainer_)[color].info_ = *pinfo;
        else
            return false;
    }
    (*pcontainer_)[color].address_ = addr;
    return true;
}

string ColorLicense::GetOwner(const type_Color &color) const
{
    return (*pcontainer_)[color].address_;
}

bool ColorLicense::IsColorExist(const type_Color &color) const
{
    if (color == DEFAULT_ADMIN_COLOR)
        return true;
    return (pcontainer_->find(color) != pcontainer_->end());
}

int64_t ColorLicense::NumOfCoins(const type_Color &color) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it == pcontainer_->end()) {
        return 0;
    }
    return it->second.num_of_coins_;
}

map<type_Color, pair<string, int64_t> > ColorLicense::ListLicense() const

bool ColorLicense::GetLicenseInfo(const type_Color &color, CLicenseInfo &info) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it != pcontainer_->end()) {
        info = it->second.info_;
        return true;
    } else
        return false;
}

}

// Namespace for cache of block miners.
namespace block_miner
{
bool BlockMiner::Add(const string &addr)
{
    while (pcontainer_->size() >= 100) pcontainer_->pop_back();
    pcontainer_->push_front(make_pair(addr, pminer->NumOfMiners()));
    return true;
}

unsigned int BlockMiner::NumOfMined(string addr, unsigned int nAlliance) const
{
    unsigned int count = 1, nSameMiner = 0;
    for (list<pair<string, unsigned int> >::iterator it = pcontainer_->begin();
         count <= Params().DynamicMiner() && count < nAlliance && it != pcontainer_->end(); it++) {
        if (it->first == addr) nSameMiner++;
        count++;
    }
    return nSameMiner;
}
}


#include "cache.h"
#include "main.h"
#include "policy/licenseinfo.h"
#include "util.h"
#include "utilerror.h"

using std::set;
using std::string;
using std::map;
using std::pair;
using std::list;
using std::exception;
using std::vector;

alliance_member::AllianceMember *palliance = NULL;
color_license::ColorLicense *plicense = NULL;
block_miner::BlockMiner *pblkminer = NULL;
miner::Miner *pminer = NULL;

// Namespace for cache of license structure.
namespace color_license
{

bool ColorLicense::SetOwner(const type_Color &color, const string addr, const CLicenseInfo *pinfo)
{
    // If the owner is assigned for the first time, license info should be assigned at the same time.
    // If the license already exists, license info should not be assigned.
    if (IsColorExist(color)) {
        if (pinfo)
            return false;
    } else {
        if (pinfo)
            (*pcontainer_)[color].info_ = *pinfo;
        else
            return false;
    }
    (*pcontainer_)[color].address_ = addr;
    return true;
}

string ColorLicense::GetOwner(const type_Color &color) const
{
    return (*pcontainer_)[color].address_;
}

bool ColorLicense::IsColorExist(const type_Color &color) const
{
    if (color == DEFAULT_ADMIN_COLOR)
        return true;
    return (pcontainer_->find(color) != pcontainer_->end());
}

int64_t ColorLicense::NumOfCoins(const type_Color &color) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it == pcontainer_->end()) {
        return 0;
    }
    return it->second.num_of_coins_;
}

map<type_Color, pair<string, int64_t> > ColorLicense::ListLicense() const
{
    map<type_Color, pair<string, int64_t> > list;
    for (Tc_t::const_iterator it = pcontainer_->begin(); it != pcontainer_->end(); it++) {
        list[it->first] = make_pair(it->second.address_, it->second.num_of_coins_);
    }
    return list;
}

bool ColorLicense::GetLicenseInfo(const type_Color &color, CLicenseInfo &info) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it != pcontainer_->end()) {
        info = it->second.info_;
        return true;
    } else
        return false;
}

}

// Namespace for cache of block miners.
namespace block_miner
{
bool BlockMiner::Add(const string &addr)
{
    while (pcontainer_->size() >= 100) pcontainer_->pop_back();
    pcontainer_->push_front(make_pair(addr, pminer->NumOfMiners()));
    return true;
}

unsigned int BlockMiner::NumOfMined(string addr, unsigned int nAlliance) const
{
    unsigned int co

    for (list<pair<string, unsigned int> >::iterator it = pcontainer_->begin();
         count <= Params().DynamicMiner() && count < nAlliance && it != pcontainer_->end(); it++) {
        if (it->first == addr) nSameMiner++;
        count++;
    }
    return nSameMiner;
}
}


for (list<pair<string, unsigned int> >::iterator it = pcontainer_->begin();
         count <= Params().DynamicMiner() && count < nAlliance && it != pcontainer_->end(); it++) {
        if (it->first == addr) nSameMiner++;
        count++;
    }

#include "cache.h"
#include "main.h"
#include "policy/licenseinfo.h"
#include "util.h"
#include "utilerror.h"

using std::set;
using std::string;
using std::map;
using std::pair;
using std::list;
using std::exception;
using std::vector;

alliance_member::AllianceMember *palliance = NULL;
color_license::ColorLicense *plicense = NULL;
block_miner::BlockMiner *pblkminer = NULL;
miner::Miner *pminer = NULL;

// Namespace for cache of license structure.
namespace color_license
{

bool ColorLicense::SetOwner(const type_Color &color, const string addr, const CLicenseInfo *pinfo)
{
    // If the owner is assigned for the first time, license info should be assigned at the same time.
    // If the license already exists, license info should not be assigned.
    if (IsColorExist(color)) {
        if (pinfo)
            return false;
    } else {
        if (pinfo)
            (*pcontainer_)[color].info_ = *pinfo;
        else
            return false;
    }
    (*pcontainer_)[color].address_ = addr;
    return true;
}

string ColorLicense::GetOwner(const type_Color &color) const
{
    return (*pcontainer_)[color].address_;
}

bool ColorLicense::IsColorExist(const type_Color &color) const
{
    if (color == DEFAULT_ADMIN_COLOR)
        return true;
    return (pcontainer_->find(color) != pcontainer_->end());
}

int64_t ColorLicense::NumOfCoins(const type_Color &color) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it == pcontainer_->end()) {
        return 0;
    }
    return it->second.num_of_coins_;
}

map<type_Color, pair<string, int64_t> > ColorLicense::ListLicense() const
{
    map<type_Color, pair<string, int64_t> > list;
    for (Tc_t::const_iterator it = pcontainer_->begin(); it != pcontainer_->end(); it++) {
        list[it->first] = make_pair(it->second.address_, it->second.num_of_coins_);
    }
    return list;
}

bool ColorLicense::GetLicenseInfo(const type_Color &color, CLicenseInfo &info) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it != pcontainer_->end()) {
        info = it->second.info_;
        return true;
    } else
        return false;
}

}

// Namespace for cache of block miners.
namespace block_miner
{
bool BlockMiner::Add(const string &addr)
{
    while (pcontainer_->size() >= 100) pcontainer_->pop_back();
    pcontainer_->push_front(make_pair(addr, pminer->NumOfMiners()));
    return true;
}

unsigned int BlockMiner::NumOfMined(string addr, unsigned int nAlliance) const
{
    unsigned int count = 1, nSameMiner = 0;


while (pcontainer_->size() >= 100) pcontainer_->pop_back();

#include "cache.h"
#include "main.h"
#include "policy/licenseinfo.h"
#include "util.h"
#include "utilerror.h"

using std::set;
using std::string;
using std::map;
using std::pair;
using std::list;
using std::exception;
using std::vector;

alliance_member::AllianceMember *palliance = NULL;
color_license::ColorLicense *plicense = NULL;
block_miner::BlockMiner *pblkminer = NULL;
miner::Miner *pminer = NULL;

// Namespace for cache of license structure.
namespace color_license
{

bool ColorLicense::SetOwner(const type_Color &color, const string addr, const CLicenseInfo *pinfo)
{
    // If the owner is assigned for the first time, license info should be assigned at the same time.
    // If the license already exists, license info should not be assigned.
    if (IsColorExist(color)) {
        if (pinfo)
            return false;
    } else {
        if (pinfo)
            (*pcontainer_)[color].info_ = *pinfo;
        else
            return false;
    }
    (*pcontainer_)[color].address_ = addr;
    return true;
}

string ColorLicense::GetOwner(const type_Color &color) const
{
    return (*pcontainer_)[color].address_;
}

bool ColorLicense::IsColorExist(const type_Color &color) const
{
    if (color == DEFAULT_ADMIN_COLOR)
        return true;
    return (pcontainer_->find(color) != pcontainer_->end());
}

int64_t ColorLicense::NumOfCoins(const type_Color &color) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it == pcontainer_->end()) {
        return 0;
    }
    return it->second.num_of_coins_;
}

map<type_Color, pair<string, int64_t> > ColorLicense::ListLicense() const
{
    map<type_Color, pair<string, int64_t> > list;
    for (Tc_t::const_iterator it = pcontainer_->begin(); it != pcontainer_->end(); it++) {
        list[it->first] = make_pair(it->second.address_, it->second.num_of_coins_);
    }
    return list;
}

bool ColorLicense::GetLicenseInfo(const type_Color &color, CLicenseInfo &info) const
{
    Tc_t::iterator it = pcontainer_->find(color);
    if (it != pcontainer_->end()) {
        info = it->second.info_;
        return true;
    } else
        return false;
}

}

// Namespace for cache of block miners.
namespace block_miner
{
bool BlockMiner::Add(const string &addr)
{

    pcontainer_->push_front(make_pair(addr, pminer->NumOfMiners()));
    return true;
}

unsigned int BlockMiner::NumOfMined(string addr, unsigned int nAlliance) const
{
    unsigned int count = 1, nSameMiner = 0;
    for (list<pair<string, unsigned int> >::iterator it = pcontainer_->begin();
         count <= Params().DynamicMiner() && count < nAlliance && it != pcontainer_->end(); it++) {
        if (it->first == addr) nSameMiner++;
        count++;
    }
    return nSameMiner;
}
}


/** <!--
 *
 *
 *
 *  If you would like this software to be made available to you under an
 *  alternate commercial license please email support@veyesys.com
 *  for more information.
 *
 * -->
 */
#include "client/storclient.hpp"

StorClient::StorClient(VidStor &stor, StorFactoryNotifyInterface &pNotify)
:m_stor(stor), m_pNotify(pNotify),
m_Quit(false), StorWebSocketClient(stor.strip(), stor.strport(), LINK_PROTO_WS_PATH)
{
	StartKeepThread();
}

StorClient::~StorClient()
{

}

bool StorClient::StorClientStart()
{
	StartKeepThread();
	return true;
}

bool StorClient::ProcessRecvMsg(char *data, size_t data_len)
{
	/* lock guard */
	std::lock_guard<std::mutex> guard(m_lock);
	std::string strMsg(data, data_len);
	Link::LinkCmd cmd;
	::google::protobuf::util::Status status =
		::google::protobuf::util::JsonStringToMessage(strMsg, &cmd);
	if (!status.ok())
	{
		return false;
	}

	switch (cmd.type())
	{
		case Link::LINK_CMD_LOGIN_RESP:
		{
			return ProcessLoginResp(cmd, m_stor.struser(), m_stor.strpasswd());
			break;
		}
		case Link::LINK_CMD_CAM_LIST_RESP:
		{
			return ProcessCamListResp(cmd);
			break;
		}
		case Link::LINK_CMD_CAM_ADD_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camaddnotify())
			{
				const LinkCamAddNotify& pCam =  cmd.camaddnotify();

				VidCamera *pNewCam = m_cCamList.add_cvidcamera();
				*pNewCam = pCam.ccam();

				data.cId.set_strcameraid(pCam.ccam().strid());
				data.cId.set_strstorid(m_stor.strid());
				data.cCam = pCam.ccam();
				data.type = STOR_FACTORY_CAMERA_ADD;
				m_pNotify.CallChange(data);

			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_DEL_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();
				VidCameraList cameraListNew;

				for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
				{
					const VidCamera &cam = m_cCamList.cvidcamera(i);
					if (cam.strid() != pCam.strid())
					{
						VidCamera *pNewCam =
								cameraListNew.add_cvidcamera();
						*pNewCam = cam;
					}
				}
				m_cCamList = cameraListNew;

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_DEL;
				m_pNotify.CallChange(data);
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_ONLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_ONLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_OFFLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_OFFLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_ON_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_ON;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_OFF_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_OFF;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_EVENT_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_evnetnotify())
			{
				const LinkEventNotify& pNotify =  cmd.evnetnotify();
				VidEvent *pEvent = new VidEvent;
				*pEvent = pNotify.cevent();

				m_pNotify.OnEvent((VidEvent &)(pNotify.cevent()), m_stor);
			}
			return true;
			break;
		}

		default:
		   	return true;
	};
	m_msgId ++;
	m_lastCmd = cmd;
	return true;
}

bool StorClient::ProcessCamListResp(Link::LinkCmd &cmd)
{
	if (!cmd.has_camlistresp())
	{
		return false;
	}

	const LinkListCamResp& pResp =  cmd.camlistresp();

	XGuard guard(m_cMutex);

	UpdateVidCameraList(pResp.clist());
	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_ONLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

bool StorClient::ProcessOffline()
{
	XGuard guard(m_cMutex);

	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_OFFLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

{
	Login(m_stor.struser(), m_stor.strpasswd(), "Nonce");
	return true;
}

StorClientOnlineMap StorClient::GetVidCameraOnlineList()
{
	if (m_bOnline == false)
	{
		StorClientOnlineMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamOnlineList;
}

StorClientRecMap StorClient::GetVidCameraRecList()
{
	if (m_bOnline == false)
	{
		StorClientRecMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamRecList;
}

bool StorClient::GetCameraConf(astring strCameraId, VidCamera &pCam)
{
	if (m_bOnline == false)
	{
		return false;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCameraId)
		{
			pCam = cam;
			return true;
		}
	}

	return false;
}

VidCameraList StorClient::GetVidCameraList()
{
	if (m_bOnline == false)
	{
		VidCameraList empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_cCamList;
}

astring StorClient::GetVidCameraName(astring strCam)
{
	astring empty;

	if (m_bOnline == false)
	{
		return empty;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCam)
		{
			return cam.strname();
		}
	}

	return empty;

}

bool StorClient::AddCam(VidCamera &pParam)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_ADD_CAM_REQ);
	LinkAddCamReq * req = new LinkAddCamReq;
	VidCamera *newCam = new VidCamera;
	*newCam = pParam;
	req->set_allocated_ccam(newCam);

	cmd.set_allocated_addcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::DeleteCam(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_DEL_CAM_REQ);
	LinkDelCamReq * req = new LinkDelCamReq;
	req->set_strid(strId);

	cmd.set_allocated_delcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}
	return true;
}

void StorClient::UpdateVidCameraList(const VidCameraList &list)
{
	/* Clean the list */
	VidCameraList empty;
	m_cCamList = list;

	int cameraSize = list.cvidcamera_size();

	for (s32 i = 0; i < list.cvidcamera_size(); i ++)
	{
		VidCamera cam = list.cvidcamera(i);
		m_CamOnlineList[cam.strid()] = cam.bonline();
		m_CamRecList[cam.strid()] = cam.brec();
	}

	return;
}

bool StorClient::SearchEvent(astring strId, s64 nStart, s64 nEnd)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_EVENT_SEARCH_REQ);
	LinkEventSearchReq * req = new LinkEventSearchReq;
	req->set_strid(strId);
	req->set_nstart(nStart);
	req->set_nend(nEnd);

	cmd.set_allocated_eventsearchreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::RegRealEvent()
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_REG_EVENT_REQ);
	LinkRegEventReq * req = new LinkRegEventReq;

	cmd.set_allocated_regeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::UnRegRealEvent()
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_UNREG_EVENT_REQ);
	LinkUnRegEventReq * req = new LinkUnRegEventReq;

	cmd.set_allocated_unregeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;

}

bool StorClient::HandleEvent(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_HANDLE_EVENT_REQ);
	LinkHandleEventReq * req = new LinkHandleEventReq;
	req->set_strid(strId);

	cmd.set_allocated_handleeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::PtzCmd(astring strId, u32 action, double param)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_PTZ_CMD);
	LinkPtzCmd * req = new LinkPtzCmd;
	req->set_strid(strId);
	req->set_naction(action);
	req->set_nparam(param);

	cmd.set_allocated_ptzcmd(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::GetOnline()
{
	return m_bOnline;
}


/** <!--
 *
 *
 *
 *  If you would like this software to be made available to you under an
 *  alternate commercial license please email support@veyesys.com
 *  for more information.
 *
 * -->
 */
#include "client/storclient.hpp"

StorClient::StorClient(VidStor &stor, StorFactoryNotifyInterface &pNotify)
:m_stor(stor), m_pNotify(pNotify),
m_Quit(false), StorWebSocketClient(stor.strip(), stor.strport(), LINK_PROTO_WS_PATH)
{
	StartKeepThread();
}

StorClient::~StorClient()
{

}

bool StorClient::StorClientStart()

bool StorClient::ProcessRecvMsg(char *data, size_t data_len)
{
	/* lock guard */
	std::lock_guard<std::mutex> guard(m_lock);
	std::string strMsg(data, data_len);
	Link::LinkCmd cmd;
	::google::protobuf::util::Status status =
		::google::protobuf::util::JsonStringToMessage(strMsg, &cmd);
	if (!status.ok())
	{
		return false;
	}

	switch (cmd.type())
	{
		case Link::LINK_CMD_LOGIN_RESP:
		{
			return ProcessLoginResp(cmd, m_stor.struser(), m_stor.strpasswd());
			break;
		}
		case Link::LINK_CMD_CAM_LIST_RESP:
		{
			return ProcessCamListResp(cmd);
			break;
		}
		case Link::LINK_CMD_CAM_ADD_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camaddnotify())
			{
				const LinkCamAddNotify& pCam =  cmd.camaddnotify();

				VidCamera *pNewCam = m_cCamList.add_cvidcamera();
				*pNewCam = pCam.ccam();

				data.cId.set_strcameraid(pCam.ccam().strid());
				data.cId.set_strstorid(m_stor.strid());
				data.cCam = pCam.ccam();
				data.type = STOR_FACTORY_CAMERA_ADD;
				m_pNotify.CallChange(data);

			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_DEL_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();
				VidCameraList cameraListNew;

				for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
				{
					const VidCamera &cam = m_cCamList.cvidcamera(i);
					if (cam.strid() != pCam.strid())
					{
						VidCamera *pNewCam =
								cameraListNew.add_cvidcamera();
						*pNewCam = cam;
					}
				}
				m_cCamList = cameraListNew;

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_DEL;
				m_pNotify.CallChange(data);
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_ONLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_ONLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_OFFLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_OFFLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_ON_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_ON;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_OFF_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_OFF;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_EVENT_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_evnetnotify())
			{
				const LinkEventNotify& pNotify =  cmd.evnetnotify();
				VidEvent *pEvent = new VidEvent;
				*pEvent = pNotify.cevent();

				m_pNotify.OnEvent((VidEvent &)(pNotify.cevent()), m_stor);
			}
			return true;
			break;
		}

		default:
		   	return true;
	};
	m_msgId ++;
	m_lastCmd = cmd;
	return true;
}

bool StorClient::ProcessCamListResp(Link::LinkCmd &cmd)
{
	if (!cmd.has_camlistresp())
	{
		return false;
	}

	const LinkListCamResp& pResp =  cmd.camlistresp();

	XGuard guard(m_cMutex);

	UpdateVidCameraList(pResp.clist());
	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_ONLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

bool StorClient::ProcessOffline()
{
	XGuard guard(m_cMutex);

	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_OFFLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

bool StorClient::ProcessOnline()
{
	Login(m_stor.struser(), m_stor.strpasswd(), "Nonce");
	return true;
}

StorClientOnlineMap StorClient::GetVidCameraOnlineList()
{
	if (m_bOnline == false)
	{
		StorClientOnlineMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamOnlineList;
}

StorClientRecMap StorClient::GetVidCameraRecList()
{
	if (m_bOnline == false)
	{
		StorClientRecMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamRecList;
}

bool StorClient::GetCameraConf(astring strCameraId, VidCamera &pCam)
{
	if (m_bOnline == false)
	{
		return false;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCameraId)
		{
			pCam = cam;
			return true;
		}
	}

	return false;
}

VidCameraList StorClient::GetVidCameraList()
{
	if (m_bOnline == false)
	{
		VidCameraList empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_cCamList;
}

astring StorClient::GetVidCameraName(astring strCam)
{
	astring empty;

	if (m_bOnline == false)
	{
		return empty;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCam)
		{
			return cam.strname();
		}
	}

	return empty;

}

bool StorClient::AddCam(VidCamera &pParam)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_ADD_CAM_REQ);
	LinkAddCamReq * req = new LinkAddCamReq;
	VidCamera *newCam = new VidCamera;
	*newCam = pParam;
	req->set_allocated_ccam(newCam);

	cmd.set_allocated_addcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::DeleteCam(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_DEL_CAM_REQ);
	LinkDelCamReq * req = new LinkDelCamReq;
	req->set_strid(strId);

	cmd.set_allocated_delcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}
	return true;
}

void StorClient::UpdateVidCameraList(const VidCameraList &list)
{
	/* Clean the list */
	VidCameraList empty;
	m_cCamList = list;

	int cameraSize = list.cvidcamera_size();

	for (s32 i = 0; i < list.cvidcamera_size(); i ++)
	{
		VidCamera cam = list.cvidcamera(i);
		m_CamOnlineList[cam.strid()] = cam.bonline();
		m_CamRecList[cam.strid()] = cam.brec();
	}

	return;
}

bool StorClient::SearchEvent(astring strId, s64 nStart, s64 nEnd)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_EVENT_SEARCH_REQ);
	LinkEventSearchReq * req = new LinkEventSearchReq;
	req->set_strid(strId);
	req->set_nstart(nStart);
	req->set_nend(nEnd);

	cmd.set_allocated_eventsearchreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::RegRealEvent()
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_REG_EVENT_REQ);
	LinkRegEventReq * req = new LinkRegEventReq;

	cmd.set_allocated_regeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::UnRegRealEvent()
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_UNREG_EVENT_REQ);
	LinkUnRegEventReq * req = new LinkUnRegEventReq;

	cmd.set_allocated_unregeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;

}

bool StorClient::HandleEvent(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_HANDLE_EVENT_REQ);
	LinkHandleEventReq * req = new LinkHandleEventReq;
	req->set_strid(strId);

	cmd.set_allocated_handleeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::PtzCmd(astring strId, u32 action, double param)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_PTZ_CMD);
	LinkPtzCmd * req = new LinkPtzCmd;
	req->set_strid(strId);
	req->set_naction(action);
	req->set_nparam(param);

	cmd.set_allocated_ptzcmd(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::GetOnline()
{
	return m_bOnline;
}


/** <!--
 *
 *
 *
 *  If you would like this software to be made available to you under an
 *  alternate commercial license please email support@veyesys.com
 *  for more information.
 *
 * -->
 */
#include "client/storclient.hpp"

StorClient::StorClient(VidStor &stor, StorFactoryNotifyInterface &pNotify)
:m_stor(stor), m_pNotify(pNotify),
m_Quit(false), StorWebSocketClient(stor.strip(), stor.strport(), LINK_PROTO_WS_PATH)
{
	StartKeepThread();
}

StorClient::~StorClient()
{

}

bool StorClient::StorClientStart()
{
	StartKeepThread();
	return true;
}

bool StorClient::ProcessRecvMsg(char *data, size_t data_len)
{
	/* lock guard */
	std::lock_guard<std::mutex> guard(m_lock);
	std::string strMsg(data, data_len);
	Link::LinkCmd cmd;
	::google::protobuf::util::Status status =
		::google::protobuf::util::JsonStringToMessage(strMsg, &cmd);
	if (!status.ok())
	{
		return false;
	}

	switch (cmd.type())
	{
		case Link::LINK_CMD_LOGIN_RESP:
		{
			return ProcessLoginResp(cmd, m_stor.struser(), m_stor.strpasswd());
			break;
		}
		case Link::LINK_CMD_CAM_LIST_RESP:
		{
			return ProcessCamListResp(cmd);
			break;
		}
		case Link::LINK_CMD_CAM_ADD_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camaddnotify())
			{
				const LinkCamAddNotify& pCam =  cmd.camaddnotify();

				VidCamera *pNewCam = m_cCamList.add_cvidcamera();
				*pNewCam = pCam.ccam();

				data.cId.set_strcameraid(pCam.ccam().strid());
				data.cId.set_strstorid(m_stor.strid());
				data.cCam = pCam.ccam();
				data.type = STOR_FACTORY_CAMERA_ADD;
				m_pNotify.CallChange(data);

			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_DEL_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();
				VidCameraList cameraListNew;

				for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
				{
					const VidCamera &cam = m_cCamList.cvidcamera(i);
					if (cam.strid() != pCam.strid())
					{
						VidCamera *pNewCam =
								cameraListNew.add_cvidcamera();
						*pNewCam = cam;
					}
				}
				m_cCamList = cameraListNew;

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_DEL;
				m_pNotify.CallChange(data);
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_ONLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_ONLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_OFFLINE_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_OFFLINE;
				m_pNotify.CallChange(data);
				m_CamOnlineList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_ON_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_ON;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = true;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_CAM_REC_OFF_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_camidnotify())
			{
				const LinkCamIdNotify& pCam =  cmd.camidnotify();

				data.cId.set_strcameraid(pCam.strid());
				data.cId.set_strstorid(m_stor.strid());
				data.type = STOR_FACTORY_CAMERA_REC_OFF;
				m_pNotify.CallChange(data);
				m_CamRecList[pCam.strid()] = false;
			}
			return true;
			break;
		}
		case Link::LINK_CMD_EVENT_NOTIFY:
		{
			StorFactoryChangeData data;
			if (cmd.has_evnetnotify())
			{
				const LinkEventNotify& pNotify =  cmd.evnetnotify();
				VidEvent *pEvent = new VidEvent;
				*pEvent = pNotify.cevent();

				m_pNotify.OnEvent((VidEvent &)(pNotify.cevent()), m_stor);
			}
			return true;
			break;
		}

		default:
		   	return true;
	};
	m_msgId ++;
	m_lastCmd = cmd;
	return true;
}

bool StorClient::ProcessCamListResp(Link::LinkCmd &cmd)
{
	if (!cmd.has_camlistresp())
	{
		return false;
	}

	const LinkListCamResp& pResp =  cmd.camlistresp();

	XGuard guard(m_cMutex);

	UpdateVidCameraList(pResp.clist());
	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_ONLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

bool StorClient::ProcessOffline()
{
	XGuard guard(m_cMutex);

	StorFactoryChangeData data;
	data.cId.set_strstorid(m_stor.strid());
	data.type = STOR_FACTORY_STOR_OFFLINE;
	m_bOnline = true;
	guard.Release();
	m_pNotify.CallChange(data);
	guard.Acquire();

	return true;
}

bool StorClient::ProcessOnline()
{
	Login(m_stor.struser(), m_stor.strpasswd(), "Nonce");
	return true;
}

StorClientOnlineMap StorClient::GetVidCameraOnlineList()
{
	if (m_bOnline == false)
	{
		StorClientOnlineMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamOnlineList;
}

StorClientRecMap StorClient::GetVidCameraRecList()
{
	if (m_bOnline == false)
	{
		StorClientRecMap empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_CamRecList;
}

bool StorClient::GetCameraConf(astring strCameraId, VidCamera &pCam)
{
	if (m_bOnline == false)
	{
		return false;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCameraId)
		{
			pCam = cam;
			return true;
		}
	}

	return false;
}

VidCameraList StorClient::GetVidCameraList()
{
	if (m_bOnline == false)
	{
		VidCameraList empty;
		return empty;
	}

	XGuard guard(m_cMutex);
	return m_cCamList;
}

astring StorClient::GetVidCameraName(astring strCam)
{
	astring empty;

	if (m_bOnline == false)
	{
		return empty;
	}

	XGuard guard(m_cMutex);

	int cameraSize = m_cCamList.cvidcamera_size();

	for (s32 i = 0; i < m_cCamList.cvidcamera_size(); i ++)
	{
		const VidCamera &cam = m_cCamList.cvidcamera(i);
		if (cam.strid() == strCam)
		{
			return cam.strname();
		}
	}

	return empty;

}

bool StorClient::AddCam(VidCamera &pParam)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_ADD_CAM_REQ);
	LinkAddCamReq * req = new LinkAddCamReq;
	VidCamera *newCam = new VidCamera;
	*newCam = pParam;
	req->set_allocated_ccam(newCam);

	cmd.set_allocated_addcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::DeleteCam(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_DEL_CAM_REQ);
	LinkDelCamReq * req = new LinkDelCamReq;
	req->set_strid(strId);

	cmd.set_allocated_delcamreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}
	return true;
}

void StorClient::UpdateVidCameraList(const VidCameraList &list)
{
	/* Clean the list */
	VidCameraList empty;
	m_cCamList = list;

	int cameraSize = list.cvidcamera_size();

	for (s32 i = 0; i < list.cvidcamera_size(); i ++)
	{
		VidCamera cam = list.cvidcamera(i);
		m_CamOnlineList[cam.strid()] = cam.bonline();
		m_CamRecList[cam.strid()] = cam.brec();
	}

	return;
}

bool StorClient::SearchEvent(astring strId, s64 nStart, s64 nEnd)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_EVENT_SEARCH_REQ);
	LinkEventSearchReq * req = new LinkEventSearchReq;
	req->set_strid(strId);
	req->set_nstart(nStart);
	req->set_nend(nEnd);

	cmd.set_allocated_eventsearchreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::RegRealEvent()
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_REG_EVENT_REQ);
	LinkRegEventReq * req = new LinkRegEventReq;

	cmd.set_allocated_regeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::UnRegRealEvent()
{
	XGu

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_UNREG_EVENT_REQ);
	LinkUnRegEventReq * req = new LinkUnRegEventReq;

	cmd.set_allocated_unregeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;

}

bool StorClient::HandleEvent(astring strId)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_HANDLE_EVENT_REQ);
	LinkHandleEventReq * req = new LinkHandleEventReq;
	req->set_strid(strId);

	cmd.set_allocated_handleeventreq(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::PtzCmd(astring strId, u32 action, double param)
{
	XGuard guard(m_cMutex);

	if (Connect() == false)
	{
		return false;
	}

	Link::LinkCmd cmd;
	cmd.set_type(Link::LINK_CMD_PTZ_CMD);
	LinkPtzCmd * req = new LinkPtzCmd;
	req->set_strid(strId);
	req->set_naction(action);
	req->set_nparam(param);

	cmd.set_allocated_ptzcmd(req);
	std::string strMsg;
	::google::protobuf::util::Status status =
		::google::protobuf::util::MessageToJsonString(cmd, &strMsg);
	if (!status.ok())
	{
		return false;
	}
	long long lastMsgId = 0;
	/* only lock here */
	{
		lastMsgId = m_msgId;
	}

	if (SendMsg(strMsg) == false)
	{
		return false;
	}

	return true;
}

bool StorClient::GetOnline()
{
	return m_bOnline;
}