/*
 * Created by jiaqiang.ye@lnxall.com
 *
 * Simple OPC-UA remote TAG implementation, for LC
 *
 * 2024/05/21
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "open62541.h"
#include "remote_ua_client.h"

#include <sys/socket.h>

void lc_opcua_option_default(struct cli_opcua_option * loo)
{
    if (loo != NULL) {
		loo->uaurl = "opc.tcp://127.0.0.1:4841";
		loo->username = "admin";
		loo->passwd = "lnxall123";
	}
}

static UA_ByteString loadFile(const char *const path) {
    UA_ByteString fileContents = UA_BYTESTRING_NULL;

    /* Open the file */
    FILE *fp = fopen(path, "rb");
    if(!fp) {
        errno = 0; /* We read errno also from the tcp layer... */
        return fileContents;
    }

    /* Get the file length, allocate the data and read */
    fseek(fp, 0, SEEK_END);
    fileContents.length = (size_t)ftell(fp);
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
    if(fileContents.data) {
        fseek(fp, 0, SEEK_SET);
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
        if(read != fileContents.length)
            UA_ByteString_clear(&fileContents);
    } else {
        fileContents.length = 0;
    }
    fclose(fp);

    return fileContents;
}




void lc_client_free(UA_Client * uacli)
{
    if (uacli != NULL) {
        UA_Client_disconnect(uacli);
        UA_Client_delete(uacli);
    }
}

UA_Client * lc_connect_opcua(const struct cli_opcua_option * loo)
{
    UA_Client * uacli;
    UA_StatusCode retval;
    UA_ClientConfig * ccfg;
    UA_ByteString *revocationList = NULL;
    size_t revocationListSize = 0;
    size_t trustListSize = 1;
    UA_String securityPolicyUri = UA_STRING_NULL;
    UA_MessageSecurityMode securityMode = UA_MESSAGESECURITYMODE_INVALID;

    uacli = UA_Client_new();
    if (uacli == NULL) {
        fprintf(stderr, "Failed to create new UA client.");
        return NULL;
    }

    UA_ByteString certificate = loadFile(CLIENT_CERT_CERT);
    UA_ByteString privateKey = loadFile(CLIENT_CERT_KEY);
    ccfg = UA_Client_getConfig(uacli);

    /* Load the trustList */
    UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
    for (size_t trustListCount = 0; trustListCount < trustListSize; trustListCount++)
        trustList[trustListCount] = loadFile(SERVER_CERT_CERT);

    /* Secure client initialization */
    UA_ClientConfig_setDefaultEncryption(ccfg, certificate, privateKey,
        trustList, trustListSize, revocationList, revocationListSize);
    ccfg->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;

    ccfg->securityMode = securityMode;
    ccfg->securityPolicyUri = securityPolicyUri;
    UA_ByteString_clear(&certificate);
    UA_ByteString_clear(&privateKey);
    for (size_t trustListCount = 0; trustListCount < trustListSize; trustListCount++)
        UA_ByteString_clear(&trustList[trustListCount]);

    if (loo->username && loo->passwd)
        retval = UA_Client_connectUsername(uacli, loo->uaurl, loo->username, loo->passwd);
    else
        retval = UA_Client_connect(uacli, loo->uaurl);
    if (retval != UA_STATUSCODE_GOOD) {
        fprintf(stderr, "Failed to connect to %s: %s", loo->uaurl, UA_StatusCode_name(retval));
        UA_Client_disconnect(uacli);
        UA_Client_delete(uacli);
        return NULL;
    }

	// set Keepalive options for OPC-UA TCP client
	// lc_opcua_tcp_keepalive(UA_Client_Rawsock(uacli));
    return uacli;
}
