/*
 * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
 */
package kr.co.zumo.app.lifeplus.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
import kr.co.zumo.app.lifeplus.util.StringUtil;

/**
 * InternetStatus
 * <pre>
 * </pre>
 *
 * @author 민효동
 * @version 1.0
 * @history 민효동   [2018. 9. 19.]   [최초 작성]
 * @since 2018. 9. 19.
 */
public class InternetStatus {
  public static final String PING_HOST = "www.google.com";
  public static final int PING_PORT = 80;
  public static final int PING_INTERVAL_MS = 5000;
  public static final int PING_TIMEOUT_MS = 2000;

  /**
   * 일정 시간 간격으로 인터넷 연결을 확인한다.
   * - 연결의 변화가 있는 경우에만 publish 하는 Observable 을 반환한다.
   *
   * @return Observable with Boolean
   */
  public static Observable<Boolean> observe() {
    return observe(PING_HOST, PING_PORT, PING_INTERVAL_MS, PING_TIMEOUT_MS);
  }

  /**
   * 일정 시간 간격으로 인터넷 연결을 확인한다.
   * - 연결의 변화가 있는 경우에만 publish 하는 Observable 을 반환한다.
   *
   * @param host       연결 호스트
   * @param port       포트
   * @param intervalMs 갱신 주기 ms
   * @param timeoutMs  타임아웃 실행 ms
   * @return Observable with Boolean
   */
  public static Observable<Boolean> observe(final String host, final int port, final int intervalMs, final int timeoutMs) {
    return Observable.interval(0, intervalMs, TimeUnit.MILLISECONDS, Schedulers.io())
      .map(tick -> isConnected(new Socket(), StringUtil.removeProtocol(host), port, timeoutMs)).distinctUntilChanged();
  }

  /**
   * 인터넷 연결을 1회 체크한다.
   *
   * @return Single with Boolean
   */
  public static Single<Boolean> check() {
    return check(PING_HOST, PING_PORT);
  }

  /**
   * 인터넷 연결을 1회 체크한다.
   *
   * @param host 연결 호스트
   * @param port 포트
   * @return
   */
  public static Single<Boolean> check(final String host, final int port) {
    return Single.fromCallable(() -> isConnected(new Socket(), StringUtil.removeProtocol(host), port, PING_TIMEOUT_MS));
  }

  static boolean isConnected(final Socket socket, final String host, final int port, final int timeoutInMs) {
//    Log.i("APP# InternetStatus | isConnected", "|" + host + ":" + port);
    boolean isConnected;
    try {
      socket.connect(new InetSocketAddress(host, port), timeoutInMs);
      isConnected = socket.isConnected();
    } catch (IOException e) {
      isConnected = Boolean.FALSE;
    } finally {
      try { socket.close();   // 줄바꿈을 하면 Test Coverage 미스가 생겨 이대로 둠
      } catch (IOException exception) {
        exception.printStackTrace();
      }
    }
    return isConnected;
  }
}
