
/*---------------------------------------------------------------------------*/
/* httpfile.cpp                                                              */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>

#include <stdint.h>

#include "common/ilib/hash.h"
#include "sdk/common/os/iomux.h"
#include "sdk/common/interface/webserver_plugin.h"
#include "sdk/common/interface/httpfile.h"

btree * staticFilesRoot = NULL;


httpfile::httpfile(const char * fileName, word servlet, word theFlags, const byte * data, size_t dataSize)
    : servlet(servlet),
      iposFlags(theFlags),
      flags(0), 
      fileName(const_cast<char *>(fileName)),
      data(data),
      dataSize(dataSize),
      type(wsr_type_t(0))
{
    if ((theFlags & HTTP_GZIP) != 0)
        flags |= WSP_FLAG_ENCODING_GZIP;


    // NOTE: If something goes wrong, I call IDebug::Create() to access the debug object instead of debug->.
    //       The reason for this: it's not that easy to have a fixed order of the creation of static objects.
    //       So it could be, that debug is NULL (or an other, undefined value) when access to that object
    //       is needed here. So we changed the IDebug::Create() function to have a singleton behaviour.
    //       So IDebug::Create() only creates a single instance of IDebug and returnes that instance.

    type = GetResponseTypeForFileName(fileName);
    if (type == WSP_RESPONSE_NO_TYPE) {
        IDebug::Create()->printf("WARNING: Unkown file type for static file %s - using text", fileName);
        type = WSP_RESPONSE_TEXT;
    }

    btree * x = staticFilesRoot->btree_find(fileName);
    if (x != NULL) {
        IDebug::Create()->printf("WARNING: HTTPFile::HTTPFile(): re-registering \"%s\"", fileName);
        staticFilesRoot = staticFilesRoot->btree_get(x);
    }

    unsigned char md5buf[16];
    hash md5;
    md5.init(HASH_MD5);
    md5.update(data, dataSize);
    md5.final(md5buf);

    for (int i = 0; i < 16; i++)
        sprintf(&md5str[i * 2], "%02x", (unsigned int)md5buf[i]);

    staticFilesRoot = staticFilesRoot->btree_put(this);
}


httpfile::~httpfile()
{
    class btree * b = staticFilesRoot->btree_find(fileName);
    if (b && b == this) staticFilesRoot = staticFilesRoot->btree_get(this);
}

class httpfile *httpfile::find(const char * name)
{
    if(name) {
        class btree * b = staticFilesRoot->btree_find(name);
        if(b) {
            return ((class httpfile *)b);
        }
    }
    return 0;
}

class httpfile *httpfile::find_next_left(const char * name)
{
    if(name) {
        class btree * b = staticFilesRoot->btree_find_next_left(name);
        if(b) {
            return ((class httpfile *)b);
        }
    }
    return 0;
}

int httpfile::btree_compare(void * key)
{
    // It could be, that there is a ? inside the given key, because someone make a request
    // with parameters. So temporarily remove that...
    char * theKey = static_cast<char *>(key);
    char * qpos = strchr(theKey, '?');
    if (qpos)
        *qpos = '\0';
    int result = strcmp(static_cast<char *>(key), fileName);
    if (qpos)
        *qpos = '?';

    return result;
}


int httpfile::btree_compare(class btree * b)
{
    return this->btree_compare(static_cast<httpfile *>(b)->fileName);
}

class httpfile_api * httpfile_api::find(const char * name)
{
    return httpfile::find(name);
}

class httpfile_api * httpfile_api::find_next_left(const char * name)
{
    return httpfile::find_next_left(name);
}

