#include "testcommon/testcommon.h"
#include "spcore/coreruntime.h"
#include "spcore/configuration.h"
//#include "spcore/basictypes.h"

#include <assert.h>
#include <iostream>
#include <stdio.h>

using namespace spcore;

#define STR_SIZE 100
struct data {
	bool the_bool_true;
	bool the_bool_false;
	double the_double;
	double the_double_neg;
	int the_int;
	int the_int_neg;
	long long the_int64;
	long long the_int_neg64;
	char the_string[STR_SIZE];
};

void set_data (struct data* d) {
	memset (d, 0, sizeof(struct data));
	d->the_bool_true= true;
	d->the_bool_false= false;
	d->the_double= 12345.6789;
	d->the_double_neg= -12345.6789;
	d->the_int= 2147483640;
	d->the_int_neg= -2147483640;
	d->the_int64= 1152921504606846976LL;
	d->the_int_neg64= -1152921504606846976LL;
	memset (d->the_string, 0, STR_SIZE);
	strcpy (d->the_string, "String contents");
}

void write_data (IConfiguration* cfg, const struct data* d) {
	// Write data
	if (!cfg->WriteBool("the_bool_true", d->the_bool_true)) ExitErr ("Write: the_bool_true");
	if (!cfg->WriteBool("the_bool_false", d->the_bool_false)) ExitErr ("Write: the_bool_false");
	if (!cfg->WriteDouble("the_double", d->the_double)) ExitErr ("Write: the_double");
	if (!cfg->WriteDouble("the_double_neg", d->the_double_neg)) ExitErr ("Write: the_double_neg");
	if (!cfg->WriteInt("the_int", d->the_int)) ExitErr ("Write: the_int");
	if (!cfg->WriteInt("the_int_neg", d->the_int_neg)) ExitErr ("Write: the_int_neg");
	if (!cfg->WriteInt64("the_int64", d->the_int64)) ExitErr ("Write: the_int64");
	if (!cfg->WriteInt64("the_int_neg64", d->the_int_neg64)) ExitErr ("Write: the_int_neg64");
	if (!cfg->WriteString("the_string", d->the_string)) ExitErr ("Write: the_string");
}

void read_data (const IConfiguration* cfg, struct data* d)
{
	// Write data
	if (!cfg->ReadBool("the_bool_true", &d->the_bool_true)) ExitErr ("Read: the_bool_true");
	if (!cfg->ReadBool("the_bool_false", &d->the_bool_false)) ExitErr ("Read: the_bool_false");
	if (!cfg->ReadDouble("the_double", &d->the_double)) ExitErr ("Read: the_double");
	if (!cfg->ReadDouble("the_double_neg", &d->the_double_neg)) ExitErr ("Read: the_double_neg");
	if (!cfg->ReadInt("the_int", &d->the_int)) ExitErr ("Read: the_int");
	if (!cfg->ReadInt("the_int_neg", &d->the_int_neg)) ExitErr ("Read: the_int_neg");
	if (!cfg->ReadInt64("the_int64", &d->the_int64)) ExitErr ("Read: the_int64");
	if (!cfg->ReadInt64("the_int_neg64", &d->the_int_neg64)) ExitErr ("Read: the_int_neg64");
	
	const char* retStr;
	if (!cfg->ReadString("the_string", &retStr)) ExitErr ("Read: the_string");
	memset (d->the_string, 0, STR_SIZE);
	strcpy (d->the_string, retStr);
}

void compare (const struct data* d1, const struct data* d2)
{
	if (memcmp(d1, d2, sizeof(struct data))) ExitErr ("comparison error");
}

static
void DoTest()
{
	spcore::ICoreRuntime* core= spcore::getSpCoreRuntime();
	//DumpCoreRuntime(core);
	

	FILE* file= NULL;

	// Create 1 & save
	SmartPtr<IConfiguration> cfg1= core->GetConfiguration();
	file= fopen("test_spcore_configuration1.cfg", "w");
	if (!file) ExitErr ("Cannot open test_spcore_configuration1.cfg");
	struct data d1;
	set_data (&d1);
	write_data (cfg1.get(), &d1);
	if (!cfg1->Save(file)) ExitErr ("save failed");
	fclose (file);
	file= NULL;

	// Load 
	SmartPtr<IConfiguration> cfg2= core->GetConfiguration();
	file= fopen("test_spcore_configuration1.cfg", "r");
	if (!file) ExitErr ("Cannot open test_spcore_configuration1.cfg");
	struct data d2;
	memset (&d2, 0, sizeof(struct data));
	if (!cfg2->Load(file)) ExitErr ("load failed");
	fclose (file);
	file= NULL;
	read_data (cfg2.get(), &d2);
	compare (&d1, &d2);

	// Create path
	if (!cfg1->WriteBool("path/inside/one/path", true)) ExitErr ("path/inside/one/path");
	file= fopen("test_spcore_configuration2.cfg", "w");
	if (!file) ExitErr ("Cannot open test_spcore_configuration2.cfg");
	if (!cfg1->Save(file)) ExitErr ("save failed");
	fclose (file);

	// Set path
	if (cfg1->SetPath("..")) ExitErr ("..");
	if (!cfg1->SetPath("/path")) ExitErr ("/path");
	if (!cfg1->SetPath("..")) ExitErr ("..");
	if (!cfg1->SetPath("/")) ExitErr ("/");
	if (cfg1->SetPath("the_int64")) ExitErr ("the_int64");

	// Overwrite
	if (!cfg1->WriteBool("the_int64", false)) ExitErr ("overwrite the_int64");
	if (cfg1->WriteBool("path", false)) ExitErr ("overwrite path");

	// Remove
	if (!cfg1->Remove("path/inside/one")) ExitErr ("the_int64");

	// Save file
	file= fopen("test_spcore_configuration3.cfg", "w");
	if (!file) ExitErr ("Cannot open test_spcore_configuration3.cfg");
	if (!cfg1->Save(file)) ExitErr ("save failed");
	fclose (file);
}

int main (int, char**)
{
	DoTest();
	
	// Cleanup
	spcore::freeSpCoreRuntime();

	printf ("Test passed successfully\n");

	return 0;
}
