from django.contrib.sessions.backends.base import SessionBase, CreateError
from django.conf import settings
from django.utils.encoding import force_unicode
import redis

class SessionStore(SessionBase):
    """ Redis store for sessions"""

    def __init__(self, session_key=None):
        self.redis = redis.Redis(
            host = settings.SESSION_REDIS_HOST,
            port = settings.SESSION_REDIS_PORT,
            socket_timeout = settings.REDIS_SOCKET_TIMEOUT
        )
        super(SessionStore, self).__init__(session_key)

    @classmethod
    def _get_key_for_redis(self, session_key):
        return 'sessionstore:%s' % session_key

    def _redis_key(self):
        return self.__class__._get_key_for_redis(self.session_key)

    def load(self):
        session_data = self.redis.get(self._redis_key())
        if session_data is not None:
            return self.decode(force_unicode(session_data))
        else:
            self.create()
            return {}

    def create(self):
        max_attempts = 10
        attempt = 0
        while True:
            self.session_key = self._get_new_session_key()
            session_dict = self._get_session(no_load = True)
            session_data = self.encode(session_dict)

            was_created = self.redis.setnx(self._redis_key(), 
                                           session_data)
            if was_created:
                self.redis.expire(self._redis_key(),
                                  settings.SESSION_COOKIE_AGE)
                self.modified = True
                self._session_cache = session_dict
                return
            else:
                # extremely unlikely
                if attempt == max_attempts:
                    raise CreateError
                else:
                    attempt += 1
                    continue

    def save(self, must_create=False):
        if must_create:
            self.create()
        else:
            encoded_data = self.encode(self._session)
            self.redis.setex(self._redis_key(), encoded_data, settings.SESSION_COOKIE_AGE)

    def exists(self, session_key):
        return self.redis.exists(self.__class__._get_key_for_redis(session_key))

    def delete(self, session_key=None):
        to_delete = (session_key or self.session_key)
        redis_key = self.__class__._get_key_for_redis(to_delete)
        self.redis.delete(redis_key)
