/*
 * Copyright (c) 2006 Kazuaki ODA.
 * Copyright (c) 2006 Mode2 inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the company nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: ctr_hdml_support.c 436 2006-11-11 08:52:58Z oda $
 */

#include "http_protocol.h"
#include "apr_strings.h"
#include "ctr_hdml_support.h"
#include "ctr_util.h"

#define CTR_ENTRY_HANDLER       "cthree-entry-handler"
#define CTR_CHKON_HANDLER       "cthree-chkon-handler"
#define CTR_CHKOFF_HANDLER      "cthree-chkoff-handler"
#define CTR_RADIO_HANDLER       "cthree-radio-handler"
#define CTR_CHOICE_HANDLER      "cthree-choice-handler"

#define CTR_CTYPE_HDML          "text/x-hdml; charset=Shift_JIS"

static int ctr_chk_handler_common(request_rec *r, int chk);
static int ctr_choice_handler_cb(void *rec, const char *key, const char *val);

char *ctr_hdml_params_manage(const char *args, const request_rec *r)
{
    apr_pool_t *pool = r->pool;
    const char *p, *tkn, *key, *val;
    char *newargs, *newtkn;

    if (args == NULL)
        return NULL;

    p = apr_pstrdup(pool, args);
    newargs = NULL;

    while (*p && (tkn = ap_getword(pool, &p, '&'))) {
        key = ap_getword(pool, &tkn, '=');
        val = ap_getword(pool, &tkn, '=');

        /*
         * Check if this is a HDML specific parameter.  If so, manage it
         * properly.
         */
        if (strcmp(key, CTR_UNIQ_PARAM_PREFIX) == 0) {
            /* found a parameter for HDML page counter */
            /*
             * Remove the parameter.
             */
            continue;
        } else if (ctr_startwith(key, CTR_SUBMIT_PARAM_PREFIX)) {
            /* found a parameter for HDML submit button */
            key += 5;
            if (strlen(key) == 0)
                continue;
        } else if (ctr_startwith(key, CTR_CHECK_PARAM_PREFIX)) {
            /* found a parameter for HDML radio button and check box */
            if (val == NULL || strlen(val) == 0) {
                /*
                 * Radio button was not selected or check box was not checked.
                 * In this case, parameter is not send under HTML.  To emulate
                 * this behavior, remove the parameter.
                 */
                continue;
            }

            key += 5;
            if (strlen(key) == 0)
                continue;
        }

        newtkn = apr_pstrcat(pool, key, "=", val, NULL);
        if (newargs == NULL)
            newargs = newtkn;
        else
            newargs = apr_pstrcat(pool, newargs, "&", newtkn, NULL);
    }

    return newargs;
}

int ctr_export_type_checker(request_rec *r)
{
    char *p;

    if ((p = strrchr(r->uri, '/')) != NULL)
        p++;
    else
        p = r->uri;

    if (strcmp(p, CTR_ENTRY_EXPORT) == 0) {
        /*
         * This is a request for an entry card that mod_cthree exported.  Set
         * content handler here.
         */
        r->handler = CTR_ENTRY_HANDLER;
        r->proxyreq = 0;
        return OK;
    } else if (strcmp(p, CTR_CHKON_EXPORT) == 0) {
        /*
         * This is a request for a checkbox nodisplay card that mod_cthree
         * exported.  Set content handler here.
         */
        r->handler = CTR_CHKON_HANDLER;
        r->proxyreq = 0;
        return OK;
    } else if (strcmp(p, CTR_CHKOFF_EXPORT) == 0) {
        /*
         * This is a request for a checkbox nodisplay card that mod_cthree
         * exported.  Set content handler here.
         */
        r->handler = CTR_CHKOFF_HANDLER;
        r->proxyreq = 0;
        return OK;
    } else if (strcmp(p, CTR_RADIO_EXPORT) == 0) {
        /*
         * This is a request for a radio nodisplay card that mod_cthree
         * exported.  Set content handler here.
         */
        r->handler = CTR_RADIO_HANDLER;
        r->proxyreq = 0;
        return OK;
    } else if (strcmp(p, CTR_CHOICE_EXPORT) == 0) {
        /*
         * This is a request for a choice card that mod_cthree exported.  Set
         * content handler here.
         */
        r->handler = CTR_CHOICE_HANDLER;
        r->proxyreq = 0;
        return OK;
    }

    return DECLINED;
}

