/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

#include "common.h"

#define DEBUG_FLAG SEAFILE_DEBUG_OTHER
#include "log.h"
#include "redis-cache.h"
#include "obj-cache.h"

#define DEFAULT_MEMCACHED_EXPIRY 24 * 3600
#define DEFAULT_MAX_CONNECTIONS 100

typedef struct CacheOption {
    char *cache_provider;
    char *redis_host;
    char *redis_passwd;
    int redis_port;
    int redis_max_connections;
    int redis_expiry;
} CacheOption;

static void
cache_option_free (CacheOption *option)
{
    if (!option)
        return;
    g_free (option->cache_provider);
    g_free (option->redis_host);
    g_free (option->redis_passwd);
    g_free (option);
}

static void
load_cache_option_from_env (CacheOption *option)
{
    const char *cache_provider, *redis_host, *redis_port, *redis_passwd, *redis_max_conn, *redis_expiry;

    cache_provider = g_getenv("CACHE_PROVIDER");
    redis_host = g_getenv("REDIS_HOST");
    redis_port = g_getenv("REDIS_PORT");
    redis_passwd = g_getenv("REDIS_PASSWORD");
    redis_max_conn = g_getenv("REDIS_MAX_CONNECTIONS");
    redis_expiry = g_getenv("REDIS_EXPIRY");

    if (!cache_provider || g_strcmp0 (cache_provider, "") == 0) {
        return;
    }

    if (cache_provider) {
        g_free (option->cache_provider);
        option->cache_provider = g_strdup (cache_provider);
    }
    if (redis_host && g_strcmp0(redis_host, "") != 0) {
        g_free (option->redis_host);
        option->redis_host = g_strdup (redis_host);
    }
    if (redis_port && g_strcmp0(redis_port, "") != 0) {
        option->redis_port = atoi (redis_port);
    }
    if (redis_passwd && g_strcmp0 (redis_passwd, "") != 0) {
        g_free (option->redis_passwd);
        option->redis_passwd = g_strdup (redis_passwd);
    }
    if (redis_max_conn && g_strcmp0 (redis_max_conn, "") != 0) {
        option->redis_max_connections = atoi (redis_max_conn);
    }
    if (redis_expiry && g_strcmp0 (redis_expiry, "") != 0) {
        option->redis_expiry = atoi (redis_expiry);
    }
}

ObjCache *
objcache_new ()
{
    ObjCache *cache = NULL;
    GError *error = NULL;
    CacheOption *option = g_new0 (CacheOption, 1);
    int redis_port;
    int redis_expiry;
    int redis_max_connections;

    redis_expiry = DEFAULT_MEMCACHED_EXPIRY;
    redis_port = 6379;
    redis_max_connections = DEFAULT_MAX_CONNECTIONS;

    option->redis_port = redis_port;
    option->redis_max_connections = redis_max_connections;
    option->redis_expiry = redis_expiry;

    load_cache_option_from_env (option);

    if (g_strcmp0 (option->cache_provider, "redis") == 0) {
        cache = redis_cache_new (option->redis_host, option->redis_passwd, option->redis_port, option->redis_expiry, option->redis_max_connections);
    } else if (option->cache_provider){
        seaf_warning ("Unsupported cache provider: %s\n", option->cache_provider);
    }

    cache_option_free (option);

    return cache;
}

void *
objcache_get_object (ObjCache *cache, const char *obj_id, size_t *len)
{
    return cache->get_object (cache, obj_id, len);
}

int
objcache_set_object (ObjCache *cache,
                    const char *obj_id,
                    const void *object,
                    int len,
                    int expiry)
{
    return cache->set_object (cache, obj_id, object, len, expiry);
}

gboolean
objcache_test_object (ObjCache *cache, const char *obj_id)
{
    return cache->test_object (cache, obj_id);
}

int
objcache_delete_object (ObjCache *cache, const char *obj_id)
{
    return cache->delete_object (cache, obj_id);
}

int
objcache_set_object_existence (ObjCache *cache, const char *obj_id, int val, int expiry, const char *existence_prefix)
{
    char *key;
    char buf[8];
    int n;
    int ret;

    key = g_strdup_printf ("%s%s", existence_prefix, obj_id);
    n = snprintf (buf, sizeof(buf), "%d", val);

    ret = cache->set_object (cache, key, buf, n+1, expiry);

    g_free (key);
    return ret;
}

int
objcache_get_object_existence (ObjCache *cache, const char *obj_id, int *val_out, const char *existence_prefix)
{
    char *key;
    size_t len;
    char *val;
    int ret = 0;

    key = g_strdup_printf ("%s%s", existence_prefix, obj_id);

    val = cache->get_object (cache, key, &len);
    if (!val)
        ret = -1;
    else 
        *val_out = atoi(val);

    g_free (key);
    g_free (val);
    return ret;
}

int
objcache_delete_object_existence (ObjCache *cache, const char *obj_id, const char *existence_prefix)
{
    char *key;
    int ret;

    key = g_strdup_printf ("%s%s", existence_prefix, obj_id);

    ret = cache->delete_object (cache, key);

    g_free (key);
    return ret;
}

int
objcache_publish (ObjCache *cache, const char *channel, const char *msg)
{
    int ret;
    ret = cache->publish (cache, channel, msg);
    return ret;
}

int
objcache_push (ObjCache *cache, const char *list, const char *msg)
{
    int ret;
    ret = cache->push (cache, list, msg);
    return ret;
}
