/*
 * Copyright (C) 2019 Intel Corporation.  All rights reserved.
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 */


#include "native_interface.h"
#include "app_manager.h"
#include "app_manager_export.h"
#include "bi-inc/shared_utils.h"
#include "bi-inc/attr_container.h"
#include "coap_ext.h"

typedef struct _app_res_register {
    struct _app_res_register *next;
    char * url;
    void (*request_handler)(request_t *, void *);
    uint32 register_id;
} app_res_register_t;

static app_res_register_t * g_resources = NULL;

void module_request_handler(request_t *request, void *user_data)
{
    unsigned int mod_id = (unsigned int)(uintptr_t)user_data;
    bh_message_t msg;
    module_data *m_data;
    request_t *req;

    /* Check module name */
    m_data = module_data_list_lookup_id(mod_id);
    if (!m_data) {
        return;
    }

    if (m_data->wd_timer.is_interrupting) {
        return;
    }

    req = clone_request(request);
    if (!req) {
        return;
    }

    /* Set queue message and send to applet's queue */
    msg = bh_new_msg(RESTFUL_REQUEST, req, sizeof(*req), request_cleaner);
    if (!msg) {
        request_cleaner(req);
        return;
    }

    if (!bh_post_msg2(m_data->queue, msg)) {
        return;
    }

    app_manager_printf("Send request to app %s success.\n",
            m_data->module_name);
}

void targeted_app_request_handler(request_t *request, void *unused)
{
    char applet_name[128] = { 0 };
    int offset;
    char *url = request->url;
    module_data *m_data;

    offset = check_url_start(request->url, strlen(request->url), "/app/");

    if (offset <= 0) {
        return;
    }

    strncpy(applet_name, request->url + offset, sizeof(applet_name) - 1);
    char *p = strchr(applet_name, '/');
    if (p) {
        *p = 0;
    } else
        return;
    app_manager_printf("Send request to applet: %s\n", applet_name);

    request->url = p + 1;

    /* Check module name */
    m_data = module_data_list_lookup(applet_name);
    if (!m_data) {
        SEND_ERR_RESPONSE(request->mid,
                "Send request to applet failed: invalid applet name");
        goto end;
    }

    module_request_handler(request, (void *)(uintptr_t)m_data->id);
    end: request->url = url;

}

void am_send_response(response_t *response)
{
    module_data *m_data;

    // if the receiver is not any of modules, just forward it to the host
    m_data = module_data_list_lookup_id(response->reciever);
    if (!m_data) {
        send_response_to_host(response);

    } else {
        response_t * resp_for_send = clone_response(response);
        if (!resp_for_send) {
            return;
        }

        bh_message_t msg = bh_new_msg(RESTFUL_RESPONSE, resp_for_send,
                sizeof(*resp_for_send), response_cleaner);
        if (!msg) {
            response_cleaner(resp_for_send);
            return;
        }

        if (!bh_post_msg2(m_data->queue, msg)) {
            return;
        }
    }
}

void * am_dispatch_request(request_t *request)
{
    app_res_register_t *r = g_resources;

    while (r) {
        if (check_url_start(request->url, strlen(request->url), r->url) > 0) {
            r->request_handler(request, (void *)(uintptr_t)r->register_id);
            return r;
        }
        r = r->next;
    }
    return NULL;
}

bool am_register_resource(const char *url,
                          void (*request_handler)(request_t *, void *),
                          uint32 register_id)
{
    app_res_register_t * r = g_resources;
    int register_num = 0;

    while (r) {
        if (strcmp(r->url, url) == 0) {
            return false;
        }

        if (r->register_id == register_id)
            register_num++;

        r = r->next;
    }

    if (strlen(url) > RESOUCE_EVENT_URL_LEN_MAX)
        return false;

    if (register_num >= RESOURCE_REGISTRATION_NUM_MAX)
        return false;

    r = (app_res_register_t *)APP_MGR_MALLOC(sizeof(app_res_register_t));
    if (r == NULL)
        return false;

    memset(r, 0, sizeof(*r));
    r->url = bh_strdup(url);
    if (r->url == NULL) {
        APP_MGR_FREE(r);
        return false;
    }

    r->request_handler = request_handler;
    r->next = g_resources;
    r->register_id = register_id;
    g_resources = r;

    return true;
}

void am_cleanup_registeration(uint32 register_id)
{
    app_res_register_t * r = g_resources;
    app_res_register_t * prev = NULL;

    while (r) {
        app_res_register_t *next = r->next;

        if (register_id == r->register_id) {
            if (prev)
                prev->next = next;
            else
                g_resources = next;

            APP_MGR_FREE(r->url);
            APP_MGR_FREE(r);
        } else
            /* if r is freed, should not change prev. Only set prev to r
             when r isn't freed. */
            prev = r;

        r = next;
    }
}
