//=============================================================================
// METHOD    : SPELLwsListDataHandler::read()
//=============================================================================
void SPELLwsListDataHandler::read()
{
	// Load the number of items
	unsigned int numItems = getStorage()->loadLong();

	// Create a list
	PyObject* listObject = PyList_New(numItems);

	for( unsigned int index = 0; index < numItems; index++)
	{
		// Load the item code
		SPELLwsData::Code code = loadDataCode();
		// Create an appropriate handler
		SPELLwsDataHandler* handler = SPELLwsDataHandlerFactory::createDataHandler(code);
		handler->setStorage(getStorage());
		// Read the data
		handler->read();
		// Add the item to the list
		PyList_SetItem(listObject, index, handler->getObject());
		delete handler;
	}

	// Set it as associated object
	setObject( listObject );
}
//=============================================================================
// METHOD    : SPELLwsListDataHandler::write()
//=============================================================================
void SPELLwsListDataHandler::write()
{
	assert( PyList_Check(getObject()));

	unsigned int numItems = PyList_Size( getObject() );

	// Store the number of items
	getStorage()->storeLong( (long) numItems );

	// Store each list item
	for( unsigned int index = 0; index < numItems; index++)
	{
		PyObject* item = PyList_GetItem( getObject(), index );

		try
		{
			SPELLwsDataHandler* handler = SPELLwsDataHandlerFactory::createDataHandler(item);
			handler->setStorage(getStorage());
			// Store the item data code. We need it for reading operation, in order to
			// know which type of handler to create.
			handler->storeDataCode();

			// IMPORTANT in the case of lists and dictionaries, we want to be able to continue
			// the storage evenif there is a problem in the handler processing at this point.
			// If that is the case, a fake empty object will be replaced by the object being
			// processed by the handler, and the dumping of this collection will continue.
			try
			{
				// Store the data
				handler->write();
			}
			catch(SPELLcoreException& ex)
			{
				std::string msg = "WARNING! Storage of element " + ISTR(index) + " failed: " + ex.what();
				LOG_WARN(msg);
				std::cerr << msg << std::endl;
				storeFakeObject( handler->getCode() );
			}
			delete handler;
		}
		catch(SPELLcoreException& ex)
		{
			std::string msg = "WARNING! Failed to create data handler: " + ex.what();
			LOG_WARN(msg);
			storeFakeObject( SPELLwsData::DATA_NONE );
		}

	}
}
//=============================================================================
// METHOD    : SPELLwsDictDataHandler::write()
//=============================================================================
void SPELLwsDictDataHandler::write()
{
	if (getObject() == NULL)
	{
		getStorage()->storeLong( -1 );
		return;
	}

	assert( PyDict_Check(getObject()));

	SPELLpyHandle keys = PyDict_Keys( getObject() );
	unsigned int numItems = PyList_Size( keys.get() );

	DEBUG("[DDH] Storing dictionary items (total " + ISTR(numItems) + ") address " + PSTR(getObject()));

	PyObject* key = NULL;
	PyObject* item = NULL;

	long toStore = 0;
	// Calculate the number of items to store
	// Store each list item
	DEBUG("[DDH] Keys of the dictionary:");
	for( unsigned int index = 0; index < numItems; index++)
	{
		key = PyList_GetItem( keys.get(), index );
		item = PyDict_GetItem( getObject(), key );
		if (SPELLwsWarmStartImpl::shouldFilter(key,item))
		{
			continue;
		}
		else
		{
			DEBUG("     - " + PYSSTR(key));
		}
		toStore++;
	}

	DEBUG("[DDH] Will store " + ISTR(toStore) + " keys");
	// Store the number of items
	getStorage()->storeLong( (long) toStore );

	DEBUG("[DDH] Start checking items");
	if (toStore>0)
	{
		// Store each list item
		for( unsigned int index = 0; index < numItems; index++)
		{
			key = PyList_GetItem( keys.get(), index );
			item = PyDict_GetItem( getObject(), key );

			DEBUG("[DDH] Checking item " + PYCREPR(key));

			// Do not consider filtered values
			if (SPELLwsWarmStartImpl::shouldFilter(key,item)) continue;

			SPELLpythonHelper::instance().checkError();

			DEBUG("		[DDH] Key index " + ISTR(index));
			DEBUG("		[DDH] Key to use" + PYREPR(key));
			DEBUG("		[DDH] Item type:" + PYREPR(PyObject_Type(item)));

			// Handler for the key
			SPELLwsObjectDataHandler keyHandler(key);
			keyHandler.setStorage(getStorage());

			DEBUG("		[DDH] Creating handler");

			// Create a handler for the item
			SPELLwsDataHandler* handler = SPELLwsDataHandlerFactory::createDataHandler(item);
			handler->setStorage(getStorage());

			// Store the key
			DEBUG("		[DDH] Storing key: " + PYREPR(key));
			keyHandler.write();

			// Store the item data code in order to recognise it later
			DEBUG("		[DDH] Storing data code: " + SPELLwsData::codeStr(handler->getCode()));
			handler->storeDataCode();

			// IMPORTANT in the case of lists and dictionaries, we want to be able to continue
			// the storage even if there is a problem in the handler processing at this point.
			// If that is the case, a fake empty object will be replaced by the object being
			// processed by the handler, and the dumping of this collection will continue.
			try
			{
				if (handler->getCode() == SPELLwsData::DATA_CUSTOM_TYPE )
				{
					std::string msg = "WARNING! warm start not supported for custom Python types (" + PYREPR(key) + "=" + PYREPR(item) + ")";
					LOG_WARN(msg);
					SPELLexecutor::instance().getCIF().warning(msg);
					storeFakeObject( SPELLwsData::DATA_NONE );
				}
				else
				{
					// Store the value
					DEBUG("		[DDH] Storing value: " + PYREPR(item));
					handler->write();
					DEBUG("		[DDH] Storing value done");
				}
			}
			catch(SPELLcoreException& ex)
			{
				std::string msg = "WARNING! WS storage of element " + ISTR(index) + " failed: " + ex.what();
				LOG_WARN(msg);
				SPELLexecutor::instance().getCIF().warning(msg);
				storeFakeObject( handler->getCode() );
			}
			delete handler;
		}
	}

	DEBUG("[DDH] Storing dictionary done");
}
//=============================================================================
// METHOD    : SPELLwsDictDataHandler::read()
//=============================================================================
void SPELLwsDictDataHandler::read()
{
	DEBUG("[DDH] Loading dictionary items");
	// Load the number of items
	int numItems = getStorage()->loadLong();
	DEBUG("[DDH] Number of items " + ISTR(numItems));

	if (numItems == -1)
	{
		setObject(NULL);
		return;
	}

	// Create a dictionary
	PyObject* dictObject = PyDict_New();

	for( unsigned int index = 0; index < (unsigned) numItems; index++)
	{
		// We know that first an Object comes, as the key. So make the handler directly.
		SPELLwsObjectDataHandler keyHandler(NULL);
		keyHandler.setStorage(getStorage());
		DEBUG("		[DDH] Loading key");
		keyHandler.read();
		PyObject* key = keyHandler.getObject();
		DEBUG("		[DDH] Loaded key " + PYREPR(key));

		// Load the item code
		DEBUG("		[DDH] Loading data code");
		SPELLwsData::Code code = loadDataCode();
		DEBUG("		[DDH] Loaded data code " + SPELLwsData::codeStr(code));

		if (code == SPELLwsData::DATA_CUSTOM_TYPE )
		{
			std::string msg = "WARNING! warm start not supported for custom Python types (" + PYREPR(key) + ")";
			LOG_WARN(msg);
			SPELLexecutor::instance().getCIF().warning(msg);
			getStorage()->loadObject(); // Load none
			PyDict_SetItem(dictObject, key, Py_None);
		}
		else
		{
			// Create an appropriate handler
			SPELLwsDataHandler* handler = SPELLwsDataHandlerFactory::createDataHandler(code);
			handler->setStorage(getStorage());
			try
			{
				// Read the data
				DEBUG("		[DDH] Loading value");
				handler->read();
				DEBUG("		[DDH] Value loaded " + PYREPR(handler->getObject()));
				// Add the item to the dictionary
				PyDict_SetItem(dictObject, key, handler->getObject());
			}
			catch(SPELLcoreException& ex)
			{
				std::string msg = "Failed to recover dictionary item " + PYREPR(key) + ": " + ex.what();
				LOG_WARN(msg);
				SPELLexecutor::instance().getCIF().warning(msg);
				PyDict_SetItem(dictObject, key, Py_None);
			}
			delete handler;
			DEBUG("     [DDH] ");
		}
	}

	DEBUG("[DDH] Dictionary loaded");

	// Set it as associated object
	setObject( dictObject );
}