package com.dsk.web.controller.tool;


import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

/**
* IP校验
*/
public class IpUtil {
	
	public final static List<String> qihooSpider = Arrays.asList("180.153.232","180.153.234","180.153.236","180.163.220","42.236.101","42.236.102","42.236.103","42.236.10","42.236.12","42.236.13","42.236.14","42.236.15","42.236.16","42.236.17","42.236.46","42.236.48","42.236.49","42.236.50","42.236.51","42.236.52","42.236.53","42.236.54","42.236.55","42.236.99");

    public final static List<String> YisouSpider = Arrays.asList("106.11.152","106.11.153","106.11.154","106.11.155","106.11.156","106.11.157","106.11.158","106.11.159","42.120.160","42.120.161","42.156.136","42.156.137","42.156.138","42.156.139","42.156.254");

    public final static List<String> ByteSpider = Arrays.asList("110.249.201","110.249.202","111.225.147","111.225.148","111.225.149","220.243.135","220.243.136","60.8.165","60.8.9");

    
    /**获取访问用户的客户端IP（适用于公网与局域网）*/
    public static final String getIpAddr(final HttpServletRequest request){
    	try{
    		if (request == null) 	return null;
            String ipString = request.getHeader("ali-cdn-real-ip");
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
                ipString = request.getHeader("x-forwarded-for");
            }
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
                ipString = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
            	ipString = request.getHeader("X-Forwarded-For");
            }
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
                ipString = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
            	ipString = request.getHeader("X-Real-IP");
            }
            if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
                ipString = request.getRemoteAddr();
            }
            // 多个路由时，取第一个非unknown的ip
            final String[] arr = ipString.split(",");
            for (final String str : arr) {
                if (!"unknown".equalsIgnoreCase(str)) {
                    ipString = str;
                    break;
                }
            }
            return ipString;
    	}catch(Exception e){
    		return null;
    	}
    }

    /**
     * write specfield bytes to a byte array start from offset
     *
     * @param    b
     * @param    offset
     * @param    v
     * @param    bytes
    */
    public static void write( byte[] b, int offset, long v, int bytes) {
        for ( int i = 0; i < bytes; i++ ) {
            b[offset++] = (byte)((v >>> (8 * i)) & 0xFF);
        }
    }

    /**
     * write a int to a byte array
     *
     * @param b
     * @param offset
     * @param v
    */
    public static void writeIntLong( byte[] b, int offset, long v ) {
        b[offset++] = (byte)((v >>  0) & 0xFF);
        b[offset++] = (byte)((v >>  8) & 0xFF);
        b[offset++] = (byte)((v >> 16) & 0xFF);
        b[offset  ] = (byte)((v >> 24) & 0xFF);
    }

    /**
     * get a int from a byte array start from the specifiled offset
     *
     * @param    b
     * @param    offset
    */
    public static long getIntLong( byte[] b, int offset ) {
        return (
            ((b[offset++] & 0x000000FFL)) |
            ((b[offset++] <<  8) & 0x0000FF00L) |
            ((b[offset++] << 16) & 0x00FF0000L) |
            ((b[offset  ] << 24) & 0xFF000000L)
        );
    }

    /**
     * get a int from a byte array start from the specifield offset
     *
     * @param    b
     * @param    offset
    */
    public static int getInt3( byte[] b, int offset ) {
        return (
            (b[offset++] & 0x000000FF) |
            (b[offset++] & 0x0000FF00) |
            (b[offset  ] & 0x00FF0000)
        );
    }

    public static int getInt2( byte[] b, int offset ) {
        return (
            (b[offset++] & 0x000000FF) |
            (b[offset  ] & 0x0000FF00)
        );
    }

    public static int getInt1( byte[] b, int offset ) {
        return (
            (b[offset] & 0x000000FF)
        );
    }

    /**
     * string ip to long ip
     *
     * @param    ip
     * @return    long
    */
    public static long ip2long( String ip ) {
        String[] p = ip.split("\\.");
        if ( p.length != 4 ) return 0;

        int p1 = ((Integer.valueOf(p[0]) << 24) & 0xFF000000);
        int p2 = ((Integer.valueOf(p[1]) << 16) & 0x00FF0000);
        int p3 = ((Integer.valueOf(p[2]) <<  8) & 0x0000FF00);
        int p4 = ((Integer.valueOf(p[3]) <<  0) & 0x000000FF);

        return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
    }

    /**
     * int to ip string
     *
     * @param    ip
     * @return    string
    */
    public static String long2ip( long ip ) {
        StringBuilder sb = new StringBuilder();

        sb
        .append((ip >> 24) & 0xFF).append('.')
        .append((ip >> 16) & 0xFF).append('.')
        .append((ip >>  8) & 0xFF).append('.')
        .append((ip >>  0) & 0xFF);

        return sb.toString();
    }

    /**
     * check the validate of the specifeld ip address
     *
     * @param    ip
     * @return    boolean
    */
    public static boolean isIpAddress( String ip ) {
        String[] p = ip.split("\\.");
        if ( p.length != 4 ) return false;

        for ( String pp : p ) {
            if ( pp.length() > 3 ) return false;
            int val = Integer.valueOf(pp);
            if ( val > 255 ) return false;
        }

        return true;
    }

    public static String execHostCmd(String ip) throws Exception {
        return execCmd("host "+ip, null);
    }

    
    public static String isSpider(String ip) throws Exception {
        String result = execCmd("host "+ip, null);
        if(StringUtils.isNotBlank(ip)&&!isSpiderUa(result)){
            for (String s : qihooSpider) {
                if(ip.startsWith(s)){
                    return "so.com";
                }
            }
            for (String s : YisouSpider) {
                if(ip.startsWith(s)){
                    return "sm.cn";
                }
            }
            for (String s : ByteSpider) {
                if(ip.startsWith(s)){
                    return "bytedance.com";
                }
            }
        }
        return result;
    }
    
    /**
     * 执行系统命令, 返回执行结果
     *
     * @param cmd 需要执行的命令
     * @param dir 执行命令的子进程的工作目录, null 表示和当前主进程工作目录相同
     */
    private static String execCmd(String cmd, File dir) throws Exception {
        StringBuilder result = new StringBuilder();

        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;

        try {
            // 执行命令, 返回一个子进程对象（命令在子进程中执行）
            process = Runtime.getRuntime().exec(cmd, null, dir);

            // 方法阻塞, 等待命令执行完成（成功会返回0）
            process.waitFor();

            // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
            bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));

            // 读取输出
            String line = null;
            while ((line = bufrIn.readLine()) != null) {
                result.append(line).append('n');
            }
            while ((line = bufrError.readLine()) != null) {
                result.append(line).append('n');
            }

        } finally {
            closeStream(bufrIn);
            closeStream(bufrError);

            // 销毁子进程
            if (process != null) {
                process.destroy();
            }
        }

        // 返回执行结果
        return result.toString();
    }
    
    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (Exception e) {
                // nothing
            }
        }
    }
    
    private static boolean isSpiderUa(String hostname){
        List<String> spiders = BizConstant.SPIDER;
        for (String spider : spiders) {
            if (hostname.toLowerCase().contains(spider)){
                return true;
            }
        }
        return false;
    }
}
