/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

/**
 * @author 田平 create 2016年5月17日下午3:28:05
 */
@Slf4j
public class IPUtil {

	/**
	 * 非回环地址的合集
	 */
	private static final Set<String> IP_ADDRS = new HashSet<>();

	private static String IP_ADDR;

	private static String preferredAddress = System.getProperty("preferredAddress");
	static {
		if(!StringUtils.hasText(preferredAddress)) {
			preferredAddress = System.getenv("preferredAddress");
		}
	}
	static {
		try {
			InetAddress candidateAddress = null;
			// 遍历所有的网络接口
			for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
				NetworkInterface iface = ifaces.nextElement();
				// 在所有的接口下再遍历IP
				for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
					InetAddress inetAddr = inetAddrs.nextElement();
					if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
						log.info("Not LoopbackAddress:{}", inetAddr);
						if (inetAddr.isSiteLocalAddress()) {
							// 如果是site-local地址，就是它了
//							IP_ADDR = inetAddr.getHostAddress();
							IP_ADDRS.add(inetAddr.getHostAddress());
							break;
						} else if (candidateAddress == null) {
							// site-local类型的地址未被发现，先记录候选地址
							if (inetAddr instanceof Inet4Address) {
								candidateAddress = inetAddr;
							}
						}
						if (inetAddr instanceof Inet4Address) {
							IP_ADDRS.add(inetAddr.getHostAddress());
						}
					} else {
						log.info("LoopbackAddress:{}", inetAddr);
					}
				}
			}
			if(!IP_ADDRS.isEmpty()) {
				IP_ADDRS.forEach(addr->{
					if(isPreferredAddress(addr)) {
						IP_ADDR = addr;
						return;
					}
				});
			}

			if (IP_ADDR == null) {
				if (candidateAddress != null) {
					IP_ADDR = candidateAddress.getHostAddress();
				} else {
					// 如果没有发现 non-loopback地址.只能用最次选的方案
					IP_ADDR = InetAddress.getLocalHost().getHostAddress();
				}
			}
		} catch (Exception e) {
			log.error("ipaddr get error!", e);
		}
	}

	private static boolean isPreferredAddress(String hostAddress) {
		if (!StringUtils.hasText(preferredAddress)) {
			return true;
		}
		if (hostAddress.matches(preferredAddress) || hostAddress.startsWith(preferredAddress)) {
			return true;
		}
		return false;
	}

	public static void main(String[] args) {
		//System.out.println(getIP());
		System.out.println(calcMaskByPrefixLength(24));
	}

	/**
	 * <pre>该方法比较耗时，进行缓存，后面不在获取</pre>
	 *
	 * @return
	 */
	public static String getIP() {
		return IP_ADDR;
	}

	/**
	 * 获取http请求的真实IP地址
	 *
	 * @param request
	 * @return
	 */
	public static String getIPAddr(HttpServletRequest request) {
		if (request == null) {
			return null;
		}
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		//电信DCOS k8s环境下获取可能会发生非常缓慢的情况，取消这种获取方式,千万不要使用
//		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
//			ip = request.getRemoteAddr();
//		}

		if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
			ip = IP_ADDR;
		}
		return ip;
	}


	//经过子网掩码的位数计算子网掩码
	public static String calcMaskByPrefixLength(int length) {

		int mask = 0xffffffff << (32 - length);
		int partsNum = 4;
		int bitsOfPart = 8;
		int maskParts[] = new int[partsNum];
		int selector = 0x000000ff;

		for (int i = 0; i < maskParts.length; i++) {
			int pos = maskParts.length - 1 - i;
			maskParts[pos] = (mask >> (i * bitsOfPart)) & selector;
		}

		String result = "";
		result = result + maskParts[0];
		for (int i = 1; i < maskParts.length; i++) {
			result = result + "." + maskParts[i];
		}
		return result;
	}


}
