package cn.com.qmth.stmms.biz.lock.impl;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.stereotype.Component;

import cn.com.qmth.stmms.biz.lock.LockProvider;
import cn.com.qmth.stmms.common.enums.LockType;

/**
 * 自己实现的内存锁控制
 * 
 * @author luoshi
 *
 */
@Component("customLockProvider")
public class CustomLockProvider implements LockProvider {

    private Map<LockType, Map<String, ReadWriteLock>> lockMap = new HashMap<>();

    @Override
    public void waitLock(LockType type, String key) {
        getLock(type, key).write();
    }

    @Override
    public boolean tryLock(LockType type, String key) {
        return getLock(type, key).tryWrite();
    }

    @Override
    public boolean isLocked(LockType type, String key) {
        return getLock(type, key).writing();
    }

    @Override
    public void unlock(LockType type, String key) {
        getLock(type, key).unWrite();
    }

    @Override
    public void watch(LockType type, String key) {
        getLock(type, key).read();
    }

    @Override
    public void unwatch(LockType type, String key) {
        getLock(type, key).unRead();
    }

    private ReadWriteLock getLock(LockType type, String key) {
        Map<String, ReadWriteLock> map = lockMap.get(type);
        if (map == null) {
            synchronized (lockMap) {
                map = lockMap.get(type);
                if (map == null) {
                    map = new HashMap<>();
                    lockMap.put(type, map);
                }
            }
        }

        ReadWriteLock lock = map.get(key);
        if (lock == null) {
            synchronized (map) {
                lock = map.get(key);
                if (lock == null) {
                    lock = new ReadWriteLock();
                    map.put(key, lock);
                }
            }
        }

        return lock;
    }

    public void clear() {
        if (lockMap.isEmpty()) {
            return;
        }
        synchronized (lockMap) {
            for (Map<String, ReadWriteLock> map : lockMap.values()) {
                Set<String> keys = new HashSet<>();
                for (Entry<String, ReadWriteLock> entry : map.entrySet()) {
                    if (!entry.getValue().writing() && entry.getValue().readCount() == 0) {
                        keys.add(entry.getKey());
                    }
                }
                for (String key : keys) {
                    map.remove(key);
                }
                keys.clear();
            }
        }
    }

}
