#include "HttpService.h"

void HttpService::AddApi(const char* path, http_method method, http_api_handler handler) {
    std::shared_ptr<http_method_handlers> method_handlers = NULL;
    auto iter = api_handlers.find(path);
    if (iter == api_handlers.end()) {
        // add path
        method_handlers = std::shared_ptr<http_method_handlers>(new http_method_handlers);
        api_handlers[path] = method_handlers;
    }
    else {
        method_handlers = iter->second;
    }
    for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
        if (iter->method == method) {
            // update
            iter->handler = handler;
            return;
        }
    }
    // add
    method_handlers->push_back(http_method_handler(method, handler));
}

int HttpService::GetApi(const char* url, http_method method, http_api_handler* handler) {
    // {base_url}/path?query
    const char* s = url;
    const char* b = base_url.c_str();
    while (*s && *b && *s == *b) {++s;++b;}
    if (*b != '\0') {
        return HTTP_STATUS_NOT_FOUND;
    }
    const char* e = s;
    while (*e && *e != '?') ++e;

    std::string path = std::string(s, e);
    auto iter = api_handlers.find(path);
    if (iter == api_handlers.end()) {
        *handler = NULL;
        return HTTP_STATUS_NOT_FOUND;
    }
    auto method_handlers = iter->second;
    for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
        if (iter->method == method) {
            *handler = iter->handler;
            return 0;
        }
    }
    *handler = NULL;
    return HTTP_STATUS_METHOD_NOT_ALLOWED;
}

int HttpService::GetApi(HttpRequest* req, http_api_handler* handler) {
    // {base_url}/path?query
    const char* s = req->path.c_str();
    const char* b = base_url.c_str();
    while (*s && *b && *s == *b) {++s;++b;}
    if (*b != '\0') {
        return HTTP_STATUS_NOT_FOUND;
    }
    const char* e = s;
    while (*e && *e != '?') ++e;

    std::string path = std::string(s, e);
    const char *kp, *ks, *vp, *vs;
    for (auto iter = api_handlers.begin(); iter != api_handlers.end(); ++iter) {
        kp = iter->first.c_str();
        vp = path.c_str();

        // RESTful API
        std::map<std::string, std::string> params;
        while (*kp && *vp && *kp == *vp) {
            if (kp[0] == '/' && kp[1] == ':') {
                kp += 2;
                ks = kp;
                while (*kp && *kp != '/') {++kp;}
                vp += 1;
                vs = vp;
                while (*vp && *vp != '/') {++vp;}
                params[std::string(ks, kp-ks)] = std::string(vs, vp-vs);
            }
            else {
                ++kp;
                ++vp;
            }
        }

        if (*kp == '\0' && *vp == '\0') {
            auto method_handlers = iter->second;
            for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
                if (iter->method == req->method) {
                    for (auto& param : params) {
                        // RESTful /:field/ => req->query_params
                        req->query_params[param.first] = param.second;
                    }
                    *handler = iter->handler;
                    return 0;
                }
            }

            if (params.size() == 0) {
                *handler = NULL;
                return HTTP_STATUS_METHOD_NOT_ALLOWED;
            }
        }
    }
    *handler = NULL;
    return HTTP_STATUS_NOT_FOUND;
}