int ctr_entry_handler(request_rec *r)
{
    const char *s, *p;
    apr_table_t *argstbl;

    /*
     * If the request is not for this handler, just return.
     */
    if (strcmp(r->handler, CTR_ENTRY_HANDLER) != 0)
        return DECLINED;

    r->content_type = CTR_CTYPE_HDML;

    /*
     * Output an entry card that mod_chtree exported.
     */
    ap_rputs("<hdml version=3.0 ttl=0 markable=false>\n", r);
    s = "<entry name=c0 key=v default=$v";
    argstbl = ctr_args_get(r);
    if (argstbl != NULL) {
        if ((p = apr_table_get(argstbl, "fmt")) != NULL)
            s = apr_pstrcat(r->pool, s, " format=", p, NULL);
        if ((p = apr_table_get(argstbl, "noecho")) != NULL)
            s = apr_pstrcat(r->pool, s, " noecho=true", NULL);
    }
    s = apr_pstrcat(r->pool, s, ">\n", NULL);
    ap_rputs(s, r);
    ap_rputs("<action type=accept task=return retvals=$v>\n", r);
    ap_rputs("</entry>\n", r);
    ap_rputs("</hdml>\n", r);

    return OK;
}

int ctr_chkon_handler(request_rec *r)
{
    /*
     * If the request is not for this handler, just return.
     */
    if (strcmp(r->handler, CTR_CHKON_HANDLER) != 0)
        return DECLINED;

    return ctr_chk_handler_common(r, TRUE);
}

int ctr_chkoff_handler(request_rec *r)
{
    /*
     * If the request is not for this handler, just return.
     */
    if (strcmp(r->handler, CTR_CHKOFF_HANDLER) != 0)
        return DECLINED;

    return ctr_chk_handler_common(r, FALSE);
}

int ctr_radio_handler(request_rec *r)
{
    const char *s, *p;
    int n;
    apr_table_t *argstbl;

    /*
     * If the request is not for this handler, just return.
     */
    if (strcmp(r->handler, CTR_RADIO_HANDLER) != 0)
        return DECLINED;

    r->content_type = CTR_CTYPE_HDML;

    /*
     * Output a radio nodisplay card that mod_chtree exported.
     */
    ap_rputs("<hdml version=3.0 ttl=0 markable=false>\n", r);
    ap_rputs("<nodisplay name=c0>\n", r);
    s = "<action type=accept task=return retvals=$v;*";
    argstbl = ctr_args_get(r);
    if (argstbl != NULL && (p = apr_table_get(argstbl, "n")) != NULL &&
        (n = (int)apr_atoi64(p)) > 0) {
        while (--n)
            s = apr_pstrcat(r->pool, s, ";_", NULL);
    }
    s = apr_pstrcat(r->pool, s, ">\n", NULL);
    ap_rputs(s, r);
    ap_rputs("</nodisplay>\n", r);
    ap_rputs("</hdml>\n", r);

    return OK;
}

int ctr_choice_handler(request_rec *r)
{
    apr_table_t *argstbl;

    /*
     * If the request is not for this handler, just return.
     */
    if (strcmp(r->handler, CTR_CHOICE_HANDLER) != 0)
        return DECLINED;

    r->content_type = CTR_CTYPE_HDML;

    /*
     * Output a choice card that mod_chtree exported.
     */
    ap_rputs("<hdml version=3.0 ttl=0 markable=false>\n", r);
    ap_rputs("<choice name=c0 key=v default=$v method=alpha>\n", r);
    argstbl = ctr_args_get(r);
    if (argstbl != NULL)
        apr_table_do(ctr_choice_handler_cb, r, argstbl, NULL);
    ap_rputs("</choice>\n", r);
    ap_rputs("</hdml>\n", r);

    return OK;
}

static int ctr_chk_handler_common(request_rec *r, int chk)
{
    const char *s;

    r->content_type = CTR_CTYPE_HDML;

    /*
     * Output a checkbox nodisplay card that mod_chtree exported.
     */
    ap_rputs("<hdml version=3.0 ttl=0 markable=false>\n", r);
    ap_rputs("<nodisplay name=c0>\n", r);
    s = "<action type=accept task=return retvals=";
    if (chk)
        s = apr_pstrcat(r->pool, s, CTR_CHKOFF_EXPORT, ";X;$v>\n", NULL);
    else
        s = apr_pstrcat(r->pool, s, CTR_CHKON_EXPORT, ";_;>\n", NULL);
    ap_rputs(s, r);
    ap_rputs("</nodisplay>\n", r);
    ap_rputs("</hdml>\n", r);

    return OK;
}

static int ctr_choice_handler_cb(void *rec, const char *key, const char *val)
{
    request_rec *r = rec;
    apr_pool_t *pool = r->pool;
    char *s;

    s = "<ce task=return value=\"";
    s = apr_pstrcat(pool, s, ctr_hdml_escape(key, pool), "\" retvals=\"$v;",
                    ctr_hdml_vars_escape(val, pool), "\">",
                    ctr_hdml_escape(val, pool), "\n", NULL);
    ap_rputs(s, r);

    return TRUE;
}
