package com.mogo.telematic.discovery;


import android.util.Log;

import com.mogo.telematic.discovery.bean.HostBean;
import com.mogo.telematic.discovery.bean.NetInfo;

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

/**
 * 搜索司机端
 *
 * @author mogoauto
 */
public class DiscoveryDriverTask extends AbstractDiscoveryTask {

    private final String TAG = "DiscoveryDriverTask";
    private final static int[] DPORTS = {1088};
    private final static int TIMEOUT_SCAN = 3600; // seconds
    private final static int TIMEOUT_CONNECT = 800; // seconds
    private final static int TIMEOUT_SHUTDOWN = 10; // seconds
    private final static int THREADS = 10; //FIXME: Test, plz set in options again ?
    private int pt_move = 2; // 1=backward 2=forward
    private ExecutorService mPool;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

    }

    @Override
    protected Void doInBackground(Void... params) {
        Log.v(TAG, "start=" + NetInfo.getIpFromLongUnsigned(start) + " (" + start + "), end=" + NetInfo.getIpFromLongUnsigned(end) + " (" + end + "), length=" + size);
        mPool = Executors.newFixedThreadPool(THREADS);
        if (ip <= end && ip >= start) {
            Log.i(TAG, "Back and forth scanning");
            // gateway
            launch(start);

            // hosts
            long pt_backward = ip;
            long pt_forward = ip + 1;
            long size_hosts = size - 1;//主机在扫描范围内，扫描数量-1

            for (int i = 0; i < size_hosts; i++) {
                if (isCancelled()) {
                    break;
                }
                Log.d(TAG, "doInBackground: "
                        + "  ip=" + NetInfo.getIpFromLongUnsigned(ip)
                        + "  start=" + NetInfo.getIpFromLongUnsigned(start)
                        + "  end=" + NetInfo.getIpFromLongUnsigned(end)
                        + "  pt_backward=" + NetInfo.getIpFromLongUnsigned(pt_backward)
                        + "  pt_forward=" + NetInfo.getIpFromLongUnsigned(pt_forward)
                        + "  size_hosts" + size_hosts
                );
                // Set pointer if of limits
                if (pt_backward <= start) {
                    pt_move = 2;
                } else if (pt_forward > end) {
                    pt_move = 1;
                }
                // Move back and forth
                if (pt_move == 1) {
                    launch(pt_backward);
                    pt_backward--;
                    pt_move = 2;
                } else if (pt_move == 2) {
                    launch(pt_forward);
                    pt_forward++;
                    pt_move = 1;
                }
            }
        } else {
            Log.i(TAG, "Sequencial scanning");
            for (long i = start; i <= end; i++) {
                if (isCancelled()) {
                    break;
                }
                launch(i);
            }
        }
        mPool.shutdown();
        try {
            if (!mPool.awaitTermination(TIMEOUT_SCAN, TimeUnit.SECONDS)) {
                mPool.shutdownNow();
                Log.e(TAG, "Shutting down pool");
                if (!mPool.awaitTermination(TIMEOUT_SHUTDOWN, TimeUnit.SECONDS)) {
                    Log.e(TAG, "Pool did not terminate");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            mPool.shutdownNow();
            Thread.currentThread().interrupt();
        }
        Log.d(TAG, "doInBackground: return null");
        return null;
    }

    @Override
    protected void onCancelled() {
        if (mPool != null) {
            synchronized (mPool) {
                mPool.shutdownNow();
                Log.d(TAG, "onCancelled: 停止线程");
            }
        }
        super.onCancelled();
    }

    private void launch(long i) {
        if (!mPool.isShutdown() && !isCancelled()) {
            try {
                mPool.execute(new CheckRunnable(NetInfo.getIpFromLongUnsigned(i)));
            } catch (Exception e) {
                Log.e(TAG, "线程池异常为：" + e.getMessage());
            }
        }
    }


    /**
     * 扫描测试线程
     */
    private class CheckRunnable implements Runnable {
        private String addr;

        CheckRunnable(String addr) {
            this.addr = addr;
        }

        @Override
        public void run() {
            if (isCancelled()) {
                publish(null);
                return;
            }
            Log.e(TAG, "run=" + addr + "   isCancelled()=" + isCancelled());
            // Create host object
            final HostBean host = new HostBean();
            host.responseTime = TIMEOUT_CONNECT;
            host.ipAddress = addr;
            Socket s = new Socket();
            for (int dport : DPORTS) {
                try {
                    s.bind(null);
                    s.connect(new InetSocketAddress(addr, dport), TIMEOUT_CONNECT);
                    Log.i(TAG, "found using TCP connect " + addr + " on port=" + dport);
                    publish(host);
                } catch (IOException | IllegalArgumentException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        s.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void publish(final HostBean host) {
        hosts_done++;
        if (host == null) {
            publishProgress((HostBean) null);
            return;
        }
        publishProgress(host);
    }
}
