//--------------------------------------------------------------------------------------------------
void CheckForLimitsConflicts
(
    const legato::App& app
)
//--------------------------------------------------------------------------------------------------
{
    size_t maxMemoryBytes = app.MaxMemoryBytes().Get();
    size_t maxFileSystemBytes = app.MaxFileSystemBytes().Get();

    for (const auto& procEnv : app.ProcEnvironments())
    {
        size_t maxLockedMemoryBytes = procEnv.MaxLockedMemoryBytes().Get();

        if (maxLockedMemoryBytes > maxMemoryBytes)
        {
            std::stringstream warning;
            warning << "maxLockedMemoryBytes (" << maxLockedMemoryBytes
                    << ") will be limited by the maxMemoryBytes limit (" << maxMemoryBytes << ").";
            PrintWarning(app, warning.str());
        }

        size_t maxFileBytes = procEnv.MaxFileBytes().Get();
        size_t maxCoreDumpFileBytes = procEnv.MaxCoreDumpFileBytes().Get();

        if (maxCoreDumpFileBytes > maxFileBytes)
        {
            std::stringstream warning;
            warning << "maxCoreDumpFileBytes (" << maxCoreDumpFileBytes
                    << ") will be limited by the maxFileBytes limit (" << maxFileBytes << ").";
            PrintWarning(app, warning.str());
        }

        if (maxCoreDumpFileBytes > maxFileSystemBytes)
        {
            std::stringstream warning;
            warning << "maxCoreDumpFileBytes (" << maxCoreDumpFileBytes
                    << ") will be limited by the maxFileSystemBytes limit ("
                    << maxFileSystemBytes << ") if the core file is inside the sandbox temporary"
                    " file system.";
            PrintWarning(app, warning.str());
        }

        if (maxFileBytes > maxFileSystemBytes)
        {
            std::stringstream warning;
            warning << "maxFileBytes (" << maxFileBytes
                    << ") will be limited by the maxFileSystemBytes limit ("
                    << maxFileSystemBytes << ") if the file is inside the sandbox temporary"
                    " file system.";
            PrintWarning(app, warning.str());
        }
    }
}
//--------------------------------------------------------------------------------------------------
static void GenerateProcessConfig
(
    std::ofstream& cfgStream,
    const legato::App& app
)
//--------------------------------------------------------------------------------------------------
{
    // Create nodes under "procs", where each process has its own node, named after the process.
    cfgStream << "  \"procs\"" << std::endl;
    cfgStream << "  {" << std::endl;

    for (const auto& procEnv : app.ProcEnvironments())
    {
        for (const auto& process : procEnv.ProcessList())
        {
            cfgStream << "    \"" << process.Name() << "\"" << std::endl;
            cfgStream << "    {" << std::endl;

            // The command-line argument list is an indexed list of arguments under a node called
            // "args", where the first argument (0) must be the executable to run.
            cfgStream << "      \"args\"" << std::endl;
            cfgStream << "      {" << std::endl;
            cfgStream << "        \"0\" \"" << process.ExePath() << "\"" << std::endl;
            int argIndex = 1;
            for (const auto& arg : process.CommandLineArgs())
            {
                cfgStream << "        \"" << argIndex << "\" \"" << arg << "\"" << std::endl;
                argIndex++;
            }
            cfgStream << "      }" << std::endl;

            GenerateProcessEnvVarsConfig(cfgStream, app, procEnv);

            // Generate the priority, fault action, and limits configuration.
            if (procEnv.FaultAction().IsSet())
            {
                cfgStream << "      \"faultAction\" \"" << procEnv.FaultAction().Get() << "\""
                          << std::endl;
            }
            if (procEnv.StartPriority().IsSet())
            {
                cfgStream << "      \"priority\" \"" << procEnv.StartPriority().Get() << "\""
                          << std::endl;
            }

            cfgStream << "      \"maxCoreDumpFileBytes\" ["
                      << procEnv.MaxCoreDumpFileBytes().Get()
                      << "]" << std::endl;

            cfgStream << "      \"maxFileBytes\" [" << procEnv.MaxFileBytes().Get() << "]"
                      << std::endl;

            cfgStream << "      \"maxLockedMemoryBytes\" ["
                      << procEnv.MaxLockedMemoryBytes().Get() << "]"
                      << std::endl;

            cfgStream << "      \"maxFileDescriptors\" ["
                      << procEnv.MaxFileDescriptors().Get() << "]"
                      << std::endl;

            if (procEnv.WatchdogTimeout().IsSet())
            {
                cfgStream << "      \"watchdogTimeout\" [" << procEnv.WatchdogTimeout().Get() << "]"
                          << std::endl;
            }
            if (procEnv.WatchdogAction().IsSet())
            {
                cfgStream << "      \"watchdogAction\" \"" << procEnv.WatchdogAction().Get() << "\""
                          << std::endl;
            }

            cfgStream << "    }" << std::endl;
        }
    }

    cfgStream << "  }" << std::endl << std::endl;
}