//--------------------------------------------------------------------------
/// Handle what happens when a Linked Trace is requested. We can either:
/// 1. Return the trace response as normal.
/// 2. Cache the response to disk, and generate a "trace metadata" file used to retrieve the trace later.
/// \param inFullResponseString The response string built by tracing the application.
/// \param inbSaveResponseToFile A switch used to determine which response method to use.
//--------------------------------------------------------------------------
void MultithreadedTraceAnalyzerLayer::HandleLinkedTraceResponse(std::stringstream& inFullResponseString, bool inbSaveResponseToFile)
{
    // If we're building for use with CodeXL, insert extra metadata into the response before returning.
#if defined(CODEXL_GRAPHICS)
    // The response should include a header when connected to CodeXL Graphics.
    gtASCIIString headerBuilder;
    headerBuilder.appendFormattedString("//AMD CodeXL Frame Trace\n");

    osModuleArchitecture moduleArchitecture;
    osRuntimePlatform currentPlatform;
    gtString executablePath;
    gtString commandLine;
    gtString workingDirectory;

    if (osGetProcessLaunchInfo(osGetCurrentProcessId(), moduleArchitecture, currentPlatform, executablePath, commandLine, workingDirectory) == true)
    {
        headerBuilder.appendFormattedString("//ProcessExe=%s\n", executablePath.asASCIICharArray());

        // Build a timestamp.
        osTime currentTime;
        currentTime.setFromCurrentTime();
        tm timeStruct;
        currentTime.timeAsTmStruct(timeStruct, osTime::LOCAL);

        // Need to add 1900, since tm contains "years since 1900".
        int year = timeStruct.tm_year + 1900;

        // Need to add 1, since tm contains "months since January".
        int month = timeStruct.tm_mon + 1;

        int day = timeStruct.tm_mday;
        int hour = timeStruct.tm_hour;
        int minute = timeStruct.tm_min;
        int second = timeStruct.tm_sec;

        gtASCIIString timestampBuilder;
        timestampBuilder.appendFormattedString("%d/%d/%d %d:%d:%d", month, day, year, hour, minute, second);
        headerBuilder.appendFormattedString("//TraceDateTime=%s\n", timestampBuilder.asCharArray());

        headerBuilder.appendFormattedString("//TraceFileVersion=%d\n", 1);
        headerBuilder.appendFormattedString("//ApplicationArgs=%s\n", commandLine.asASCIICharArray());
        headerBuilder.appendFormattedString("//WorkingDirectory=%s\n", workingDirectory.asASCIICharArray());
    }
    else
    {
        Log(logERROR, "Failed to retrieve process info when building response header.\n");
    }

    // Build a system information header string.
    std::string systemInfo;
    OSWrappers::WriteSystemInfoString(systemInfo);
    headerBuilder.appendFormattedString("\n%s\n", systemInfo.c_str());

    // Store the response temporarily.
    std::string headerString = headerBuilder.asCharArray();
    std::string responseString = inFullResponseString.str();

    // Clear the response string stream.
    inFullResponseString.str(std::string());
    inFullResponseString.clear();

    // Write the header and response chunks into the final response.
    inFullResponseString << headerString;
    inFullResponseString << responseString;
#endif

    // Check if we want to cache the response to disk, or return it as-is.
    if (inbSaveResponseToFile)
    {
        std::string metadataXMLString;
        bool bWriteMetadataSuccessful = WriteTraceAndMetadataFiles(inFullResponseString, metadataXMLString);
        if (bWriteMetadataSuccessful)
        {
            // Send a response back to the client indicating which trace metadata file was written to disk.
            mCmdLinkedTraceWithSave.Send(metadataXMLString.c_str());
        }
        else
        {
            Log(logERROR, "Failed to write trace metadata XML.\n");
            mCmdLinkedTraceWithSave.Send("Failed");
        }
    }
    else
    {
        // Return the normal trace response string.
        // Send a response containing the API and GPU trace text.
        mCmdLinkedTrace.Send(std::string(inFullResponseString.str()).c_str());
    }
}
//--------------------------------------------------------------------------
/// Handle what happens when a Linked Trace is requested. We can either:
/// 1. Return the trace response as normal.
/// 2. Cache the response to disk, and generate a "trace metadata" file used to retrieve the trace later.
/// \param inFullResponseString The response string built by tracing the application.
/// \param inbSaveResponseToFile A switch used to determine which response method to use.
//--------------------------------------------------------------------------
void MultithreadedTraceAnalyzerLayer::HandleLinkedTraceResponse(gtASCIIString& inFullResponseString, bool inbSaveResponseToFile)
{
    ModernAPILayerManager* parentLayerManager = GetParentLayerManager();

    if (parentLayerManager->InCapturePlayer())
    {
        const std::string& metadataFile = parentLayerManager->GetPathToTargetMetadataFile();

        if (metadataFile.length() > 0)
        {
            // Read the metadata file and store the contents in a structure.
            TraceMetadata traceMetadata;
            traceMetadata.mFrameInfo = new FrameInfo;

            bool bReadMetadataFileSuccessfully = ReadMetadataFile(metadataFile, &traceMetadata);

            if (bReadMetadataFileSuccessfully)
            {
                gtASCIIString traceContents;
                bool bReadTraceSuccessfully = LoadTraceFile(traceMetadata.mPathToTraceFile, traceContents);

                if (bReadTraceSuccessfully)
                {
                    // At this point the full trace response text should be loaded into our string and ready to be sent back to the client.
                    mCmdLinkedTrace.Send(traceContents.asCharArray());
                }
                else
                {
                    Log(logERROR, "Failed to read trace file at '%s'.", traceMetadata.mPathToTraceFile.c_str());
                }
            }
            else
            {
                Log(logERROR, "Failed to read metadata file at '%s'.", metadataFile.c_str());
            }

            // Destroy the FrameInfo instance that was created above.
            SAFE_DELETE(traceMetadata.mFrameInfo);
        }
        else
        {
            Log(logERROR, "Failed to locate valid path to trace metadata file.");
        }
    }
    else
    {
        gtASCIIString traceHeaderBlock;
        bool bBuiltHeaderSuccessfully = GenerateLinkedTraceHeader(traceHeaderBlock);

        if (bBuiltHeaderSuccessfully)
        {
            bool bKeypressTrigger = parentLayerManager->IsTraceTriggeredByKeypress();

            // Collect a trace and generate the trace metadata string. Write the trace and metadata files to disk.
            std::string metadataXMLString;
            bool bWriteMetadataSuccessful = WriteTraceAndMetadataFiles(traceHeaderBlock, inFullResponseString, metadataXMLString);

            // If the trace wasn't triggered by a keypress, we'll need to send a response back through either of the following commands.
            CommandResponse& frameCaptureWithSaveResponse = (inbSaveResponseToFile == true) ? parentLayerManager->mCmdFrameCaptureWithSave : mCmdLinkedTrace;

            if (bWriteMetadataSuccessful)
            {
                // We only need to send the response back through a request if the client triggered collection.
                if (!bKeypressTrigger)
                {
                    // Check if we want to cache the response to disk, or return it as-is.
                    if (inbSaveResponseToFile)
                    {
                        if (bWriteMetadataSuccessful)
                        {
                            // Send a response back to the client indicating which trace metadata file was written to disk.
                            frameCaptureWithSaveResponse.Send(metadataXMLString.c_str());
                        }
                        else
                        {
                            Log(logERROR, "Failed to write trace metadata XML.\n");
                            frameCaptureWithSaveResponse.Send("Failed");
                        }
                    }
                    else
                    {
                        // Send a response containing the API and GPU trace text.
                        frameCaptureWithSaveResponse.Send(inFullResponseString.asCharArray());
                    }
                }
                else
                {
                    Log(logMESSAGE, "Successfully traced frame %d.\n", parentLayerManager->GetFrameCount());
                }
            }
            else
            {
                Log(logERROR, "Failed to write trace metadata XML.\n");

                // If a failed trace collection was triggered by a command, we need to respond with an error message.
                if (!bKeypressTrigger)
                {
                    frameCaptureWithSaveResponse.Send("Failed");
                }
            }
        }
    }
}