/**
 * 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.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

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

	private static String IP_ADDR;

	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();
					// 排除loopback类型地址
					if (!inetAddr.isLoopbackAddress()) {
						log.info("Not LoopbackAddress:{}", inetAddr);
						if (inetAddr.isSiteLocalAddress()) {
							// 如果是site-local地址，就是它了
							IP_ADDR = inetAddr.getHostAddress();
							break;
						} else if (candidateAddress == null) {
							// site-local类型的地址未被发现，先记录候选地址
							if (inetAddr instanceof Inet4Address) {
								candidateAddress = inetAddr;
							}
						}
					} else {
						log.info("LoopbackAddress:{}", inetAddr);
					}
				}
			}
			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);
		}
	}

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

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

	/**
	 * <pre>获取http请求的真实IP地址</pre>
	 *
	 * @param request
	 * @return
	 */
	public static String getIPAddr(ServerHttpRequest request) {
		if (request == null) {
			return null;
		}
		HttpHeaders headers = request.getHeaders();

		String ip = headers.getFirst("X-Forwarded-For");

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

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

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

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
		}

		// getRequest().getRemoteAddress().getAddress() 电信DCOS k8s环境下获取可能会发生非常缓慢的情况，取消这种获取方式
//		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
//			ip = request.getRemoteAddress().getHostName();
//		}

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

		return ip;
	}

}
