package com.keao.edu.common.redis.service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import com.keao.edu.common.cache.Cache;
import com.keao.edu.common.cache.CacheException;

@Service
public class RedisCache<K, V> implements Cache<K, V> {

	@Autowired
	private RedisTemplate<K, V> redisTemplate;

	public RedisCache(RedisTemplate<K, V> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	@Override
	public V get(K key) throws CacheException {
		ValueOperations<K, V> valueOps = redisTemplate.opsForValue();
		return valueOps.get(key);
	}

	@Override
	public void put(K key, V value) throws CacheException {
		ValueOperations<K, V> valueOps = redisTemplate.opsForValue();
		valueOps.set(key, value);
	}

	@Override
	public void put(K key, V value, int expireTimes) throws CacheException {
		ValueOperations<K, V> valueOps = redisTemplate.opsForValue();
		valueOps.set(key, value, expireTimes, TimeUnit.SECONDS);
	}

	@Override
	public void delete(K key) throws CacheException {
		redisTemplate.delete(key);
	}

	@Override
	public boolean exists(K key) {
		return redisTemplate.hasKey(key);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Set<K> keys() throws CacheException {
		return redisTemplate.keys((K) "*");
	}

	@Override
	public long size() throws CacheException {
		return keys().size();
	}

	@Override
	public void expire(K key, int expireTimes) {
		redisTemplate.expire(key, expireTimes, TimeUnit.SECONDS);
	}

	public void setRedisTemplate(RedisTemplate<K, V> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public RedisTemplate<K, V> getRedisTemplate() {
		return redisTemplate;
	}

	@Override
	public boolean getLocked(K key, V threadId, int seconds) {
		if (exists(key)) {
			return false;
		}

		put(key, threadId, seconds);

		return true;
	}

	@Override
	public boolean releaseLocked(K key, V threadId) {
		if (exists(key)) {
			V v = get(key);
			if (v.toString().equals(threadId.toString())) {
				delete(key);
				return true;
			}
		}
		return false;
	}
}
