package com.ntels.onecable.common.mdns;

import com.ntels.onecable.common.Constants;
import com.ntels.onecable.common.util.LogUtil;
import com.ntels.onecable.common.util.Util;
import com.ntels.onecable.common.websocket.AsyncTaskCancelTimerTask;

import android.os.AsyncTask;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;

/**
 * <pre>
 * 1. ClassName :   MdnsDiscovery
 * 2. FileName  :   MdnsDiscovery.java
 * 3. Package   :   com.ntels.onecable.common.mdns
 * 4. Date      :   2016-12-06
 * 5. Author    :   aaron
 * 6. Comment   :   Initialize
 * </pre>
 */
public class MdnsDiscovery {
    private static final String TAG = MdnsDiscovery.class.getSimpleName();

    private static final String SERVICE_TYPE = "_ntelshub._tcp.local.";
    private InetAddress deviceIpAddress;
    private JmDNS mJmDNS;
    private ServiceListener serviceListener;
    private onDiscoveryListener discoveryListener;

    /**
     * 생성자.
     *
     * @param listener MDNS discovery listener
     */
    public MdnsDiscovery(onDiscoveryListener listener) {
        this.discoveryListener = listener;
    }

    /**
     * MDNS discovery task start.
     */
    public void start() {
        AsyncTask<String, Integer, Boolean> mDNSTask = new AsyncTask<String, Integer, Boolean>() {

            @Override
            protected Boolean doInBackground(String... params) {
                LogUtil.i(TAG, "doInBackground");
                startJmDNSDiscovery();
                return true;
            }

            @Override
            protected void onCancelled(Boolean aBoolean) {
                LogUtil.i(TAG, "onCancelled : " + aBoolean);
                stopJmDNSDiscovery();
            }
        };

        new AsyncTaskCancelTimerTask(mDNSTask, 10000, 1000, true).start();
        mDNSTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    /**
     * MDNS discovery task stop.
     */
    public void stop() {
        AsyncTask<String, Integer, Boolean> mDNSTask = new AsyncTask<String, Integer, Boolean>() {

            @Override
            protected Boolean doInBackground(String... params) {
                LogUtil.i(TAG, "doInBackground");
                stopJmDNSDiscovery();
                return true;
            }

            @Override
            protected void onCancelled(Boolean aBoolean) {
                LogUtil.i(TAG, "onCancelled : " + aBoolean);
            }
        };

        new AsyncTaskCancelTimerTask(mDNSTask, 10000, 1000, true).start();
        mDNSTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    /**
     * MDNS discovery start.
     */
    private void startJmDNSDiscovery() {
        try {
            deviceIpAddress = Util.getIpAddress();
            if (deviceIpAddress == null) {
                try {
                    deviceIpAddress = InetAddress.getByName("127.0.0.1");
                } catch (UnknownHostException e) {
                    return;
                }
            }
            mJmDNS = JmDNS.create(deviceIpAddress); // deviceIpAddress
            mJmDNS.addServiceListener(SERVICE_TYPE, serviceListener = new ServiceListener() {

                @SuppressWarnings("deprecation")
                @Override
                public void serviceResolved(ServiceEvent event) {

                    LogUtil.i(TAG, "serviceResolved. name : " + event.getName() +
                            " type : " + event.getType() + " hostAddress : " + event.getInfo().getHostAddress());

                    ServiceInfo info = event.getInfo();
                    LogUtil.i(TAG, "serviceInfo : " + info.toString());
                    //displayResult("serviceInfo : " + info.hasData());

                    LogUtil.i(TAG, "attributes : " + info.getQualifiedNameMap().toString());
                    LogUtil.i(TAG, "getPropertyNames : " + info.getPropertyNames());

                    HashMap<String, Object> deviceInfo = new HashMap<String, Object>();
                    deviceInfo.put(Constants.MDNS_KEY_INFO_DEVICE_NAME, event.getName());
                    deviceInfo.put(Constants.MDNS_KEY_INFO_SERVICE_TYPE, event.getType());
                    deviceInfo.put(Constants.MDNS_KEY_INFO_HOST_ADDRESS, event.getInfo().getHostAddress());

                    Enumeration<String> names = info.getPropertyNames();
                    while (names.hasMoreElements()) {
                        String name = names.nextElement();
                        LogUtil.i(TAG, "PropertyNames : " + name + ", value = " + info.getPropertyString(name));
                        deviceInfo.put(name, info.getPropertyString(name));
                    }
                    discoveryListener.onFindDevice(deviceInfo);
                }

                @SuppressWarnings("deprecation")
                @Override
                public void serviceRemoved(ServiceEvent event) {
                    LogUtil.i(TAG, "JmDNS serviceRemoved(event=" + event + ")");

                }

                @SuppressWarnings("deprecation")
                @Override
                public void serviceAdded(ServiceEvent event) {
                    LogUtil.i(TAG, "serviceAdded. name : " + event.getName() +
                            "type : " + event.getType() + "hostAddress : " + event.getInfo().getHostAddress());
                    mJmDNS.requestServiceInfo(event.getType(), event.getName(), true);
                }
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "cannot create JmDNS : " + e.getMessage());
        }
    }

    /**
     * MDNS discovery stop.
     */
    private void stopJmDNSDiscovery() {
        LogUtil.d(TAG, "stopJmDNSDiscovery");
        if (mJmDNS != null) {
            try {
                mJmDNS.removeServiceListener(SERVICE_TYPE, serviceListener);
                mJmDNS.unregisterAllServices();
                mJmDNS.close();
            } catch (Exception e) {
                LogUtil.e(TAG, "cannot close JmDNS");
            } finally {
                mJmDNS = null;
            }
        }
    }

    /**
     * MDNS discovery listener interface.
     */
    public interface onDiscoveryListener {
        public void onFindDevice(HashMap<String, Object> homehubInfo);
    }
}
