/**
 * @module node-opcua-transport
 */
import { decodeUInt32, encodeUInt32, UInt32 } from "node-opcua-basic-types";
import { BinaryStream, OutputBinaryStream } from "node-opcua-binary-stream";
import {
    BaseUAObject,
    buildStructuredType,
    check_options_correctness_against_schema,
    initialize_field,
    parameters,
    IStructuredTypeSchema
} from "node-opcua-factory";
import { IHelloAckLimits } from "./i_hello_ack_limits";

const schemaAcknowledgeMessage = buildStructuredType({
    name: "AcknowledgeMessage",

    baseType: "BaseObjectType",

    fields: [
        {
            name: "ProtocolVersion",

            fieldType: "UInt32",

            documentation: "The latest version of the OPC UA TCP protocol supported by the Server."
        },
        { name: "ReceiveBufferSize", fieldType: "UInt32" },
        { name: "SendBufferSize", fieldType: "UInt32" },
        { name: "MaxMessageSize", fieldType: "UInt32", documentation: "The maximum size for any request message." },
        {
            name: "MaxChunkCount",
            fieldType: "UInt32",
            documentation: "The maximum number of chunks in any request message."
        }
    ]
});

interface AcknowledgeMessageOptions extends Partial<IHelloAckLimits>{
    protocolVersion?: UInt32;
}

export class AcknowledgeMessage extends BaseUAObject implements IHelloAckLimits {
    public static possibleFields: string[] = [
        "protocolVersion",
        "receiveBufferSize",
        "sendBufferSize",
        "maxMessageSize",
        "maxChunkCount"
    ];
    public static schema = schemaAcknowledgeMessage;

    public protocolVersion: UInt32;
    public receiveBufferSize: UInt32;
    public sendBufferSize: UInt32;
    public maxMessageSize: UInt32;
    public maxChunkCount: UInt32;

    constructor(options?: AcknowledgeMessageOptions) {
        options = options || {};

        super();
        const schema = schemaAcknowledgeMessage;
        /* istanbul ignore next */
        if (parameters.debugSchemaHelper) {
            check_options_correctness_against_schema(this, schema, options);
        }

        this.protocolVersion = initialize_field(schema.fields[0], options.protocolVersion);
        this.receiveBufferSize = initialize_field(schema.fields[1], options.receiveBufferSize);
        this.sendBufferSize = initialize_field(schema.fields[2], options.sendBufferSize);
        this.maxMessageSize = initialize_field(schema.fields[3], options.maxMessageSize);
        this.maxChunkCount = initialize_field(schema.fields[4], options.maxChunkCount);
    }

    public encode(stream: OutputBinaryStream): void {
        super.encode(stream);
        encodeUInt32(this.protocolVersion, stream);
        encodeUInt32(this.receiveBufferSize, stream);
        encodeUInt32(this.sendBufferSize, stream);
        encodeUInt32(this.maxMessageSize, stream);
        encodeUInt32(this.maxChunkCount, stream);
    }

    public decode(stream: BinaryStream): void {
        // call base class implementation first
        super.decode(stream);
        this.protocolVersion = decodeUInt32(stream);
        this.receiveBufferSize = decodeUInt32(stream);
        this.sendBufferSize = decodeUInt32(stream);
        this.maxMessageSize = decodeUInt32(stream);
        this.maxChunkCount = decodeUInt32(stream);
    }

    public toString(): string {
        let str = "";
        str += "protocolVersion   = " + this.protocolVersion + "\n";
        str += "receiveBufferSize = " + this.receiveBufferSize + "\n";
        str += "sendBufferSize    = " + this.sendBufferSize + "\n";
        str += "maxMessageSize    = " + this.maxMessageSize + "\n";
        str += "maxChunkCount     = " + this.maxChunkCount + "\n";
        return str;
    }
}
