/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/***************************************************************************
 * Description: Context handling (Autoconf)                                *
 * Author:      Henri Gomez <hgomez@apache.org>                            *
 ***************************************************************************/

#include "jk_global.h"
#include "jk_context.h"
#include "jk_ajp_common.h"


/*
 * Set the virtual name of the context
 */

int context_set_virtual(jk_context_t *c, char *virt)
{
    if (c) {

        if (virt) {
            c->virt = jk_pool_strdup(&c->p, virt);

            if (!c->virt)
                return JK_FALSE;
        }

        return JK_TRUE;
    }

    return JK_FALSE;
}

/*
 * Init the context info struct
 */

int context_open(jk_context_t *c, char *virt)
{
    if (c) {
        jk_open_pool(&c->p, c->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE);
        c->size = 0;
        c->capacity = 0;
        c->contexts = NULL;

        return context_set_virtual(c, virt);
    }

    return JK_FALSE;
}

/*
 * Close the context info struct
 */

int context_close(jk_context_t *c)
{
    if (c) {

        jk_close_pool(&c->p);
        return JK_TRUE;
    }

    return JK_FALSE;
}

/*
 * Allocate and open context
 */

int context_alloc(jk_context_t **c, char *virt)
{
    if (c)
        return context_open(*c =
                            (jk_context_t *)calloc(1, sizeof(jk_context_t)),
                            virt);

    return JK_FALSE;
}

/*
 * Close and destroy context
 */

int context_free(jk_context_t **c)
{
    if (c && *c) {
        context_close(*c);
        free(*c);
        *c = NULL;
        return JK_TRUE;
    }

    return JK_FALSE;
}


/*
 * Ensure there will be memory in context info to store Context Bases
 */

static int context_realloc(jk_context_t *c)
{
    if (c->size == c->capacity) {
        jk_context_item_t **contexts;
        int capacity = c->capacity + CBASE_INC_SIZE;

        contexts =
            (jk_context_item_t **)jk_pool_alloc(&c->p,
                                                sizeof(jk_context_item_t *) *
                                                capacity);

        if (!contexts)
            return JK_FALSE;

        if (c->capacity && c->contexts)
            memcpy(contexts, c->contexts,
                   sizeof(jk_context_item_t *) * c->capacity);

        c->contexts = contexts;
        c->capacity = capacity;
    }

    return JK_TRUE;
}

/*
 * Ensure there will be memory in context info to URIS
 */

static int context_item_realloc(jk_context_t *c, jk_context_item_t *ci)
{
    if (ci->size == ci->capacity) {
        char **uris;
        int capacity = ci->capacity + URI_INC_SIZE;

        uris = (char **)jk_pool_alloc(&c->p, sizeof(char *) * capacity);

        if (!uris)
            return JK_FALSE;

        memcpy(uris, ci->uris, sizeof(char *) * ci->capacity);

        ci->uris = uris;
        ci->capacity = capacity;
    }

    return JK_TRUE;
}


/*
 * Locate a context base in context list
 */

jk_context_item_t *context_find_base(jk_context_t *c, char *cbase)
{
    int i;
    jk_context_item_t *ci;

    if (!c || !cbase)
        return NULL;

    for (i = 0; i < c->size; i++) {

        ci = c->contexts[i];

        if (!ci)
            continue;

        if (!strcmp(ci->cbase, cbase))
            return ci;
    }

    return NULL;
}

/*
 * Locate an URI in a context item
 */

char *context_item_find_uri(jk_context_item_t *ci, char *uri)
{
    int i;

    if (!ci || !uri)
        return NULL;

    for (i = 0; i < ci->size; i++) {
        if (!strcmp(ci->uris[i], uri))
            return ci->uris[i];
    }

    return NULL;
}

void context_dump_uris(jk_context_t *c, char *cbase, FILE * f)
{
    jk_context_item_t *ci;
    int i;

    ci = context_find_base(c, cbase);

    if (!ci)
        return;

    for (i = 0; i < ci->size; i++)
        fprintf(f, "/%s/%s\n", ci->cbase, ci->uris[i]);

    fflush(f);
}


/*
 * Add a new context item to context
 */

jk_context_item_t *context_add_base(jk_context_t *c, char *cbase)
{
    jk_context_item_t *ci;

    if (!c || !cbase)
        return NULL;

    /* Check if the context base was not allready created */
    ci = context_find_base(c, cbase);

    if (ci)
        return ci;

    if (context_realloc(c) != JK_TRUE)
        return NULL;

    ci = (jk_context_item_t *)jk_pool_alloc(&c->p, sizeof(jk_context_item_t));

    if (!ci)
        return NULL;

    c->contexts[c->size] = ci;
    c->size++;
    ci->cbase = jk_pool_strdup(&c->p, cbase);
    ci->status = 0;
    ci->size = 0;
    ci->capacity = 0;
    ci->uris = NULL;

    return ci;
}

/*
 * Add a new URI to a context item
 */

int context_add_uri(jk_context_t *c, char *cbase, char *uri)
{
    jk_context_item_t *ci;

    if (!uri)
        return JK_FALSE;

    /* Get/Create the context base */
    ci = context_add_base(c, cbase);

    if (!ci)
        return JK_FALSE;

    if (context_item_find_uri(ci, uri) != NULL)
        return JK_TRUE;

    if (context_item_realloc(c, ci) == JK_FALSE)
        return JK_FALSE;

    ci->uris[ci->size] = jk_pool_strdup(&c->p, uri);

    if (ci->uris[ci->size] == NULL)
        return JK_FALSE;

    ci->size++;
    return JK_TRUE;
}
