package org.github.etcd.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.github.etcd.service.ApiVersion;
import org.github.etcd.service.ClusterManager;
import org.github.etcd.service.EtcdCluster;
import org.github.etcd.service.EtcdProxyFactory;
import org.github.etcd.service.api.EtcdMember;
import org.github.etcd.service.api.EtcdProxy;
import org.github.etcd.service.api.EtcdSelfStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClusterManagerImpl implements ClusterManager {

    private static final Logger log = LoggerFactory.getLogger(ClusterManager.class);

    private static final Comparator<EtcdMember> MEMBER_SORTER = new Comparator<EtcdMember>() {
        @Override
        public int compare(EtcdMember o1, EtcdMember o2) {
            return o1.getName().compareTo(o2.getName());
        }
    };

    private static final Map<String, String> STATE_MAPPINGS = new HashMap<>();

    static {
        STATE_MAPPINGS.put("leader", "leader");
        STATE_MAPPINGS.put("follower", "follower");
        STATE_MAPPINGS.put("StateLeader", "leader");
        STATE_MAPPINGS.put("StateFollower", "follower");
    }

    @Inject
    private EtcdProxyFactory proxyFactory;

    private Map<String, EtcdCluster> clusters = Collections.synchronizedMap(new LinkedHashMap<String, EtcdCluster>());

    private static final String DEFAULT_ETCD_CLIENT = "ETCD_CLIENT_URL";

    public ClusterManagerImpl() {

        String etcdAddress = System.getenv(DEFAULT_ETCD_CLIENT);
        if (etcdAddress == null) {
            etcdAddress = System.getProperty(DEFAULT_ETCD_CLIENT, "http://localhost:2379/");
        }

        addCluster("default", etcdAddress, ApiVersion.V2);
        // addCluster("kvm", "http://192.168.122.201:2379/");
    }

    @Override
    public boolean exists(String name) {
        return clusters.containsKey(name);
    }

    @Override
    public EtcdCluster getCluster(String name) {
        return name == null ? null : clusters.get(name);
    }

    @Override
    public EtcdCluster addCluster(String name, String etcdPeerAddress, ApiVersion apiVersion) {
        EtcdCluster cluster = new EtcdCluster(name, etcdPeerAddress, apiVersion);
        clusters.put(name, cluster);
        return cluster;
    }

    @Override
    public void removeCluster(String name) {
        clusters.remove(name);
    }

    @Override
    public List<EtcdCluster> getClusters() {
        return new ArrayList<>(clusters.values());
    }

    @Override
    public List<String> getClusterNames() {
        return new ArrayList<>(clusters.keySet());
    }

    @Override
    public void refreshCluster(String name) {
        if (name == null) {
            return;
        }
        EtcdCluster cluster = clusters.get(name);

        // default leader address is the provided one
        String leaderAddress = cluster.getAddress();
        ApiVersion apiVersion = cluster.getApiVersion();

        List<EtcdMember> members;

        try (EtcdProxy proxy = proxyFactory.getEtcdProxy(name, leaderAddress, apiVersion)) {

            members = proxy.getMembers();
            Collections.sort(members, MEMBER_SORTER);

            cluster.setAuthEnabled(proxy.isAuthEnabled());

        } catch (Exception e) {
            log.error("Last known leader " + leaderAddress + " is not accessible: " + e.getLocalizedMessage(), e);
            // use the previously discovered members if they exist
            if (cluster.getMembers() == null) {
                throw e;
            }
            members = cluster.getMembers();
        }

        // collect self statistics from each member
        for (EtcdMember member : members) {

            member.setState(null);
            member.setVersion(null);

            for (String clientURL : member.getClientURLs()) {

                try (EtcdProxy proxy = proxyFactory.getEtcdProxy(name, clientURL, apiVersion)) {

                    EtcdSelfStats memberStats = proxy.getSelfStats();

                    member.setState(STATE_MAPPINGS.get(memberStats.getState()));

                    if ("leader".equals(member.getState())) {
                        leaderAddress = clientURL;

                        cluster.setAuthEnabled(proxy.isAuthEnabled());

                    }

                    member.setVersion(proxy.getVersion());


                    break;
                } catch (Exception e) {
                    log.warn("etcd server " + clientURL + " is not accessible: " + e.getLocalizedMessage(), e);
                }
            }
        }

        cluster.setMembers(members);

        cluster.setAddress(leaderAddress);
        cluster.setLastRefreshTime(new Date());
        cluster.setRefreshed(true);

    }

}

@@ -1832,25 +1832,24 @@
 calhost:2379
-/
 %22);%0A        
@@ -1906,17 +1906,17 @@
 ersion.V
-2
+3
 );%0A     

Use v3 API by default