package com.cirle.scientific.utils.redis;

import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 分布式锁servicee
 *
 * @author heihaier@mmears.com
 * Date: 2018/10/10
 * Time: 8:09 PM
 */
@Slf4j
@Service
public class DistributedLockCache {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     *
     * @param lock 锁
     * @param timeout 分布式锁尝试超时时间 单位：毫秒
     * @param tryInterval 分布式锁间隔时间 单位：毫秒
     * @param lockExpireTime 分布式锁过期时间 单位：秒
     * @return
     */
    public boolean tryLock(QkLock lock, long timeout, long tryInterval, long lockExpireTime) {
        return getLock(lock, timeout, tryInterval, lockExpireTime);
    }


    public boolean getLock(QkLock lock, long timeout, long tryInterval, long lockExpireTime) {
        try {
            if (Strings.isNullOrEmpty(lock.getName()) || Strings.isNullOrEmpty(lock.getValue())) {
                return false;
            }

            long startTime = System.currentTimeMillis();

            while (System.currentTimeMillis() - startTime < timeout) {
                if (stringRedisTemplate.opsForValue().setIfAbsent(lock.getName(), lock.getValue())) {
                    Boolean flag = stringRedisTemplate.expire(lock.getName(), lockExpireTime, TimeUnit.SECONDS);
                    if (!flag) {
                        stringRedisTemplate.delete(lock.getName());
                    }
                    return flag;
                }

                Thread.sleep(tryInterval);
            }

            return false;
        } catch (Exception e) {
            log.error("get lock fail.", e);
            stringRedisTemplate.delete(lock.getName());
            return false;
        }
    }

    public void releaseLock(QkLock lock) {
        if (!Strings.isNullOrEmpty(lock.getName())) {
            stringRedisTemplate.delete(lock.getName());
        }
    }
}
