package com.netease.LDNetDiagnoService;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.List;

import android.util.Log;

public class LDNetSocket {
  private static final int PORT = 80;
  private static final int CONN_TIMES = 4;
  private static final String TIMEOUT = "DNS解析正常,连接超时,TCP建立失败";
  private static final String IOERR = "DNS解析正常,IO异常,TCP建立失败";
  private static final String HOSTERR = "DNS解析失败,主机地址不可达";
  private static LDNetSocket instance=null;
  private LDNetSocketListener listener;
  private int timeOut = 6000;// 设置每次连接的timeout时间
  public InetAddress[] _remoteInet;
  public List<String> _remoteIpList;
  private boolean[] isConnnected;
  private final long[] RttTimes = new long[CONN_TIMES];// 用于存储三次测试中每次的RTT值

  public boolean isCConn = true;
  
  private LDNetSocket() {
  
  }
  public static LDNetSocket getInstance(){
	  if(instance==null){
		  instance=new LDNetSocket();
	  }
	  return instance;
  }
  
  public void initListener(LDNetSocketListener listener){
	  this.listener=listener;
  }

  /**
   * 通过connect函数测试TCP的RTT时延
   */
  public boolean exec(String host) {
    if (isCConn && loaded) {
    	try{
    		startJNITelnet(host, "80"); //默认80端口
    		return true;
    	}catch(UnsatisfiedLinkError e){
    		e.printStackTrace();
    		Log.i("LDNetSocket", "call jni failed, call execUseJava");
    		return execUseJava(host);
    	}	
    } else {
      return execUseJava(host);
    }
  }

  /**
   * 使用java执行connected
   */
  private boolean execUseJava(String host) {
    if (_remoteInet != null && _remoteIpList != null) {
      int len = _remoteInet.length;
      isConnnected = new boolean[len];
      for (int i = 0; i < len; i++) {
        if (i != 0) {
          this.listener.OnNetSocketUpdated("\n");
        }
        isConnnected[i] = execIP(_remoteInet[i], _remoteIpList.get(i));
      }
      for (Boolean i : isConnnected) {
        if (i == true) {// 一个连接成功即认为成功
          this.listener.OnNetSocketFinished("\n");
          return true;
        }
      }

    } else {
      this.listener.OnNetSocketFinished(HOSTERR);
    }
    this.listener.OnNetSocketFinished("\n");
    return false;
  }

  /**
   * 返回某个IP进行5次connect的最终结果
   */
  private boolean execIP(InetAddress inetAddress, String ip) {
    boolean isConnected = true;
    StringBuilder log = new StringBuilder();
    InetSocketAddress socketAddress = null;
    if (inetAddress != null && ip != null) {
      socketAddress = new InetSocketAddress(inetAddress, PORT);
      int flag = 0;
      this.listener.OnNetSocketUpdated("Connect to host: " + ip + "..." + "\n");
      for (int i = 0; i < CONN_TIMES; i++) {
        execSocket(socketAddress, timeOut, i);
        if (RttTimes[i] == -1) {// 一旦发生timeOut,则尝试加长连接时间
          this.listener.OnNetSocketUpdated((i + 1) + "'s time=" + "TimeOut"
              + ",  ");
          timeOut += 4000;
          if (i > 0 && RttTimes[i - 1] == -1) {// 连续两次连接超时,停止后续测试
            flag = -1;
            break;
          }
        } else if (RttTimes[i] == -2) {
          this.listener
              .OnNetSocketUpdated((i + 1) + "'s time=" + "IOException");
          if (i > 0 && RttTimes[i - 1] == -2) {// 连续两次出现IO异常,停止后续测试
            flag = -2;
            break;
          }
        } else {
          this.listener.OnNetSocketUpdated((i + 1) + "'s time=" + RttTimes[i]
              + "ms,  ");
        }
      }
      long time = 0;
      int count = 0;
      if (flag == -1) {
        // log.append(TIMEOUT);
        isConnected = false;
      } else if (flag == -2) {
        // log.append(IOERR);
        isConnected = false;
      } else {
        for (int i = 0; i < CONN_TIMES; i++) {
          if (RttTimes[i] > 0) {
            time += RttTimes[i];
            count++;
          }
        }
        if (count > 0) {
          time = time / count;
          log.append("average=" + time + "ms");
        }
      }
    } else {
      isConnected = false;
    }
    this.listener.OnNetSocketUpdated(log.toString());
    return isConnected;
  }

  /**
   * 针对某个IP第index次connect
   */
  private void execSocket(InetSocketAddress socketAddress, int timeOut,
      int index) {
    Socket socket = null;
    long start = 0;
    long end = 0;
    try {
      socket = new Socket();
      start = System.currentTimeMillis();
      socket.connect(socketAddress, timeOut);
      end = System.currentTimeMillis();
      RttTimes[index] = end - start;
    } catch (SocketTimeoutException e) {
      RttTimes[index] = -1;// 作为TIMEOUT标识
      e.printStackTrace();
    } catch (IOException e) {
      RttTimes[index] = -2;// 作为IO异常标识
      e.printStackTrace();
    } finally {
      if (socket != null) {
        try {
          socket.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public void resetInstance() {
    if (instance != null) {
      instance = null;
    }
  }

  /*
   * 调用jni中native方法
   */
  public native void startJNITelnet(String host, String port);

  static boolean loaded;
  static {
    try {
      System.loadLibrary("tracepath");
      loaded = true;
    } catch (UnsatisfiedLinkError e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  public void printSocketInfo(String log){
	  listener.OnNetSocketUpdated(log);
  }
  
  public interface LDNetSocketListener {
    public void OnNetSocketFinished(String log);

    public void OnNetSocketUpdated(String log);
  }

}
