/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2020, Erik Moqvist
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/* This file was generated by Messi. */

#include "messi.h"
#include "my_protocol_server.h"

static void on_connected_default(struct my_protocol_server_t *self_p,
                                 struct my_protocol_server_client_t *client_p)
{
    (void)self_p;
    (void)client_p;
}

static void on_disconnected_default(struct my_protocol_server_t *self_p,
                                    struct my_protocol_server_client_t *client_p)
{
    (void)self_p;
    (void)client_p;
}

static void on_client_connected()
{
}

static void on_client_disconnected()
{
}

static void on_client_input(struct async_stcp_server_client_t *client_p)
{
    (void)client_p;
}

void my_protocol_server_new_output_message(struct my_protocol_server_t *self_p)
{
    self_p->output.message_p = my_protocol_server_to_client_new(
        &self_p->output.workspace.buf_p[0],
        self_p->output.workspace.size);
}

static void on_foo_req_default(
    struct my_protocol_server_t *self_p,
    struct my_protocol_server_client_t *client_p,
    struct my_protocol_foo_req_t *message_p)
{
    (void)self_p;
    (void)client_p;
    (void)message_p;
}
static void on_bar_ind_default(
    struct my_protocol_server_t *self_p,
    struct my_protocol_server_client_t *client_p,
    struct my_protocol_bar_ind_t *message_p)
{
    (void)self_p;
    (void)client_p;
    (void)message_p;
}
static void on_fie_rsp_default(
    struct my_protocol_server_t *self_p,
    struct my_protocol_server_client_t *client_p,
    struct my_protocol_fie_rsp_t *message_p)
{
    (void)self_p;
    (void)client_p;
    (void)message_p;
}

int my_protocol_server_init(
    struct my_protocol_server_t *self_p,
    const char *server_uri_p,
    struct my_protocol_server_client_t *clients_p,
    int clients_max,
    uint8_t *clients_input_bufs_p,
    size_t client_input_size,
    uint8_t *workspace_in_buf_p,
    size_t workspace_in_size,
    uint8_t *workspace_out_buf_p,
    size_t workspace_out_size,
    my_protocol_server_on_client_connected_t on_connected,
    my_protocol_server_on_client_disconnected_t on_disconnected,
    my_protocol_server_on_foo_req_t on_foo_req,
    my_protocol_server_on_bar_ind_t on_bar_ind,
    my_protocol_server_on_fie_rsp_t on_fie_rsp,
    struct async_t *async_p)
{
    int res;
    int i;
    
    if (on_foo_req == NULL) {
        on_foo_req = on_foo_req_default;
    }

    if (on_bar_ind == NULL) {
        on_bar_ind = on_bar_ind_default;
    }

    if (on_fie_rsp == NULL) {
        on_fie_rsp = on_fie_rsp_default;
    }

    if (on_connected == NULL) {
        on_connected = on_connected_default;
    }

    if (on_disconnected == NULL) {
        on_disconnected = on_disconnected_default;
    }

    res = messi_parse_tcp_uri(server_uri_p,
                              &self_p->server.address[0],
                              sizeof(self_p->server.address),
                              &self_p->server.port);

    if (res != 0) {
        return (res);
    }

    self_p->on_foo_req = on_foo_req;
    self_p->on_bar_ind = on_bar_ind;
    self_p->on_fie_rsp = on_fie_rsp;
    (void)workspace_in_buf_p;
    (void)workspace_in_size;
    self_p->output.workspace.buf_p = workspace_out_buf_p;
    self_p->output.workspace.size = workspace_out_size;
    self_p->async_p = async_p;
    async_stcp_server_init(&self_p->stcp,
                           &self_p->server.address[0],
                           self_p->server.port,
                           NULL,
                           on_client_connected,
                           on_client_disconnected,
                           on_client_input,
                           async_p);

    for (i = 0; i < clients_max; i++) {
        clients_p[i].input.data.buf_p = &clients_input_bufs_p[i * client_input_size];
        clients_p[i].input.data.size = client_input_size;
        async_stcp_server_add_client(&self_p->stcp, &clients_p[i].stcp);
    }
    
    return (0);
}

void my_protocol_server_start(struct my_protocol_server_t *self_p)
{
    async_stcp_server_start(&self_p->stcp);
}

void my_protocol_server_stop(struct my_protocol_server_t *self_p)
{
    async_stcp_server_stop(&self_p->stcp);
}

void my_protocol_server_send(struct my_protocol_server_t *self_p,
                      struct my_protocol_server_client_t *client_p)
{
    int res;
    struct messi_header_t *header_p;

    res = my_protocol_server_to_client_encode(
        self_p->output.message_p,
        &self_p->output.message.buf_p[sizeof(*header_p)],
        self_p->output.message.size - sizeof(*header_p));

    if (res < 0) {
        return;
    }

    header_p = (struct messi_header_t *)&self_p->output.message.buf_p[0];
    messi_header_create(header_p, MESSI_MESSAGE_TYPE_SERVER_TO_CLIENT_USER, res);
    async_stcp_server_client_write(&client_p->stcp,
                                   &self_p->output.message.buf_p[0],
                                   res + sizeof(*header_p));
}

struct my_protocol_foo_rsp_t *my_protocol_server_init_foo_rsp(
    struct my_protocol_server_t *self_p)
{
    my_protocol_server_new_output_message(self_p);
    my_protocol_server_to_client_messages_foo_rsp_init(self_p->output.message_p);

    return (&self_p->output.message_p->messages.value.foo_rsp);
}

struct my_protocol_fie_req_t *my_protocol_server_init_fie_req(
    struct my_protocol_server_t *self_p)
{
    my_protocol_server_new_output_message(self_p);
    my_protocol_server_to_client_messages_fie_req_init(self_p->output.message_p);

    return (&self_p->output.message_p->messages.value.fie_req);
}

