//
// HTTPRequest.cpp
//

#define DBG_LEVEL 0
#include <Raym/Log.h>
#include "net/HTTPRequest.h"

using namespace Raym;

namespace NET
{

const char *HTTPRequest::KEY_CGI    = "CGI";
const char *HTTPRequest::KEY_PARAMS = "PARAMS";

HTTPRequest::HTTPRequest()
{
    _method  = NULL;
    _uri     = NULL;
    _version = NULL;
    _message = NULL;
}

HTTPRequest::~HTTPRequest()
{
    RELEASE(_method);
    RELEASE(_uri);
    RELEASE(_version);
    RELEASE(_message);
}

HTTPRequest *HTTPRequest::requestWithSocket(SOCKET sock)
{
    DebugLog2("%s", __FUNCTION__);

    char buf[16384];
    int offset = 0;
    while (offset < sizeof(buf) - 1)
    {
        int len = recv(sock, &buf[offset], 1, 0);
        if (len == 0)
        {
            break;
        }
        if (offset > 0)
        {
            if ((buf[offset - 1] == '\r') && (buf[offset] == '\n'))
            {
                ++offset;
                break;
            }
        }
        ++offset;
    }
    buf[offset] = '\0';

    DebugLog2("%s 02", __FUNCTION__);

    HTTPRequest *result = NULL;

    String *method  = NULL;
    String *uri     = NULL;
    String *version = NULL;
    if (strchr(buf, ' ') != NULL)
    {
        char *p = strchr(buf, ' ');
        *p++ = '\0';
        if ((buf[strlen(buf) - 2] == '\r') && (buf[strlen(buf) - 1] == '\n'))
        {
            buf[strlen(buf) - 2] = '\0';
        }
        method = String::alloc()->initWithUTF8String(&buf[0]);
        while (*p == ' ')
        {
            ++p;
        }
        if (strchr(p, ' ') != NULL)
        {
            char *p2 = strchr(p, ' ');
            *p2++ = '\0';
            if ((p[strlen(p) - 2] == '\r') && (p[strlen(p) - 1] == '\n'))
            {
                p[strlen(p) - 2] = '\0';
            }
            uri = String::alloc()->initWithUTF8String(p);
            while (*p2 == ' ')
            {
                ++p2;
            }
            if (strchr(p2, ' ') == NULL)
            {
                if ((p2[strlen(p2) - 2] == '\r') && (p2[strlen(p2) - 1] == '\n'))
                {
                    p2[strlen(p2) - 2] = '\0';
                }
                version = String::alloc()->initWithUTF8String(p2);
            }
        }
    }

    if (version != NULL)
    {
        if (version->isEqualToString(String::stringWithUTF8String("HTTP/1.0")) || version->isEqualToString(String::stringWithUTF8String("HTTP/1.1")))
        {
            InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->initWithSocket(sock);
            if (header != NULL)
            {
                InternetTextMessageBody *body = NULL;
                /*
                if (header->fieldBodyForName("Transfer-Encoding") != NULL)
                {
                    DebugLog3("has Transfer-Encoding\n");
                    abort();
                }
                else if (header->fieldBodyForName("Content-Length") != NULL)
                {
                    DebugLog3("has Content-Length\n");
                    abort();
                }
                else if (header->fieldBodyForName("Content-Type") != NULL)
                {
                    DebugLog3("has Content-Type\n");
                    abort();
                }
                */

                InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
                RELEASE(header);
                RELEASE(body);

                result = new HTTPRequest();
                result->setMethod(method);
                result->setURI(uri);
                result->setVersion(version);
                result->setMessage(message);
                result->autorelease();

                RELEASE(message);
            }
            else
            {
                DebugLog3("error: InternetTextMessageHeader::headerWithSocket()\n");
            }
        }
    }

    RELEASE(method);
    RELEASE(uri);
    RELEASE(version);

    return result;
}

void HTTPRequest::setMethod(String *method)
{
    SET_METHOD(_method, method);
}

String *HTTPRequest::method()
{
    return _method;
}

void HTTPRequest::setURI(String *uri)
{
    SET_METHOD(_uri, uri);
}

String *HTTPRequest::URI()
{
    return _uri;
}

void HTTPRequest::setVersion(String *version)
{
    SET_METHOD(_version, version);
}

String *HTTPRequest::version()
{
    return _version;
}

void HTTPRequest::setMessage(InternetTextMessage *message)
{
    SET_METHOD(_message, message);
}

InternetTextMessage *HTTPRequest::message()
{
    return _message;
}

Dictionary *HTTPRequest::parseAsCGI()
{
    DebugLog2("HTTPRequest::parseAsCGI()");

    Dictionary *result = NULL;
    if (_uri != NULL)
    {
        DebugLog3("_uri != NULL");
        char *tmpstr = _strdup(_uri->cString());
        if (tmpstr != NULL)
        {
            DebugLog3("tmpstr != NULL");
            char *p1 = strchr(tmpstr, '?');
            if (p1 != NULL)
            {
                DebugLog3("p1 != NULL");
                *p1 = '\0';
                DebugLog2("cgi: %s", tmpstr);
                result = Dictionary::dictionaryWithCapacity(0);
                result->setObject(String::stringWithUTF8String(tmpstr), KEY_CGI);

                Array *params = Array::arrayWithCapacity(0);
                result->setObject(params, KEY_PARAMS);

                ++p1;
                while (true)
                {
                    char *p2 = strchr(p1, '&');
                    if (p2 != NULL)
                    {
                        *p2 = '\0';
                    }
                    char *p3 = strchr(p1, '=');
                    if (p3 != NULL)
                    {
                        *p3 = '\0';
                        String *para_name = String::stringWithUTF8String(p1);
                        ++p3;
                        String *para_val = String::stringWithUTF8String(p3);
                        DebugLog3("para_name: %s, para_val: %s", p1, p3);
                        Dictionary *para = Dictionary::dictionaryWithCapacity(0);
                        para->setObject(para_val, para_name);
                        params->addObject(para);
                    }

                    // 終端判定
                    if (p2 == NULL)
                    {
                        break;
                    }

                    // 次パラメータに設定
                    p1 = p2 + 1;
                }
            }

            free(tmpstr);
        }
    }
    return result;
}

const char *HTTPRequest::className()
{
    return "HTTPRequest";
}

} // NET
