// 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 org.apache.commons.lang3.RandomUtils;
import java.util.List;
package com.github.sofn.trpc.client.loadbalance;




/**
 * @author sofn
 * @version 1.0 Created at: 2016-10-02 00:20
 */
public class RandomLoadBalance extends AbstractLoadBalance {

    @Override
    public TrpcServiceNode getNode(ServiceKey key, ClientArgs args) {
        List<TrpcServiceNode> allNodes = getAllNodes(key, args);

        int length = allNodes.size(); // 总个数
        int totalWeight = 0;          // 总权重
        boolean sameWeight = true;    // 权重是否都一样
        for (int i = 0; i < length; i++) {
            int weight = allNodes.get(i).getWeight();
            totalWeight += weight; // 累计总权重
            if (sameWeight && i > 0 && weight != allNodes.get(i - 1).getWeight()) {
                sameWeight = false; // 计算所有权重是否一样
            }
        }
        if (totalWeight > 0 && !sameWeight) {
            // 如果权重不相同且权重大于0则按总权重数随机
            int offset = RandomUtils.nextInt(0, totalWeight);
            // 并确定随机值落在哪个片断上
            for (TrpcServiceNode node : allNodes) {
                offset -= node.getWeight();
                if (offset < 0) {
                    return node;
                }
            }
        }
        // 如果权重相同或权重为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/RandomLoadBalance.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 org.apache.commons.lang3.RandomUtils;
import java.util.List;

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




/**
 * @author sofn
 * @version 1.0 Created at: 2016-10-02 00:20
 */
public class RandomLoadBalance extends AbstractLoadBalance {

    @Override
    public TrpcServiceNode getNode(ServiceKey key, ClientArgs args) {
        List<TrpcServiceNode> allNodes = getAllNodes(key, args);

        int length = allNodes.size(); // 总个数
        int totalWeight = 0;          // 总权重
        boolean sameWeight = true;    // 权重是否都一样
        for (int i = 0; i < length; i++) {
            int weight = allNodes.get(i).getWeight();
            totalWeight += weight; // 累计总权重
            if (sameWeight && i > 0 && weight != allNodes.get(i - 1).getWeight()) {
                sameWeight = false; // 计算所有权重是否一样
            }
        }
        if (totalWeight > 0 && !sameWeight) {
            // 如果权重不相同且权重大于0则按总权重数随机
            int offset = RandomUtils.nextInt(0, totalWeight);
            // 并确定随机值落在哪个片断上
            for (TrpcServiceNode node : allNodes) {
                offset -= node.getWeight();
                if (offset < 0) {
                    return node;
                }
            }
        }
        // 如果权重相同或权重为0则均等随机
        return allNodes.get(RandomUtils.nextInt(0, length));