#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"

#include "ngx_http_echo_foreach.h"
#include "ngx_http_echo_util.h"

#include <nginx.h>


ngx_int_t
ngx_http_echo_it_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    ngx_http_echo_ctx_t         *ctx;
    ngx_uint_t                   i;
    ngx_array_t                 *choices;
    ngx_str_t                   *choice_elts, *choice;

    ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);

    if (ctx && ctx->foreach != NULL) {

        choices = ctx->foreach->choices;
        i = ctx->foreach->next_choice;

        if (i < choices->nelts) {
            choice_elts = choices->elts;
            choice = &choice_elts[i];

            v->len = choice->len;
            v->data = choice->data;
            v->valid = 1;
            v->no_cacheable = 1;
            v->not_found = 0;

            return NGX_OK;
        }
    }

    v->not_found = 1;

    return NGX_OK;
}


ngx_int_t
ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r,
    ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
    ngx_http_echo_loc_conf_t    *elcf;
    ngx_str_t                   *delimiter, *compound;
    u_char                      *pos, *last, *end;
    ngx_str_t                   *choice;
    ngx_str_t                   *computed_arg_elts;
    ngx_array_t                 *cmds;
    ngx_http_echo_cmd_t         *cmd;
    ngx_http_echo_cmd_t         *cmd_elts;

    if (ctx->foreach != NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "Nested echo_foreach not supported yet.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (computed_args->nelts < 2) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "echo_foreach should take at least two arguments. "
                      "(if your delimiter starts with \"-\", preceding it "
                      "with a \"--\".)");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    computed_arg_elts = computed_args->elts;

    compound  = &computed_arg_elts[1];

    dd("HEY coumpound len: %u", (int) compound->len);

    ctx->foreach = ngx_palloc(r->pool, sizeof(ngx_http_echo_foreach_ctx_t));

    if (ctx->foreach == NULL) {
        return NGX_ERROR;
    }

    ctx->foreach->cmd_index = ctx->next_handler_cmd;

    ctx->foreach->next_choice = 0;

    ctx->foreach->choices = ngx_array_create(r->pool, 10, sizeof(ngx_str_t));
    if (ctx->foreach->choices == NULL) {
        return NGX_ERROR;
    }

    delimiter = &computed_arg_elts[0];

    pos = compound->data;
    end = compound->data + compound->len;

    while ((last = ngx_http_echo_strlstrn(pos, end, delimiter->data,
                                          delimiter->len - 1)) != NULL)
    {
        dd("entered the loop");

        if (last == pos) {
            dd("!!! len == 0");
            pos = last + delimiter->len;
            continue;
        }

        choice = ngx_array_push(ctx->foreach->choices);
        if (choice == NULL) {
            return NGX_ERROR;
        }

        choice->data = pos;
        choice->len  = last - pos;
        pos = last + delimiter->len;
    }

    if (pos < end) {
        choice = ngx_array_push(ctx->foreach->choices);
        if (choice == NULL) {
            return NGX_ERROR;
        }

        choice->data = pos;
        choice->len  = end - pos;
    }

    if (ctx->foreach->choices->nelts == 0) {
        /* skip the foreach body entirely */
        elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
        cmds = elcf->handler_cmds;
        cmd_elts = cmds->elts;
        for (/* void */; ctx->next_handler_cmd < cmds->nelts;
             ctx->next_handler_cmd++)
        {
            cmd = &cmd_elts[ctx->next_handler_cmd + 1];
            if (cmd->opcode == echo_opcode_echo_end) {
                return NGX_OK;
            }
        }

    }

    return NGX_OK;
}


ngx_int_t
ngx_http_echo_exec_echo_end(ngx_http_request_t *r,
    ngx_http_echo_ctx_t *ctx)
{
    if (ctx->foreach == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "Found a echo_end that has no corresponding echo_foreach "
                      "before it.");
        return NGX_ERROR;
    }

    ctx->foreach->next_choice++;

    if (ctx->foreach->next_choice >= ctx->foreach->choices->nelts) {
        /* TODO We need to explicitly free the foreach ctx from
         * the pool */
        ctx->foreach = NULL;

        return NGX_OK;
    }

    dd("echo_end: ++ next_choice (total: %u): %u",
       (unsigned) ctx->foreach->choices->nelts,
       (unsigned) ctx->foreach->next_choice);

    /* the main handler dispatcher loop will increment
     *   ctx->next_handler_cmd for us anyway. */
    ctx->next_handler_cmd = ctx->foreach->cmd_index;

    return NGX_OK;
}
