void CGenerateCSharpClasses::codeGenerate()

in src/codegen/tool/GenerateCSharpClasses.cpp [425:855]


void CGenerateCSharpClasses::codeGenerate(const schema::CObservableObjectInfo *pPropertyModelInfo)
{
    bool isViewModel = pPropertyModelInfo->getModelType() == schema::ModelTypeInfoType_ViewModel;

    std::wstring typeInfoName = toTypeInfoName(pPropertyModelInfo->getName());

    _typeInfoClasses[pPropertyModelInfo->getType()] = typeInfoName;

    std::wstring baseClass;

    std::wostringstream osInternalProperties;
    std::wostringstream osInitializeCommandProperties;
    std::wostringstream osInitializeCollectionProperties;
    std::wostringstream osInvokeInternalMethods;

    std::wostringstream osCommandCallbackInterface;
    std::wostringstream osExecuteCommandPropertyCallback;
    std::wostringstream osCanExecuteCommandPropertyCallback;
    std::wostringstream osInitializeCommandPropertiesCallback;

    const schema::CObservableObjectInfo *pBaseType = (schema::CObservableObjectInfo *)pPropertyModelInfo->getBaseType();
    if (pBaseType != nullptr)
    {
        baseClass = this->getNamespaceLookup(pBaseType->getParent().getNamespace());
        baseClass += L".";
        baseClass += toTypeInfoName(pBaseType->getName());
    }
    else
    {
        baseClass = isViewModel ? L"ViewModel" : L"ObservableObject";
    }

    // Iterate Properties
    for(schema::_PropertyIteratorType::const_iterator iter = pPropertyModelInfo->getProperties().begin();
        iter != pPropertyModelInfo->getProperties().end();
        ++iter)
    {
        bool isAncestorProperty = ((*iter)->getFlags() & PropertyFlagType_IsAncestor) != 0;
        bool isParentProperty = (*iter)->isParent();

        bool isCoreReadyOnly = isAncestorProperty || isParentProperty;

        // Emit Internal Property Access
        std::wstring propertyAccessName = (*iter)->getName();
        if (propertyAccessName == L"Invoke")
        {
            // workaround to prevent compiler to fail on this keyword
            propertyAccessName += L"_";
        }
        osInternalProperties << FormatW(
            _internalProperty_Template,
            (*iter)->getName().data(),
            toCSharpPropertyTypeInfo(*iter).data(),
            this->getNamespace().data(),
            typeInfoName.data(),
            propertyAccessName.data(),
            nullptr);

        // Emit Initialize Property
        if(!isCoreReadyOnly && (*iter)->getModelType())
        {
            schema::ModelTypeInfoType modelTypeInfoType = (*iter)->getModelType()->getModelType();

            if(modelTypeInfoType == schema::ModelTypeInfoType_Command)
            {
                const schema::CCommandTypeInfo *pCommmandModelInfo = (schema::CCommandTypeInfo *)((*iter)->getModelType());
                const schema::CPropertyTypeInfo *pParameterTypeInfo = pCommmandModelInfo->getParameterTypeInfo();
                const schema::CPropertyTypeInfo *pResutTypeInfo = pCommmandModelInfo->getResultTypeInfo();

                const bool isAsync = pCommmandModelInfo->getIsAsync();

                std::wstring typeIID;
                if (isSimpleCommand(pCommmandModelInfo))
                {
                    typeIID = FormatW(
                        L"new Guid(\"{0}\")",
                        isAsync ? _simpleAsyncCommandTypeId : _simpleCommandTypeId,
                        nullptr);
                }
                else if (isObjectObjectCommand(pCommmandModelInfo))
                {
                    typeIID = FormatW(
                        L"new Guid(\"{0}\")",
                        isAsync ? _objectObjectAsyncCommandTypeId : _objectObjectCommandTypeId,
                        nullptr);
                }
                else
                {
                    std::wstring commandModelInfoNameInc = getModelTypeInfoIncName(pCommmandModelInfo);

                    typeIID = FormatW(L"{0}.TypeInfoClass.IID_{1}",
                        this->getNamespaceLookup(pCommmandModelInfo->getParent().getNamespace()).c_str(),
                        commandModelInfoNameInc.c_str(),
                        nullptr);
                }

                std::wstring commandModelOptions = isAsync ?
                        L"(CommandOptions)(CommonModelOptions.IsFreeThreadApartment)":
                        L"CommandOptions.None";

                std::wstring cSharpParameterTypeInfo = toCSharpInterfacePropertyTypeInfo(pParameterTypeInfo);
                std::wstring cSharpResultTypeInfo = toCSharpInterfacePropertyTypeInfo(pResutTypeInfo);

                if (!_useClassInterfaceCallback)
                {
                    osInitializeCommandProperties << "\t\t\t" <<
                        FormatW(L"{0} = new ContainedCommand<{1},{2},{3}>({4},{5},\"{0}\");",
                        propertyAccessName.data(),
                        typeInfoName.data(),
                        cSharpParameterTypeInfo.data(),
                        cSharpResultTypeInfo.data(),
                        commandModelOptions.data(),
                        typeIID.data(),
                        nullptr) << std::endl;
                }

                osCommandCallbackInterface << "\t\t";
                bool isVoidResult = pResutTypeInfo->getPropertyType() == foundation::PropertyType_Empty;
                bool isVoidParameter = pParameterTypeInfo->getPropertyType() == foundation::PropertyType_Empty;
                if (isAsync || isVoidResult)
                {
                    osCommandCallbackInterface << "void";
                }
                else
                {
                    osCommandCallbackInterface << cSharpResultTypeInfo;
                }
                osCommandCallbackInterface << " Execute" << propertyAccessName << "(";

                std::wstring executeCallbackParams;


                if (!isVoidParameter)
                {
                    osCommandCallbackInterface << cSharpParameterTypeInfo << " parameter";
                    executeCallbackParams = FormatW(
                        L"parameter.{0}<{1}>()", 
                        isAsync ? L"GetAsyncCommandParameter" : L"AssertCast",
                        cSharpParameterTypeInfo.c_str(), 
                        nullptr);
                }

                if (isAsync)
                {
                    if (!isVoidParameter)
                    {
                        osCommandCallbackInterface << ",";
                        executeCallbackParams += L",";
                    }
                    osCommandCallbackInterface << "AsyncOperation asyncOperation";
                    executeCallbackParams += L"parameter.GetAsyncCommandOperation()";
                }
                osCommandCallbackInterface << ");" << std::endl;

                osExecuteCommandPropertyCallback << FormatW(_onExecuteCommandPropertyCallbackInternal_Template,
                    toTypeInfoName(pPropertyModelInfo->getName()).c_str(),
                    (*iter)->getName().data(),
                    executeCallbackParams.c_str(),
                    isAsync || isVoidResult ? L"" : L"result =",
                    nullptr);

                if (pCommmandModelInfo->getIsUnknownState())
                {
                    osCommandCallbackInterface << "\t\tbool CanExecute" << propertyAccessName << "(";
                    if (!isVoidParameter)
                    {
                        osCommandCallbackInterface << cSharpParameterTypeInfo << " parameter";
                    }
                    osCommandCallbackInterface << ");" << std::endl;
                    osCanExecuteCommandPropertyCallback << FormatW(
                        _onCanExecuteCommandPropertyCallbackInternal_Template,
                        toTypeInfoName(pPropertyModelInfo->getName()).c_str(),
                        (*iter)->getName().data(),
                        isVoidParameter ? L"" : FormatW(L"parameter.AssertCast<{0}>()", cSharpParameterTypeInfo.c_str(), nullptr).c_str(),
                        nullptr);
                }
                osInitializeCommandPropertiesCallback << "\t\t\t" <<
                    FormatW(L"model.SetPropertyInternal((uint){3}Properties.{0},PropertyModelHelper.CreatePropertyCommand({1},{2},(uint){3}Properties.{0},callbacks));",
                    propertyAccessName.data(),
                    commandModelOptions.data(),
                    typeIID.data(),
                    typeInfoName.data(),
                    nullptr) << std::endl;
                
            }

            else if(modelTypeInfoType == schema::ModelTypeInfoType_ObservableCollection || modelTypeInfoType == schema::ModelTypeInfoType_ObservableList)
            {
                std::wstring typeIID;

                const schema::CEnumerableTypeInfo *pCollectionModelInfo = (schema::CEnumerableTypeInfo *)((*iter)->getModelType());
                const schema::CPropertyTypeInfo *pItemTypeInfo = pCollectionModelInfo->getItemTypeInfo();
                if(pItemTypeInfo->getModelType() != nullptr)
                {
                    std::wstring collectionModelInfoNameInc = getModelTypeInfoIncName(pCollectionModelInfo);
                    typeIID = FormatW(L"{0}.TypeInfoClass.IID_{1}",
                        this->getNamespaceLookup(pCollectionModelInfo->getParent().getNamespace()).c_str(),
                        collectionModelInfoNameInc.c_str(), 
                        nullptr);
                }
                else
                {
                    // a 'Core' type
                    foundation::PropertyType propertyType = pItemTypeInfo->getPropertyType();
                    // lookup for supported 'Core' types
                    if(propertyType == foundation::PropertyType::PropertyType_String)
                    {
                        typeIID = L"StringType";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_Int16)
                    {
                        typeIID = L"Int16Type";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_UInt16)
                    {
                        typeIID = L"UInt16Type";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_Int32)
                    {
                        typeIID = L"Int32Type";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_UInt32)
                    {
                        typeIID = L"UInt32Type";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_Boolean)
                    {
                        typeIID = L"BooleanType";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_DateTime)
                    {
                        typeIID = L"DateTimeType";
                    }
                    else if(propertyType == foundation::PropertyType::PropertyType_UInt8)
                    {
                        typeIID = L"ByteType";
                    }
                    else
                    {
                        typeIID = L"ObjectType";
                    }
                    typeIID = L"CollectionModel." + typeIID;
                }
                osInitializeCollectionProperties << "\t\t\t" <<
                    FormatW(L"{0} = new CollectionModel({1},ObservableCollectionOptions.None);",propertyAccessName.data(),typeIID.data(),nullptr) << std::endl;
            }

        }
    }

    if (osCommandCallbackInterface.tellp())
    {
        const schema::CObservableObjectInfo *pCommandCallbackBaseType = nullptr;
        for (pCommandCallbackBaseType = pBaseType;
            pCommandCallbackBaseType != nullptr;
            pCommandCallbackBaseType = (const schema::CObservableObjectInfo *)pCommandCallbackBaseType->getBaseType())
        {
            if (countCommandProperties(pCommandCallbackBaseType))
            {
                break;
            }
        }

        _osCSharpClassesSrc << FormatW(
            _commandPropertyCallbackInterface_Template,
            typeInfoName.data(),
            osCommandCallbackInterface.str().data(),
            pCommandCallbackBaseType ?
                FormatW(L": {0}.I{1}CommandCallback",
                    this->getNamespaceLookup(pCommandCallbackBaseType->getParent().getNamespace()).c_str(),
                    toTypeInfoName(pCommandCallbackBaseType->getName()).c_str(),
                    nullptr
                ).c_str() :
                L"",
            nullptr
            );
        _osCSharpClassesSrc << FormatW(
            _commandPropertyCallbackClass_Template,
            typeInfoName.data(),
            osExecuteCommandPropertyCallback.str().data(),
            osCanExecuteCommandPropertyCallback.str().data(),
            pCommandCallbackBaseType ?
                FormatW(L" {0}.{1}",
                    this->getNamespaceLookup(pCommandCallbackBaseType->getParent().getNamespace()).c_str(),
                    toTypeInfoName(pCommandCallbackBaseType->getName()).c_str(),
                    nullptr
                ).c_str() :
                L"",
            osInitializeCommandPropertiesCallback.str().c_str(),
            nullptr
            );

    }

    std::wostringstream osMethodCallbackInterface;
    std::wostringstream osMethodCallbackInvokeCallback;

    // Iterate Methods
    for(schema::_MethodIteratorType::const_iterator iter = pPropertyModelInfo->getMethods().begin();
        iter != pPropertyModelInfo->getMethods().end();
        ++iter)
    {
        bool isVoidResult =
            (*iter)->getResultType()->getPropertyType() == foundation::PropertyType_Empty;

        osMethodCallbackInterface << "\t\t";
        if ((*iter)->getIsAsync() || isVoidResult)
        {
            osMethodCallbackInterface << "void";
        }
        else
        {
            osMethodCallbackInterface << toCSharpInterfacePropertyTypeInfo((*iter)->getResultType());
        }
        osMethodCallbackInterface << " ";
        osMethodCallbackInterface << (*iter)->getName();
        osMethodCallbackInterface << "(";

        std::wostringstream osInvokeParameters;

        for(schema::_MethodParamIteratorType::const_iterator iterParam = (*iter)->getParameters().begin();
            iterParam != (*iter)->getParameters().end();
            ++iterParam)
        {
            std::wstring cSharpTypeInfo = toCSharpInterfacePropertyTypeInfo(*iterParam);
            if (iterParam != (*iter)->getParameters().begin())
            {
                osMethodCallbackInterface << ",";
                osInvokeParameters << "," << std::endl;
            }
            osMethodCallbackInterface << cSharpTypeInfo << " " << (*iterParam)->getParameterName();

            osInvokeParameters << "\t\t\t\t\t";
            osInvokeParameters << "parameters[" << (int)(iterParam-(*iter)->getParameters().begin())
                << "].AssertCast<" << cSharpTypeInfo << ">()";
        }

        if ((*iter)->getIsAsync())
        {
            if ((*iter)->getParameters().size())
            {
                osInvokeParameters << "," << std::endl;
                osMethodCallbackInterface << ",";
            }
            osMethodCallbackInterface << "AsyncOperation asyncOperation";
            osInvokeParameters << "\t\t\t\t\t";
            osInvokeParameters << "parameters[" << (int)((*iter)->getParameters().size()) << "].AssertCast<AsyncOperation>()";
        }
        osMethodCallbackInterface << ");" << std::endl;

        std::wstring invokeName = L"\"Invoke" + (*iter)->getName() + L"\"";
        if ((*iter)->getIsAsync() || (*iter)->getParameters().size())
        {
            invokeName += L",";
        }

        bool isVoidResultCallback = (*iter)->getIsAsync() || isVoidResult;

        osMethodCallbackInvokeCallback << FormatW(_onInvokeCallbackInternal_Template,
            toTypeInfoName(pPropertyModelInfo->getName()).c_str(),
            (*iter)->getName().data(),
            osInvokeParameters.str().data(),
            isVoidResultCallback ? L"":L"result =",
            nullptr);

        osInvokeInternalMethods << FormatW(_onInvokeInternal_Template,
            toTypeInfoName(pPropertyModelInfo->getName()).c_str(),
            (*iter)->getName().data(),
            invokeName.data(),
            osInvokeParameters.str().data(),
            nullptr);
    }

    if (pPropertyModelInfo->getMethods().size())
    {
        const schema::CObservableObjectInfo *pMethodCallbackBaseType =
            pBaseType && pBaseType->getMethods().size() ? pBaseType :
            nullptr;

        _osCSharpClassesSrc << FormatW(
            _methodCallbackInterface_Template,
            typeInfoName.data(),
            osMethodCallbackInterface.str().data(),
            pMethodCallbackBaseType ?
                FormatW(L": {0}.I{1}MethodCallback", 
                    this->getNamespaceLookup(pBaseType->getParent().getNamespace()).c_str(),
                    toTypeInfoName(pBaseType->getName()).c_str(),
                    nullptr
                    ).c_str() :
                L"",
            nullptr
            );
        _osCSharpClassesSrc << FormatW(
            _methodCallbackClass_Template,
            typeInfoName.data(),
            osMethodCallbackInvokeCallback.str().data(),
            pMethodCallbackBaseType ?
                FormatW(L"{0}.{1}",
                    this->getNamespaceLookup(pBaseType->getParent().getNamespace()).c_str(),
                    toTypeInfoName(pBaseType->getName()).c_str(),
                    nullptr
                    ).c_str() :
                L"",
            pMethodCallbackBaseType ? L"new" : L"",
            nullptr
            );

    }
    // Emit C# Class implementation
    _osCSharpClassesSrc << FormatW(
        isViewModel ? _implementViewModelClass_Template:_implementModelClass_Template,
        typeInfoName.data(),
        baseClass.data(),
        L"",
        _useClassInterfaceCallback && osCommandCallbackInterface.tellp() ?
        FormatW(_initializeCommandPropertyCallbackInternal_Template,
                    typeInfoName.data(),
                    nullptr).c_str() :
            osInitializeCommandProperties.str().data(),
        osInitializeCollectionProperties.str().data(),
        osInternalProperties.str().data(),
        !_useClassInterfaceCallback && pPropertyModelInfo->getMethods().size() ? 
            FormatW(_onInvokeImplement_Template,osInvokeInternalMethods.str().data(),nullptr).data(): 
            L"",
        _useClassInterfaceCallback && pPropertyModelInfo->getMethods().size() ?
            FormatW(_initializeMethodCallbackInternal_Template, typeInfoName.data(), nullptr).data() :
            L"",
        pPropertyModelInfo->getBaseType() ? L"new" : L"",
        nullptr
        );
}