// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/ClientArgs.java
// @Getter
// public class ClientArgs {
//     private volatile TrpcClientPoolProvider poolProvider;
//     private volatile AbstractLoadBalance loadBalance;
//     private GenericKeyedObjectPoolConfig poolConfig;
//     private List<AbstractMonitor> monitors;
//     private List<String> serviceInterfaces;
//     private String serviceInterface;
//     private String localAppKey;
//     private String remoteAppKey;
//     private String ipPorts;
//     private int timeout;
//     private boolean async;
// 
//     @Builder
//     public ClientArgs(GenericKeyedObjectPoolConfig poolConfig, List<AbstractMonitor> monitors, List<String> serviceInterfaces, String serviceInterface, String localAppKey, String remoteAppKey, String ipPorts, int timeout, boolean async) {
//         this.poolConfig = poolConfig;
//         this.monitors = monitors;
//         this.serviceInterfaces = serviceInterfaces;
//         this.serviceInterface = serviceInterface;
//         this.localAppKey = localAppKey;
//         this.remoteAppKey = remoteAppKey;
//         this.ipPorts = ipPorts;
//         this.timeout = timeout;
//         this.async = async;
//         afterPropertiesSet();
//     }
// 
//     private void afterPropertiesSet() {
//         if (StringUtils.isNoneEmpty(serviceInterface)) {
//             if (serviceInterfaces == null) {
//                 serviceInterfaces = new ArrayList<>();
//             }
//             serviceInterfaces.add(serviceInterface);
//         }
//         if (StringUtils.isNotEmpty(ipPorts)) {
//             List<ThriftServerInfo> serverInfos = Arrays.stream(ipPorts.split(",")).map(ThriftServerInfo::new).collect(Collectors.toList());
//             if (monitors == null) {
//                 monitors = new ArrayList<>();
//             }
//             monitors.add(new StaticMonitor(serverInfos, serviceInterfaces, remoteAppKey));
//         }
//     }
// 
//     public AbstractLoadBalance getLoadBalance() {
//         if (this.loadBalance == null) {
//             synchronized (this) {
//                 if (this.loadBalance == null) {
//                     this.loadBalance = new RandomLoadBalance();
//                 }
//             }
//         }
//         return this.loadBalance;
//     }
// 
//     public TrpcClientPoolProvider getPoolProvider() {
//         if (this.poolProvider == null) {
//             synchronized (this) {
//                 if (this.poolProvider == null) {
//                     this.poolProvider = new TrpcClientPoolImpl(this.poolConfig, this.async);
//                 }
//             }
//         }
//         return this.poolProvider;
//     }
// 
// }
// 
// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/ServiceKey.java
// @Data
// @AllArgsConstructor
// public class ServiceKey {
//     private String remoteKey;
//     private String service;
// }
// 
// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/TrpcServiceNode.java
// @Getter
// @ToString
// @AllArgsConstructor
// @EqualsAndHashCode(of = {"ip", "port"})
// public class TrpcServiceNode implements Comparable<TrpcServiceNode> {
//     private String ip;
//     private int port;
//     private int weight;
//     private int timeout;
// 
//     public static List<TrpcServiceNode> fromRegistryConfig(RegistryConfig registryConfig) {
//         ThriftServerInfo server = registryConfig.getServerInfo();
//         return registryConfig.getServers().stream()
//                 .map(s -> new TrpcServiceNode(server.getIp(), server.getPort(), s.getWeight(), s.getTimeout()))
//                 .collect(Collectors.toList());
//     }
// 
//     public ThriftServerInfo toThriftServerInfo() {
//         return new ThriftServerInfo(this.ip, this.port);
//     }
// 
//     @Override
//     public int compareTo(TrpcServiceNode other) {
//         int result = this.ip.compareTo(other.ip);
//         return result != 0 ? result : this.port - other.port;
//     }
// }


import com.github.sofn.trpc.client.config.ClientArgs;
import com.github.sofn.trpc.client.config.ServiceKey;
import com.github.sofn.trpc.client.config.TrpcServiceNode;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
package com.github.sofn.trpc.client.loadbalance;




/**
 * @author sofn
 * @version 1.0 Created at: 2016-10-03 10:20
 */
public class RoundRobinLoadBalance extends AbstractLoadBalance {

    private final Map<ServiceKey, AtomicInteger> callCounts = new ConcurrentHashMap<>();

