package com.sjyt.icom.asst.conf;

import com.sjyt.icom.asst.conf.properties.ObjectPoolsProperties;
import com.sjyt.icom.asst.context.pools.MeetRoomFactory;
import com.sjyt.icom.asst.context.pools.MeetRoomPool;
import com.sjyt.icom.asst.context.pools.One2OneRoomFactory;
import com.sjyt.icom.asst.context.pools.One2OneRoomPool;
import com.sjyt.icom.asst.common.model.room.MeetRoom;
import com.sjyt.icom.asst.common.model.room.OneToOneRoom;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <p>自动装配，对象池配置</p>
 *
 * @author renyanru
 * @version V1.0.0
 * @date 2022/6/16 10:35
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(ObjectPoolsProperties.class)
public class ObjectPoolConfig {
    private final ObjectPoolsProperties objectPoolsProperties;
    private One2OneRoomPool one2OneRoomPool;
    private MeetRoomPool meetRoomPool;

    @Autowired
    public ObjectPoolConfig(ObjectPoolsProperties objectPoolsProperties) {
        this.objectPoolsProperties = objectPoolsProperties;
    }
    /**
     * 一对一房间池化
     * @return r
     */
    @Bean
    @ConditionalOnClass(OneToOneRoom.class)
    protected One2OneRoomPool one2OneRoomPool() {
        One2OneRoomFactory factory = new One2OneRoomFactory();
        GenericObjectPoolConfig<OneToOneRoom> config = new GenericObjectPoolConfig<>();
        initConfig(config);
        //创建对象池，并传入配置
        one2OneRoomPool = new One2OneRoomPool(factory, config);
        initOne2OneRoomPools(objectPoolsProperties.getInitialSize(), objectPoolsProperties.getMaxIdle());
        return one2OneRoomPool;
    }
    /**
     * 会议房间池化
     * @return r
     */
    @Bean
    @ConditionalOnClass(MeetRoom.class)
    protected MeetRoomPool meetRoomPool() {
        MeetRoomFactory factory = new MeetRoomFactory();
        GenericObjectPoolConfig<MeetRoom> config = new GenericObjectPoolConfig<>();
        initConfig(config);
        //创建对象池，并传入配置
         meetRoomPool= new MeetRoomPool(factory, config);
        initMeetRoomPools(objectPoolsProperties.getInitialSize(), objectPoolsProperties.getMaxIdle());
        return meetRoomPool;
    }
    private  void initConfig(GenericObjectPoolConfig config){
        //连接池中最大数量
        config.setMaxIdle(objectPoolsProperties.getMaxIdle());
        config.setMaxTotal(objectPoolsProperties.getMaxTotal());
        config.setMinIdle(objectPoolsProperties.getMinIdle());
        //为true时,maxWaitMillis参数才能生效.为false时,当连接池没有资源，立马抛出一次。默认为true
        config.setBlockWhenExhausted(true);
        //默认false，borrow的时候检测是有有效，如果无效则从池子中移除，并尝试继续获取
        config.setTestOnBorrow(true);
        //默认false，return的时候检测是有有效，如果无效则从池子中移除，并尝试继续获取
        config.setTestOnReturn(false);
        //默认false，在evictor线程里头，当evictorPolicy.evict()方法返回false时，而且testWhileIdle为true时检测是否有效，如果无效则从池子中移除
        config.setTestWhileIdle(true);
        //空闲连接检测线程检测的周期，毫秒数。如果为负值，表示不运行检测程序。默认为-1
        config.setTimeBetweenEvictionRunsMillis(-1);
        //关闭jmx，springboot报错
        config.setJmxEnabled(false);
    }

    /**
     * 预加载一对一房间对象到池子
     *
     * @param initialSize 初始化大小
     * @param maxIdle     最大数
     */
    private void initOne2OneRoomPools(int initialSize, int maxIdle) {
        if (initialSize < 0) {
            return;
        }
        int size = Math.max(initialSize, maxIdle);
        try {
            for (int i = 0; i < size; i++) {
                one2OneRoomPool.addObject();
                //TimeUnit.MILLISECONDS.sleep(100L);
            }
        log.info("*****************一对一房间池初始化完成*****************");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 预加载会议房间对象到池子
     *
     * @param initialSize 初始化大小
     * @param maxIdle     最大数
     */
    private void initMeetRoomPools(int initialSize, int maxIdle) {
        if (initialSize < 0) {
            return;
        }
        int size = Math.max(initialSize, maxIdle);
        try {
            for (int i = 0; i < size; i++) {
                meetRoomPool.addObject();
            }
            log.info("*****************会议房间池初始化完成*****************");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
