//----------------------------------------------------------------------------------------------
int ObjectSerializer::SerializeUserDefinedType(ISerializable *pObj, TypeNode* pType, bool isPtr, fstream& pen)
{
	int     size = 0;
	bool    isNull = false;

	if (isPtr)
	{
		// Access the pointer pointed by the pointer to pointer
		pObj = (*(ISerializable**)pObj);
		int         length = 0;
		string      typeName;
		char        buffer[MaxTypeNameLength + 1];

		isNull = (NULL == pObj);
		pen.write(reinterpret_cast<char*>(&isNull), sizeof(bool));

		if (!isNull)
		{
			auto        objLayout = pObj->GetObjectLayout();

			typeName = g_ObjectFactory.FromCName(objLayout.CName());

			PerformLateBinding(pObj, pType);

			length = typeName.size();
			_ASSERTE(length <= MaxTypeNameLength);
			strcpy_s(buffer, typeName.c_str());
			buffer[length] = 0;
			pen.write(buffer, MaxTypeNameLength + 1);

			Iterator* addresses = objLayout.GetIterator();
			unsigned* addr32;
			for (int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
			{
				_ASSERTE(memberIdx < pType->Children.size());
				addr32 = reinterpret_cast<unsigned*>(addresses->Current());
				SerializeType(reinterpret_cast<char*>(*addr32), pType->Children[memberIdx].Ptr32, pen);
			}
		}
		size = sizeof(unsigned);
	}
	else
	{
		auto objLayout = pObj->GetObjectLayout();
		Iterator* addresses = objLayout.GetIterator();
		unsigned* addr32;
		for (int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
		{
			_ASSERTE(memberIdx < pType->Children.size());
			addr32 = reinterpret_cast<unsigned*>(addresses->Current());
			SerializeType(reinterpret_cast<char*>(*addr32), pType->Children[memberIdx].Ptr32, pen);
		}

		size = objLayout.TypeSize();
	}

	return size;
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::DeserializeUserDefinedType(char* p_fieldAddress, TypeNode* p_type, bool p_isPtr, fstream& p_eye)
{
    int     size = 0;
    UserObject* object = NULL;
    bool    isNull = false;

    if(p_isPtr)
    {
        unsigned* addr32;
        p_eye.read(reinterpret_cast<char*>(&isNull), sizeof(bool));
        addr32 = reinterpret_cast<unsigned*>(p_fieldAddress);

        if(!isNull)
        {
            string  typeName;
            char    buffer[MaxTypeNameLength + 1];

            p_eye.read(buffer, MaxTypeNameLength + 1);
            typeName = buffer;
            object = static_cast<UserObject*>(g_ObjectFactory.GetObject(typeName)->Prototype());

            PerformLateBinding(object, p_type);

            object->InitializeAddresses();

            Iterator* addresses = object->GetIterator();
            unsigned* addr32;
            for(int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
            {
                _ASSERTE(memberIdx < p_type->Children.size());
                addr32 = reinterpret_cast<unsigned*>(addresses->Current());
                DeserializeType(reinterpret_cast<char*>(*addr32), p_type->Children[memberIdx].Ptr32, p_eye);
            }
        }

        *addr32 = reinterpret_cast<unsigned>(object);
        size = sizeof(unsigned);
    }
    else
    {
        object = reinterpret_cast<UserObject*>(p_fieldAddress);
        object->InitializeAddresses();

        Iterator* addresses = object->GetIterator();
        unsigned* addr32;
        for(int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
        {
            _ASSERTE(memberIdx < p_type->Children.size());
            addr32 = reinterpret_cast<unsigned*>(addresses->Current());
            DeserializeType(reinterpret_cast<char*>(*addr32), p_type->Children[memberIdx].Ptr32, p_eye);
        }

        size = object->TypeSize();
    }

    return size;
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::DeserializeUserDefinedType(ISerializable* pMem, TypeNode* pType, bool isPtr, fstream& eye)
{
	int     size = 0;
	ISerializable* pObj = NULL;
	bool    isNull = false;

	if (isPtr)
	{
		unsigned* addr32;
		eye.read(reinterpret_cast<char*>(&isNull), sizeof(bool));
		addr32 = reinterpret_cast<unsigned*>(pMem);

		if (!isNull)
		{
			string  typeName;
			char    buffer[MaxTypeNameLength + 1];

			eye.read(buffer, MaxTypeNameLength + 1);
			typeName = buffer;
			pObj = static_cast<ISerializable*>(g_ObjectFactory.Create(typeName));

			PerformLateBinding(pObj, pType);

			auto objLayout = pObj->GetObjectLayout();
			Iterator* addresses = objLayout.GetIterator();
			unsigned* addr32;
			for (int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
			{
				_ASSERTE(memberIdx < pType->Children.size());
				addr32 = reinterpret_cast<unsigned*>(addresses->Current());
				DeserializeType(reinterpret_cast<char*>(*addr32), pType->Children[memberIdx].Ptr32, eye);
			}
		}

		*addr32 = reinterpret_cast<unsigned>(pObj);
		size = sizeof(unsigned);
	}
	else
	{
		pObj = reinterpret_cast<ISerializable*>(pMem);

		auto objLayout = pObj->GetObjectLayout();
		Iterator* addresses = objLayout.GetIterator();
		unsigned* addr32;
		for (int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
		{
			_ASSERTE(memberIdx < pType->Children.size());
			addr32 = reinterpret_cast<unsigned*>(addresses->Current());
			DeserializeType(reinterpret_cast<char*>(*addr32), pType->Children[memberIdx].Ptr32, eye);
		}

		size = objLayout.TypeSize();
	}

	return size;
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::DeserializePair(ISerializable* pObj, TypeNode* pType, fstream& eye)
{
	// Pointer to pair is not supported
	_ASSERTE(pType->Indirection == false);

	auto objLayout = pObj->GetObjectLayout();
	Iterator* addresses = objLayout.GetIterator();
	unsigned* addr32;
	for (int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
	{
		addr32 = reinterpret_cast<unsigned*>(addresses->Current());
		DeserializeType(reinterpret_cast<char*>(*addr32), pType->TemplateArguments[memberIdx], eye);
	}

	return objLayout.TypeSize();
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::DeserializePair(char* p_fieldAddress, TypeNode* p_type, fstream& p_eye)
{
    // Pointer to pair is not supported
    _ASSERTE(p_type->Indirection == false);

    UserObject* object = reinterpret_cast<UserObject*>(p_fieldAddress);
    object->InitializeAddresses();

    Iterator* addresses = object->GetIterator();
    unsigned* addr32;
    for(int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
    {
        addr32 = reinterpret_cast<unsigned*>(addresses->Current());
        DeserializeType(reinterpret_cast<char*>(*addr32), p_type->TemplateArguments[memberIdx], p_eye);
    }

    return object->TypeSize();
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::SerializeContainerMap(char* p_fieldAddress, TypeNode* p_type, fstream& p_pen)
{
    // Pointer to map is not supported
    _ASSERTE(p_type->Indirection == false);
    _ASSERTE(p_type->TemplateArguments.size() == 1);

    Container*  container   = reinterpret_cast<Container*>(p_fieldAddress);
    Iterator*   itr         = container->GetIterator();
    int         count       = container->ContainerCount();

    p_pen.write(reinterpret_cast<char*>(&count), sizeof(int));
    while(itr->MoveNext())
    {
        SerializeType(itr->Current(), p_type->TemplateArguments[0], p_pen);
    }

    return container->TypeSize();
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::SerializeContainerSet(ISerializable* pObj, TypeNode* pType, fstream& pen)
{
	// Pointer to set is not supported
	_ASSERTE(pType->Indirection == false);
	_ASSERTE(pType->TemplateArguments.size() == 1);

	auto        objLayout = pObj->GetObjectLayout();
	IContainer* pContainer = dynamic_cast<IContainer*>(pObj);
	_ASSERTE(pContainer);
	Iterator*   itr = objLayout.GetIterator();
	int         count = pContainer->ContainerCount();

	pen.write(reinterpret_cast<char*>(&count), sizeof(int));
	while (itr->MoveNext())
	{
		SerializeType(itr->Current(), pType->TemplateArguments[0], pen);
	}

	return objLayout.TypeSize();
}
//----------------------------------------------------------------------------------------------
int ObjectSerializer::SerializeUserDefinedType(char* p_fieldAddress, TypeNode* p_type, bool p_isPtr, fstream& p_pen)
{
    int     size = 0;
    UserObject* object = NULL;
    bool    isNull = false;
    if(p_isPtr)
    {
        int         length = 0;
        string      typeName;
        char        buffer[MaxTypeNameLength + 1];
        unsigned*   addr32 = reinterpret_cast<unsigned*>(p_fieldAddress);

        isNull = (NULL == *addr32);
        p_pen.write(reinterpret_cast<char*>(&isNull), sizeof(bool));

        if(!isNull)
        {
            object = reinterpret_cast<UserObject*>(*addr32);

            typeName = g_ObjectFactory.FromCName(object->CName());

            PerformLateBinding(object, p_type);

            length = typeName.size();
            _ASSERTE(length <= MaxTypeNameLength);
            strcpy(buffer, typeName.c_str());
            buffer[length] = 0;
            p_pen.write(buffer, MaxTypeNameLength + 1);

            object->InitializeAddresses();

            Iterator* addresses = object->GetIterator();
            unsigned* addr32;
            for(int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
            {
                _ASSERTE(memberIdx < p_type->Children.size());
                addr32 = reinterpret_cast<unsigned*>(addresses->Current());
                SerializeType(reinterpret_cast<char*>(*addr32), p_type->Children[memberIdx].Ptr32, p_pen);
            }
        }
        size = sizeof(unsigned);
    }
    else
    {
        object = reinterpret_cast<UserObject*>(p_fieldAddress);
        object->InitializeAddresses();

        Iterator* addresses = object->GetIterator();
        unsigned* addr32;
        for(int memberIdx = 0; addresses->MoveNext(); ++memberIdx)
        {
            _ASSERTE(memberIdx < p_type->Children.size());
            addr32 = reinterpret_cast<unsigned*>(addresses->Current());
            SerializeType(reinterpret_cast<char*>(*addr32), p_type->Children[memberIdx].Ptr32, p_pen);
        }

        size = object->TypeSize();
    }

    return size;
}