//
// Created by eirik on 05/09/2019.
//
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/client_subscriptions.h>
#include <open62541/plugin/log_stdout.h>
#include <stdlib.h>

static UA_StatusCode opc_ua_browser_recursion(UA_Client *client, UA_NodeId parent)
{
    UA_StatusCode retval;
    UA_BrowseRequest bReq;
    UA_BrowseRequest_init(&bReq);
    bReq.requestedMaxReferencesPerNode = 0;
    bReq.nodesToBrowse = UA_BrowseDescription_new();
    bReq.nodesToBrowseSize = 1;
    bReq.nodesToBrowse[0].nodeId = parent;                      /* browse objects folder */
    bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
    UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
    printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
    for (size_t i = 0; i < bResp.resultsSize; ++i)
    {
        for (size_t j = 0; j < bResp.results[i].referencesSize; ++j)
        {
            UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);

            if (ref->nodeClass == UA_NODECLASS_OBJECT)
            {
                UA_NodeId new;
                UA_NodeId_copy(&ref->nodeId.nodeId, &new);
                opc_ua_browser_recursion(client, new);
                //UA_NodeId_clear(&new);
            }
            else if (ref->nodeClass == UA_NODECLASS_VARIABLE || ref->nodeClass == UA_NODECLASS_METHOD)
            {
                if (ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
                {
                    printf("%-9d %-16d %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
                           ref->nodeId.nodeId.identifier.numeric, (int)ref->browseName.name.length,
                           ref->browseName.name.data, (int)ref->displayName.text.length,
                           ref->displayName.text.data);
                }
                else if (ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING)
                {
                    printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
                           (int)ref->nodeId.nodeId.identifier.string.length,
                           ref->nodeId.nodeId.identifier.string.data,
                           (int)ref->browseName.name.length, ref->browseName.name.data,
                           (int)ref->displayName.text.length, ref->displayName.text.data);
                }
            }
        }
    }
    UA_BrowseRequest_clear(&bReq);
    UA_BrowseResponse_clear(&bResp);
}

int main(int argc, char **argv)
{
    UA_Client *client = UA_Client_new();
    char *url = argv[1];
    UA_ClientConfig_setDefault(UA_Client_getConfig(client));
    UA_StatusCode retval = UA_Client_connect(client, url);

    if (retval != UA_STATUSCODE_GOOD)
    {
        printf("Unable to connect!");
        UA_Client_delete(client);
        return (int)retval;
    }

    printf("Browsing nodes in objects folder:\n");
    printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
    opc_ua_browser_recursion(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER));

    printf("Program End\n");

    /* Clean up */
    UA_Client_delete(client); /* Disconnects the client internally */
    return UA_STATUSCODE_GOOD;
}
