package com.zm.order.tool.server.component;

import com.google.common.base.Throwables;
import org.apache.curator.framework.CuratorFramework;
import org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * @Description snowflake算法构建id
 * @Author 陈标
 * @Date 2020/4/14 15:08
 */
@Component
public class ShardingKeyGenerator implements InitializingBean {

    private static Logger logger = LoggerFactory.getLogger(ShardingKeyGenerator.class);

    /**
     * 功能：数据运行节点的ID标识
     */
    private static final String WORKER_ID = "worker.id";

    /**
     * 通用运行节点路径
     */
    private static final String COMMON_WORKER_PATH = "/worker";

    /**
     * 项目路径
     */
    private static final String PROJECT_PATH = "/order-center/";

    @Autowired
    private CuratorFramework curator;

    private final SnowflakeShardingKeyGenerator defaultKeyGenerator = new SnowflakeShardingKeyGenerator();


    public String generateSnowflakeKey() {
        return defaultKeyGenerator.generateKey().toString();
    }

    public long generateSnowflakeNumKey() {
        return Long.parseLong(generateSnowflakeKey());
    }


    private long initWorkerId() {
        long workerId = 0L;
        while (!createZkNode(workerId)) {
            workerId++;
        }
        logger.info("current workerId is {} ", workerId);
        return workerId;
    }

    private boolean createZkNode(long workerId) {
        try {
            Stat stat = curator.checkExists().forPath(COMMON_WORKER_PATH + PROJECT_PATH + workerId);
            if (stat != null) {
                return false;
            }
            // 创建一个临时节点，并自动递归创建父节点
            curator.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(COMMON_WORKER_PATH + PROJECT_PATH + workerId);
        } catch (Throwable throwable) {
            logger.error("create zk node failed, cause by:{}",
                    workerId, Throwables.getStackTraceAsString(throwable));
            return false;
        }
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Properties properties = defaultKeyGenerator.getProperties();
        if (properties == null) {
            properties = new Properties();
        }
        String workerId = initWorkerId() + "";
        properties.setProperty(WORKER_ID, workerId);
        defaultKeyGenerator.setProperties(properties);
    }

}



