#include "lip/app/opcua/server/lip_opcua_server_cfg_defs.h"
#if LIP_OPCUA_SERVER_ENABLE
#include "lip_opcua_server_svcset_attr.h"
#include "lip/app/opcua/server/lip_opcua_server_con.h"
#include "lip/app/opcua/server/tree/lip_opcua_server_tree.h"
#include "lip/app/opcua/types/lip_opcua_nodeid.h"
#include "lip/app/opcua/lip_opcua_std_nodeids.h"
#include "lip/app/opcua/types/lip_opcua_datavalue.h"
#include "lip/app/opcua/types/lip_opcua_write_value.h"



t_lip_opcua_err lip_opcua_server_procreq_attr_read(struct st_lip_opcua_con *con, const t_lip_opcua_req_info *req, t_lip_proc_buf *data_buf) {
    t_lip_opcua_err err =  LIP_OPCUA_ERR_GOOD;

    double maxAge;
    t_lip_opcua_ret_tstmp_types retTstmps;
    t_lip_opcua_arrsize nodes_cnt;
    struct st_lip_opcua_session_ctx *session = lip_opcua_con_session(con);

    err = lip_opcua_procbuf_get_double(data_buf, &maxAge);
    if (err == LIP_OPCUA_ERR_GOOD) {
        uint32_t val;
        err = lip_opcua_procbuf_get_enum(data_buf, &val);
        if (err == LIP_OPCUA_ERR_GOOD) {
            retTstmps = val;
        }
    }

    if (err == LIP_OPCUA_ERR_GOOD) {
        err = lip_opcua_procbuf_get_arrsize(data_buf, &nodes_cnt);
    }
    if (err == LIP_OPCUA_ERR_GOOD) {
        static const t_lip_opcua_nodeid f_resp_node_id = LIP_OPCUA_NODEID_STDNS_INT(LIP_OPCUA_NODEID_STD_READ_RESPONSE_BIN);
        t_lip_proc_buf *resp_buf = lip_opcua_con_resp_prepare(con, &req->resp, &f_resp_node_id, LIP_OPCUA_ERR_GOOD);
        if (!resp_buf) {
            err = LIP_OPCUA_ERR_BAD_TCP_SERVER_TOO_BUSY;
        } else {
            err = lip_opcua_procbuf_put_arrsize(resp_buf, nodes_cnt);
            for (int32_t node_idx = 0; (node_idx < nodes_cnt) && (err == LIP_OPCUA_ERR_GOOD); ++node_idx) {
                t_lip_opcua_read_value_id rdval;
                err = lip_opcua_procbuf_get_readvalueid(data_buf, &rdval);
                if (err == LIP_OPCUA_ERR_GOOD) {
                    t_lip_opcua_data_value val;
                    memset(&val, 0, sizeof(val));

                    lip_opcua_server_tree_read(session, &rdval, retTstmps, &val);
                    err = lip_opcua_procbuf_put_datavalue(resp_buf, &val, retTstmps, session);
                }
            }


            if (err == LIP_OPCUA_ERR_GOOD) {
                /* DiagnosticInfo */
                err = lip_opcua_procbuf_put_arrsize_null(resp_buf);
            }

            if (err == LIP_OPCUA_ERR_GOOD) {
                lip_opcua_con_resp_finish(con, resp_buf);
            }
        }
    }

    return err;
}

t_lip_opcua_err lip_opcua_server_procreq_attr_write(struct st_lip_opcua_con *con, const t_lip_opcua_req_info *req, t_lip_proc_buf *data_buf) {
    t_lip_opcua_err err =  LIP_OPCUA_ERR_GOOD;
    t_lip_opcua_arrsize nodes_cnt;
    struct st_lip_opcua_session_ctx *session = lip_opcua_con_session(con);

    err = lip_opcua_procbuf_get_arrsize(data_buf, &nodes_cnt);
    if (err == LIP_OPCUA_ERR_GOOD) {
        static const t_lip_opcua_nodeid f_resp_node_id = LIP_OPCUA_NODEID_STDNS_INT(LIP_OPCUA_NODEID_STD_WRITE_RESPONSE_BIN);
        t_lip_proc_buf *resp_buf = lip_opcua_con_resp_prepare(con, &req->resp, &f_resp_node_id, LIP_OPCUA_ERR_GOOD);
        if (!resp_buf) {
            err = LIP_OPCUA_ERR_BAD_TCP_SERVER_TOO_BUSY;
        } else {
            err = lip_opcua_procbuf_put_arrsize(resp_buf, nodes_cnt);
            for (int32_t node_idx = 0; (node_idx < nodes_cnt) && (err == LIP_OPCUA_ERR_GOOD); ++node_idx) {
                t_lip_opcua_write_value wrval;
                err = lip_opcua_procbuf_get_nodeid(data_buf, &wrval.nodeid);
                if (err == LIP_OPCUA_ERR_GOOD) {
                    uint32_t idval;
                    err = lip_opcua_procbuf_get_uint32(data_buf, &idval);
                    if (err == LIP_OPCUA_ERR_GOOD)  {
                        wrval.attr = idval;
                    }
                }
                if (err == LIP_OPCUA_ERR_GOOD) {
                    err = lip_opcua_procbuf_get_string(data_buf, &wrval.range);
                }

                if (err == LIP_OPCUA_ERR_GOOD) {
                    err = lip_opcua_procbuf_get_datavalue(data_buf, &wrval.value);
                }

                if (err == LIP_OPCUA_ERR_GOOD) {
                    t_lip_opcua_err wr_res = lip_opcua_server_tree_write(session, &wrval);
                    err = lip_opcua_procbuf_put_status(resp_buf, wr_res);
                }
            }

            if (err == LIP_OPCUA_ERR_GOOD) {
                /* DiagnosticInfo */
                err = lip_opcua_procbuf_put_arrsize_null(resp_buf);
            }

            if (err == LIP_OPCUA_ERR_GOOD) {
                lip_opcua_con_resp_finish(con, resp_buf);
            }
        }
    }

    return err;

}

t_lip_opcua_err lip_opcua_server_procreq_attr_history_read(struct st_lip_opcua_con *con, const t_lip_opcua_req_info *req, t_lip_proc_buf *data_buf) {
    t_lip_opcua_err err =  LIP_OPCUA_ERR_BAD_SERVICE_UNSUPPORTED;

    return err;
}

t_lip_opcua_err lip_opcua_server_procreq_attr_history_update(struct st_lip_opcua_con *con, const t_lip_opcua_req_info *req, t_lip_proc_buf *data_buf) {
    t_lip_opcua_err err =  LIP_OPCUA_ERR_BAD_SERVICE_UNSUPPORTED;

    return err;
}

#endif
