/*
 * Project: srm-display-info Example
 *
 * Author: Eduardo Hopperdietzel
 *
 * Description: This small utility displays the GPU configuration
 *              generated by SRM, along with its corresponding
 *              resources information.
 */

#include <SRMCore.h>
#include <SRMDevice.h>
#include <SRMListener.h>
#include <SRMCrtc.h>
#include <SRMEncoder.h>
#include <SRMPlane.h>
#include <SRMConnector.h>
#include <SRMConnectorMode.h>

#include <SRMList.h>
#include <SRMLog.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define YES "true"
#define NO  "false"

static int openRestricted(const char *path, int flags, void *userData)
{
    SRM_UNUSED(userData);
    return open(path, flags);
}

static void closeRestricted(int fd, void *userData)
{
    SRM_UNUSED(userData);
    close(fd);
}

SRMInterface srmInterface =
{
    .openRestricted = &openRestricted,
    .closeRestricted = &closeRestricted
};

void printJSON(SRMCore *core, const char *auth, const char *desc)
{
    SRMLog("{");
    SRMLog("    \"auth\":\"%s\",", auth);
    SRMLog("    \"desc\":\"%s\",", desc);
    SRMLog("    \"allocatorDevice\":\"%s\",", srmDeviceGetName(srmCoreGetAllocatorDevice(core)));
    SRMLog("    \"devices\":");
    SRMLog("    [");
    SRMList *devices = srmCoreGetDevices(core);
    SRMListForeach(item1, devices)
    {
    SRMDevice *device = srmListItemGetData(item1);
    SRMLog("        {");
    SRMLog("            \"name\":\"%s\",", srmDeviceGetName(device));
    SRMLog("            \"clientCaps\":");
    SRMLog("            {");
    SRMLog("                \"stereo3D\":%s,",            srmDeviceGetClientCapStereo3D(device)             ? YES : NO);
    SRMLog("                \"universalPlanes\":%s,",     srmDeviceGetClientCapUniversalPlanes(device)      ? YES : NO);
    SRMLog("                \"atomic\":%s,",              srmDeviceGetClientCapAtomic(device)               ? YES : NO);
    SRMLog("                \"aspectRatio\":%s,",         srmDeviceGetClientCapAspectRatio(device)          ? YES : NO);
    SRMLog("                \"writebackConnectors\":%s",  srmDeviceGetClientCapWritebackConnectors(device)  ? YES : NO);
    SRMLog("            },");
    SRMLog("            \"caps\":");
    SRMLog("            {");
    SRMLog("                \"dumbBuffer\":%s,",          srmDeviceGetCapDumbBuffer(device)                 ? YES : NO);
    SRMLog("                \"primeImport\":%s,",         srmDeviceGetCapPrimeImport(device)                ? YES : NO);
    SRMLog("                \"primeExport\":%s,",         srmDeviceGetCapPrimeExport(device)                ? YES : NO);
    SRMLog("                \"addFB2Modifiers\":%s",      srmDeviceGetCapAddFb2Modifiers(device)            ? YES : NO);
    SRMLog("            },");
    SRMLog("            \"configuration\":");
    SRMLog("            {");
    SRMLog("                \"enabled\":%s,",             srmDeviceIsEnabled(device)                        ? YES : NO);
    SRMLog("                \"isRenderer\":%s,",          srmDeviceIsRenderer(device)                       ? YES : NO);
    SRMLog("                \"renderMode\":\"%s\",",      srmGetRenderModeString(srmDeviceGetRenderMode(device)));
    SRMLog("                \"rendererDevice\":\"%s\"",   srmDeviceGetName(srmDeviceGetRendererDevice(device)));
    SRMLog("            },");

    // Device crtcs
    SRMLog("            \"crtcs\":");
    SRMLog("            [");
    SRMList *deviceCrtcs = srmDeviceGetCrtcs(device);
    SRMListForeach(item2, deviceCrtcs)
    {
    SRMLog("                {");
    SRMCrtc *crtc = srmListItemGetData(item2);
    SRMLog("                    \"id\":%d", srmCrtcGetID(crtc));
    printf("                }");
    if (item2 != srmListGetBack(deviceCrtcs))
        printf(",");
    printf("\n");
    }
    SRMLog("            ],");

    // Device encoders
    SRMLog("            \"encoders\":");
    SRMLog("            [");
    SRMList *deviceEncoders = srmDeviceGetEncoders(device);
    SRMListForeach(item2, deviceEncoders)
    {
    SRMLog("                {");
    SRMEncoder *encoder = srmListItemGetData(item2);
    SRMLog("                    \"id\":%d,", srmEncoderGetID(encoder));
    printf("                    \"crtcs\":[");
    SRMList *encoderCrtcs = srmEncoderGetCrtcs(encoder);
    SRMListForeach(item3, encoderCrtcs)
    {
        SRMCrtc *crtc = srmListItemGetData(item3);
        printf("%d", srmCrtcGetID(crtc));
        if (item3 != srmListGetBack(encoderCrtcs))
            printf(",");
    }
    SRMLog("]");
    printf("                }");
    if (item2 != srmListGetBack(deviceEncoders))
        printf(",");
    printf("\n");
    }
    SRMLog("            ],");

    // Device planes
    SRMLog("            \"planes\":");
    SRMLog("            [");
    SRMList *devicePlanes = srmDeviceGetPlanes(device);
    SRMListForeach(item2, devicePlanes)
    {
    SRMLog("                {");
    SRMPlane *plane = srmListItemGetData(item2);
    SRMLog("                    \"id\":%d,", srmPlaneGetID(plane));
    SRMLog("                    \"type\":\"%s\",", srmGetPlaneTypeString(srmPlaneGetType(plane)));
    printf("                    \"crtcs\":[");
    SRMList *planeCrtcs = srmPlaneGetCrtcs(plane);
    SRMListForeach(item3, planeCrtcs)
    {
        SRMCrtc *crtc = srmListItemGetData(item3);
        printf("%d", srmCrtcGetID(crtc));
        if (item3 != srmListGetBack(planeCrtcs))
            printf(",");
    }
    SRMLog("]");
    printf("                }");
    if (item2 != srmListGetBack(devicePlanes))
        printf(",");
    printf("\n");
    }
    SRMLog("            ],");

    // Device connectors
    SRMLog("            \"connectors\":");
    SRMLog("            [");
    SRMList *deviceConnectors = srmDeviceGetConnectors(device);
    SRMListForeach(item2, deviceConnectors)
    {
    SRMLog("                {");
    SRMConnector *connector = srmListItemGetData(item2);
    SRMLog("                    \"id\":%d,", srmConnectorGetID(connector));
    SRMLog("                    \"type\":\"%s\",", srmGetConnectorTypeString(srmConnectorGetType(connector)));
    SRMLog("                    \"name\":\"%s\",", srmConnectorGetName(connector));
    SRMLog("                    \"mode\":\"%s\",", srmConnectorGetModel(connector));
    SRMLog("                    \"manufacturer\":\"%s\",", srmConnectorGetManufacturer(connector));
    SRMLog("                    \"connected\":%s,", srmConnectorIsConnected(connector) ? YES : NO);
    SRMLog("                    \"state\":\"%s\",", srmGetConnectorStateString(srmConnectorGetState(connector)));
    printf("                    \"encoders\":[");
    SRMList *connectorEncoders = srmConnectorGetEncoders(connector);
    SRMListForeach(item3, connectorEncoders)
    {
        SRMEncoder *encoder = srmListItemGetData(item3);
        printf("%d", srmEncoderGetID(encoder));
        if (item3 != srmListGetBack(connectorEncoders))
            printf(",");
    }
    SRMLog("],");
    SRMLog("                    \"modes\":");
    SRMLog("                    [");
    SRMList *connectorModes = srmConnectorGetModes(connector);
    SRMListForeach(item3, connectorModes)
    {
    SRMConnectorMode *connectorMode = srmListItemGetData(item3);
    SRMLog("                       {");
    SRMLog("                            \"width\":%d,", srmConnectorModeGetWidth(connectorMode));
    SRMLog("                            \"height\":%d,", srmConnectorModeGetHeight(connectorMode));
    SRMLog("                            \"refreshRate\":%d", srmConnectorModeGetRefreshRate(connectorMode));
    SRMLog("                       }");
    if (item3 != srmListGetBack(connectorModes))
        printf(",");
    }
    SRMLog("                    ]");

    printf("                }");
    if (item2 != srmListGetBack(deviceConnectors))
        printf(",");
    printf("\n");
    }
    SRMLog("            ]");
    SRMLog("        }");

    if (item1 != srmListGetBack(devices))
        printf(",");

    }
    SRMLog("    ]");
    SRMLog("}");
}

int main(void)
{
    setenv("SRM_DEBUG", "1", 1);

    SRMCore *core = srmCoreCreate(&srmInterface, NULL);

    if (!core)
    {
        SRMFatal("Failed to initialize SRM core.");
        return 1;
    }

    printJSON(core,
              "Your fullname",
              "Here you can add any additional information");

    srmCoreDestroy(core);

    return 0;
}
