#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Developed by niphlod@gmail.com
License MIT/BSD/GPL

Serves as base to implement Redis connection object and various utils
for redis_cache, redis_session and redis_scheduler in the future
Should-could be overriden in case redis doesn't keep up (e.g. cluster support)
to ensure compatibility with another - similar - library
"""

import logging
from threading import Lock
import time
from gluon import current

logger = logging.getLogger("web2py.redis_utils")

try:
    import redis
    from redis.exceptions import WatchError as RWatchError
    from redis.exceptions import ConnectionError as RConnectionError
except ImportError:
    logger.error("Needs redis library to work")
    raise RuntimeError('Needs redis library to work')


locker = Lock()


def RConn(application=None, *args, **vars):
    """
    Istantiates a StrictRedis connection with parameters, at the first time
    only
    """
    locker.acquire()
    try:
        if application is None:
            application = current.request.application
        instance_name = 'redis_conn_' + application
        if not hasattr(RConn, instance_name):
            setattr(RConn, instance_name, redis.StrictRedis(*args, **vars))
        return getattr(RConn, instance_name)
    finally:
        locker.release()

def acquire_lock(conn, lockname, identifier, ltime=10):
    while True:
        if conn.set(lockname, identifier, ex=ltime, nx=True):
            return identifier
        time.sleep(.01)


_LUA_RELEASE_LOCK = """
if redis.call("get", KEYS[1]) == ARGV[1]
then
    return redis.call("del", KEYS[1])
else
    return 0
end
"""


def release_lock(instance, lockname, identifier):
    return instance._release_script(
        keys=[lockname], args=[identifier])


def register_release_lock(conn):
    rtn = conn.register_script(_LUA_RELEASE_LOCK)
    return rtn
