//
// Created by magino on 16. 9. 2019.
//

#ifndef S7METHODNODE_H
#define S7METHODNODE_H

#include <Management.h>
#include <communication/ICommunication.h>
#include "composite/INode.h"
#include <compositeBuilder/S7CsvDataBlock/S7CsvRowModel.h>

class S7MethodNode: public INode {
private:
    Management& _mngmnt;
    ArgumentList _in;
    ArgumentList _out;
    S7CsvRowModel _trigger;
    std::list<S7CsvRowModel> _rows;
    S7CsvRowModel _row;
public:
    S7MethodNode(ICommunication& comm, MyUaServer& server, S7CsvRowModel& row, Management& mngmnt): INode(comm, server), _mngmnt(mngmnt), _row(row)  {}
    ~S7MethodNode() override = default;

    void* GetCommParam() override { return &_row; }
    UA_DataType GetUaDataType() const override  { return _row.uaDataType; };

    void AddOpcUaNode(UaNodeId& parent) override {
        uaServer.AddMethodNode(_row.name,
                               _row.name,
                               _row.description,
                               false,
                               _in,
                               _out,
                               parent,
                               instanceNodeId,
                               UaNodeId::HasComponent,
                               &MethodCallback,
                               this);
    }

    /*
    IS7Node* FindNode(const UaNodeId& uaNodeId) override {
        //if(UA_NodeId_equal(&nodeId, uaNodeId))
        //    return this;
        if(nodeIdd == uaNodeId)
            return this;
        else return nullptr;
    }
    */

    void AddTrigger(S7CsvRowModel row) { _trigger = row; }
    void AddOutputArgument(S7CsvRowModel row) {
        _rows.push_back(std::move(row));
        _out.AddScalarArgument(_rows.back().name, row.comment , _rows.back().uaDataType.typeIndex, &_rows.back());
    }
    void AddInputArgument(S7CsvRowModel row) {
        _rows.push_back(std::move(row));
        _in.AddScalarArgument(_rows.back().name, row.comment, _rows.back().uaDataType.typeIndex, &_rows.back());
    }

    UA_StatusCode CallBack(UaNodeId& methodNodeId,
                           size_t inputSize,
                           const UA_Variant* input,
                           size_t outputSize,
                           UA_Variant* output) override {

        for(int i = 0; i < inputSize; ++i)
            comm.WriteValue(input[i], _in.at(i).context);

        UA_Variant runMethod;
        UA_Boolean run = true;
        UA_Variant_setScalarCopy(&runMethod, &run, &UA_TYPES[UA_TYPES_BOOLEAN]);

        // Write boolean run method
        comm.WriteValue(runMethod, &_trigger);
        usleep(100); // wait for sync values
        UA_Variant returnVal = comm.ReadValue(_out.at(0).context);
        UA_Variant_setScalarCopy(output, returnVal.data, &UA_TYPES[UA_TYPES_BOOLEAN]);

        //_mngmnt.RemoveActualReservation();
    }
};

#endif //S7METHODNODE_H