package com.zzsn.common.cache;

import com.google.code.yanf4j.core.impl.StandardSocketOption;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.transcoders.SerializingTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * Memcached客户端
 */
public class Memcached {
	private static Logger logger = LoggerFactory.getLogger(Memcached.class);

	private static MemcachedClient client = null;

	static {
		logger.debug("memcached initialize...");
		Properties prop = getConfig();
		String server = prop.getProperty("memcached.server");
		if (server == null || server.isEmpty()) {
			throw new IllegalArgumentException("The property 'memcached.server' is not found in memcached.properties file!");
		}
		String[] servers = server.split(",");
		int[] weights = new int[servers.length];
		List<InetSocketAddress> addressList = new ArrayList<>(servers.length);
		for (int i = 0; i < servers.length; i++) {
			String[] addr = servers[i].split(":");
			addressList.add(new InetSocketAddress(addr[0], Integer.parseInt(addr[1])));
			String weight = prop.getProperty("memcached.server"+(i+1)+".weight");
			if (weight == null || weight.isEmpty()) {
				weights[i] = 1;
			} else {
				weights[i] = Integer.parseInt(weight);
			}
		}
		XMemcachedClientBuilder builder = new XMemcachedClientBuilder(addressList, weights);
		String poolSize = prop.getProperty("memcached.connectionPoolSize");
		if (poolSize != null && !poolSize.isEmpty()) {
			builder.setConnectionPoolSize(Integer.parseInt(poolSize));
		}
		String failureMode = prop.getProperty("memcached.failureMode");
		if (failureMode != null && !failureMode.isEmpty()) {
			builder.setFailureMode(Boolean.parseBoolean(failureMode));
		}
		String connTimeout = prop.getProperty("memcached.connectTimeout");
		if (connTimeout != null && !connTimeout.isEmpty()) {
			builder.setConnectTimeout(Integer.parseInt(connTimeout));
		}
		String opTimeout = prop.getProperty("memcached.opTimeout");
		if (opTimeout != null && !opTimeout.isEmpty()) {
			builder.setOpTimeout(Integer.parseInt(opTimeout));
		}
		String enableHealSession = prop.getProperty("memcached.enableHealSession");
		if (enableHealSession != null && !enableHealSession.isEmpty()) {
			builder.setEnableHealSession(Boolean.parseBoolean(enableHealSession));//启用或者禁止连接修复
		}
		String statistics = prop.getProperty("memcached.statistics");
		if (statistics != null && !statistics.isEmpty()) {
			builder.getConfiguration().setStatisticsServer(Boolean.parseBoolean(statistics));
		}
		String binary = prop.getProperty("memcached.binaryCommand");
		if (binary != null && "true".equals(binary)) {
			builder.setCommandFactory(new BinaryCommandFactory());
		}
		builder.setTranscoder(new SerializingTranscoder());
		builder.setSocketOption(StandardSocketOption.SO_RCVBUF, 32* 1024);// 设置接收缓存区为32K，默认16K
		builder.setSocketOption(StandardSocketOption.SO_SNDBUF,16 *1024); // 设置发送缓冲区为16K，默认为8K
		builder.setSocketOption(StandardSocketOption.TCP_NODELAY,true); // 启用nagle算法，提高吞吐量，默认关闭
		String sessionIdleTimeout = prop.getProperty("memcahced.sessionIdleTimeout");
		if (sessionIdleTimeout != null && !sessionIdleTimeout.isEmpty()) {
			builder.getConfiguration().setSessionIdleTimeout(Integer.parseInt(sessionIdleTimeout)*1000); // 如果连接超过x秒没有任何IO操作发生即认为空闲并发起心跳检测
		}

		try {
			client = builder.build();
			String optimizeMergeBuffer = prop.getProperty("memcached.optimizeMergeBuffer");
			if (optimizeMergeBuffer != null && !optimizeMergeBuffer.isEmpty()) {
				client.setOptimizeMergeBuffer(Boolean.parseBoolean(optimizeMergeBuffer));
			}
			String mergeFactor = prop.getProperty("memcached.mergeFactor");
			if (mergeFactor != null && !optimizeMergeBuffer.isEmpty()) {
				client.setMergeFactor(Integer.parseInt(mergeFactor));
			}
			logger.debug("memcached initialize completed!");
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private Memcached() {

	}

	public static MemcachedClient getClient() {
		return client;
	}

	public static void shutdown(MemcachedClient client) {
		if (client != null) {
			try {
				client.shutdown();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static Properties getConfig() {
		Properties properties = new Properties();
		InputStream is = null;
		String location = "memcached.properties";
		try {
			Resource resource = new DefaultResourceLoader().getResource(location);
			is = resource.getInputStream();
			properties.load(is);
			logger.debug("memcached config: {}", properties.toString());
		} catch (IOException ex) {
			logger.error("Could not load property file:" + location, ex);
		} finally {
			try {
				if (is != null) {
					is.close();
				}
			} catch (IOException ioe) {
				// ignore
			}
		}
		return properties;
	}
}
