/*
 * © Copyright 1996-2012 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include "mars.h"

#define VALIDATE 0x01
#define STATISTICS 0x02
#define SCHEDULE 0x04
/* MARSLITE defines those verbs which can be executed when the client is running on behalf of a marslite client */
#define MARSLITE 0x08


static handler handlers[] = {
    {
        "RETRIEVE",
        handle_retrieve,
        VALIDATE | STATISTICS | SCHEDULE | MARSLITE,
    },
    {
        "WRITE",
        handle_write,
        0,
    },
    {
        "READ",
        handle_read,
        0,
    },
    {
        "COMPUTE",
        handle_compute,
        0,
    },
    {
        "ARCHIVE",
        handle_archive,
        VALIDATE | STATISTICS,
    },
#ifdef ECMWF
    {
        "REMOVE",
        handle_remove,
        VALIDATE | STATISTICS,
    },
#endif

    {
        "DEFAULT",
        handle_default,
        0,
    },

    /* On new DHS */

    {
        "ERASE",
        handle_retrieve,
        VALIDATE | STATISTICS,
    },
    {
        "FLUSH",
        handle_control,
        VALIDATE | STATISTICS,
    },
    {
        "ATTACH",
        handle_control,
        VALIDATE | STATISTICS,
    },
    {
        "LIST",
        handle_control,
        MARSLITE,
    },
    {
        "BROWSE",
        handle_control,
        VALIDATE,
    },
    {
        "STAGE",
        handle_control,
        VALIDATE | STATISTICS | MARSLITE,
    },

    {
        "GET",
        handle_control,
        0,
    },

    {
        "STORE",
        handle_control,
        VALIDATE | STATISTICS,
    },
    {
        "FETCH",
        handle_retrieve,
        VALIDATE | STATISTICS,
    },

    {
        "END",
        handle_end,
        0,
    },
};


err handle_request(request* r, void* data) {
    int i;
    char buf[80];
    static int n = 0;

    if (!r) {
        marslog(LOG_EROR, "Cannot handle null requests");
        return -2;
    }

    if (mars.verbose) {

        putchar('\n');
        marslog(LOG_INFO, "Processing request %d", ++n);
    }

    if (add_hidden_parameters(r) != NOERR) {
        marslog(LOG_EROR, "Error while processing hidden parameters");
        return -2;
    }

    if (mars.marslite_mode) {
        if (!mars.keep_database) {
            unset_value(r, "DATABASE");
        }
        unset_value(r, "FIELDSET");
    }

    if (mars.verbose) {
        putchar('\n');
        print_one_request(r);
    }


    for (i = 0; i < NUMBER(handlers); i++)
        if (EQ(handlers[i].name, r->name)) {
            err e;
            err ret;
            request* env    = get_environ();
            clock_t cpu     = 0;
            double elapsed  = 0;
            boolean logstat = handlers[i].flags & STATISTICS;

            if (logstat) {
                init_statistics(r, env);
                log_statistics("reqno", "%d", n);
            }

            if ((handlers[i].flags & VALIDATE) == 0)
                mars.request_id = -1;
            else if ((e = validate_request(r, env, mars.validate)) != 0) {
                if (logstat) {
                    log_statistics("status", "restricted");
                    log_errors();
                    flush_statistics(r, env);
                }
                return e;
            }

#if defined(ECMWF) && !defined(NOSCHEDULE)
            if ((handlers[i].flags & SCHEDULE)) {
                if ((e = check_dissemination_schedule(r, env, logstat)) != 0) {
                    /* Fail if dissemination schedule */
                    if (mars.dissemination_schedule & SCHEDULE_FAIL) {
                        if (logstat) {
                            log_statistics("status", "before_schedule");
                            flush_statistics(r, env);
                            log_errors();
                        }
                        return e;
                    }
                }
            }
#endif

            if (!(handlers[i].flags & MARSLITE) && mars.marslite_mode) {
                int j = 0;
                marslog(LOG_WARN, "MARS running on behalf of marslite client");
                marslog(LOG_EROR, "Verb: %s disabled", handlers[i].name);
                marslog(LOG_WARN, "Allowed verbs in this mode:");
                for (j = 0; j < NUMBER(handlers); j++) {
                    if (handlers[j].flags & MARSLITE)
                        marslog(LOG_WARN, "   %s", handlers[j].name);
                }
                log_statistics("status", "marslite");
                return -1;
            }


            qenter(r);
            start_timer();
            e       = handlers[i].proc(r, data);
            elapsed = stop_timer(buf);
            cpu     = timer_cpu();
            if (*buf)
                marslog(LOG_INFO, "Request time: %s", buf);
            qleave();

            print_all_timers();
            reset_all_timers();

            if ((ret = fflush(stdout)) != 0)
                marslog(LOG_WARN, "Error while flushing output (%d)", ret);

            if (logstat) {
                log_statistics("cpu", "%ld", (long)cpu);
                log_statistics("elapsed", "%ld", (long)elapsed);
                log_statistics("status", "%s", e == NOERR ? "ok" : "fail");
                if (e)
                    log_errors();
                flush_statistics(r, env);
            }


            return e;
        }

    marslog(LOG_EROR, "No handler for verb '%s' found", r->name);
    return -1;
}

err handle_end(request* r, void* data) {
    marslog(LOG_INFO, "Note: in this version of MARS, END is not compulsary");
    marslog(LOG_INFO, "Any remaining requests ignored");
    return END_REQUEST;
}