    @Override
    public TrpcServiceNode getNode(ServiceKey serviceKey, ClientArgs args) {
        List<TrpcServiceNode> allNodes = getAllNodes(serviceKey, args);
        int length = allNodes.size(); // 总个数
        int maxWeight = 0;            // 最大权重
        int minWeight = Integer.MAX_VALUE; // 最小权重
        int weightSum = 0;
        Map<TrpcServiceNode, AtomicInteger> weightMap = new LinkedHashMap<>();
        for (int i = 0; i < length; i++) {
            TrpcServiceNode node = allNodes.get(i);
            weightMap.put(node, new AtomicInteger(node.getWeight()));
            int weight = node.getWeight();
            maxWeight = Math.max(maxWeight, weight); // 累计最大权重
            minWeight = Math.min(minWeight, weight); // 累计最小权重
            if (weight > 0) {
// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/ClientArgs.java
// @Getter
// public class ClientArgs {
//     private volatile TrpcClientPoolProvider poolProvider;
//     private volatile AbstractLoadBalance loadBalance;
//     private GenericKeyedObjectPoolConfig poolConfig;
//     private List<AbstractMonitor> monitors;
//     private List<String> serviceInterfaces;
//     private String serviceInterface;
//     private String localAppKey;
//     private String remoteAppKey;
//     private String ipPorts;
//     private int timeout;
//     private boolean async;
// 
//     @Builder
//     public ClientArgs(GenericKeyedObjectPoolConfig poolConfig, List<AbstractMonitor> monitors, List<String> serviceInterfaces, String serviceInterface, String localAppKey, String remoteAppKey, String ipPorts, int timeout, boolean async) {
//         this.poolConfig = poolConfig;
//         this.monitors = monitors;
//         this.serviceInterfaces = serviceInterfaces;
//         this.serviceInterface = serviceInterface;
//         this.localAppKey = localAppKey;
//         this.remoteAppKey = remoteAppKey;
//         this.ipPorts = ipPorts;
//         this.timeout = timeout;
//         this.async = async;
//         afterPropertiesSet();
//     }
// 
//     private void afterPropertiesSet() {
//         if (StringUtils.isNoneEmpty(serviceInterface)) {
//             if (serviceInterfaces == null) {
//                 serviceInterfaces = new ArrayList<>();
//             }
//             serviceInterfaces.add(serviceInterface);
//         }
//         if (StringUtils.isNotEmpty(ipPorts)) {
//             List<ThriftServerInfo> serverInfos = Arrays.stream(ipPorts.split(",")).map(ThriftServerInfo::new).collect(Collectors.toList());
//             if (monitors == null) {
//                 monitors = new ArrayList<>();
//             }
//             monitors.add(new StaticMonitor(serverInfos, serviceInterfaces, remoteAppKey));
//         }
//     }
// 
//     public AbstractLoadBalance getLoadBalance() {
//         if (this.loadBalance == null) {
//             synchronized (this) {
//                 if (this.loadBalance == null) {
//                     this.loadBalance = new RandomLoadBalance();
//                 }
//             }
//         }
//         return this.loadBalance;
//     }
// 
//     public TrpcClientPoolProvider getPoolProvider() {
//         if (this.poolProvider == null) {
//             synchronized (this) {
//                 if (this.poolProvider == null) {
//                     this.poolProvider = new TrpcClientPoolImpl(this.poolConfig, this.async);
//                 }
//             }
//         }
//         return this.poolProvider;
//     }
// 
// }
// 
// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/ServiceKey.java
// @Data
// @AllArgsConstructor
// public class ServiceKey {
//     private String remoteKey;
//     private String service;
// }
// 
// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/config/TrpcServiceNode.java
// @Getter
// @ToString
// @AllArgsConstructor
// @EqualsAndHashCode(of = {"ip", "port"})
// public class TrpcServiceNode implements Comparable<TrpcServiceNode> {
//     private String ip;
//     private int port;
//     private int weight;
//     private int timeout;
// 
//     public static List<TrpcServiceNode> fromRegistryConfig(RegistryConfig registryConfig) {
//         ThriftServerInfo server = registryConfig.getServerInfo();
//         return registryConfig.getServers().stream()
//                 .map(s -> new TrpcServiceNode(server.getIp(), server.getPort(), s.getWeight(), s.getTimeout()))
//                 .collect(Collectors.toList());
//     }
// 
//     public ThriftServerInfo toThriftServerInfo() {
//         return new ThriftServerInfo(this.ip, this.port);
//     }
// 
//     @Override
//     public int compareTo(TrpcServiceNode other) {
//         int result = this.ip.compareTo(other.ip);
//         return result != 0 ? result : this.port - other.port;
//     }
// }


// Path: trpc-client/src/main/java/com/github/sofn/trpc/client/loadbalance/RoundRobinLoadBalance.java
import com.github.sofn.trpc.client.config.ClientArgs;
import com.github.sofn.trpc.client.config.ServiceKey;
import com.github.sofn.trpc.client.config.TrpcServiceNode;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

package com.github.sofn.trpc.client.loadbalance;




/**
 * @author sofn
 * @version 1.0 Created at: 2016-10-03 10:20
 */
public class RoundRobinLoadBalance extends AbstractLoadBalance {

    private final Map<ServiceKey, AtomicInteger> callCounts = new ConcurrentHashMap<>();

    @Override
    public TrpcServiceNode getNode(ServiceKey serviceKey, ClientArgs args) {
        List<TrpcServiceNode> allNodes = getAllNodes(serviceKey, args);
        int length = allNodes.size(); // 总个数
        int maxWeight = 0;            // 最大权重
        int minWeight = Integer.MAX_VALUE; // 最小权重
        int weightSum = 0;
        Map<TrpcServiceNode, AtomicInteger> weightMap = new LinkedHashMap<>();
        for (int i = 0; i < length; i++) {
            TrpcServiceNode node = allNodes.get(i);
            weightMap.put(node, new AtomicInteger(node.getWeight()));
            int weight = node.getWeight();
            maxWeight = Math.max(maxWeight, weight); // 累计最大权重
            minWeight = Math.min(minWeight, weight); // 累计最小权重
            if (weight > 0) {
                weightSum += weight;