package com.bonait.bnframework.common.helper;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

import com.bonait.bnframework.common.constant.ConfigName;
import com.bonait.bnframework.common.helper.I.IMessage;
import com.bonait.bnframework.common.helper.I.IRun;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

/**
 * mqtt帮助类
 */
public class MQTT {
    //region 单例模式
    private static volatile MQTT instance = null;

    public static MQTT get() {
        MQTT manager = instance;
        if (manager == null) {
            synchronized (MQTT.class) {
                manager = instance;
                if (manager == null) {
                    manager = new MQTT();
                    instance = manager;
                }
            }
        }
        return manager;
    }

    private MQTT() {
       // Connect("emqx_u_block","emqx_p_admin8765490789","10.2.1.21",1883);
    }
    //endregion

    //region 变量
    private String string_IMEI_ID = "奶茶机"+java.util.UUID.randomUUID().toString();
    private String host = "tcp://broker.emqx.io:1883";
    private String userName = "emqx_u_block";
    private String passWord = "emqx_p_admin8765490789";
    private MqttClient mqttClient;//客户端
    private MqttConnectOptions options;//配置  保存控制客户端连接到服务器的方式的选项集。
    public IMessage callback=null;//消息回调
    public IRun ConnectOk=null;
    public IRun Disconnect=null;
    public boolean IsConnect=false;
    //endregion

    //region 公有函数

    /**
     * 初始化配置Mqtt
     * @param name
     * @param Pass
     * @param Ip
     * @param post
     */
    public void Connect(String name, String Pass, final String Ip, int post) {
        try {
            userName=name;
            passWord=Pass;
            host="tcp://"+ Ip+":"+post;
            //(1)主机地址(2)客户端ID,一般以客户端唯一标识符(不能够和其它客户端重名)(3)最后一个参数是指数据保存在内存(具体保存什么数据,以后再说,其实现在我也不是很确定)
            mqttClient = new MqttClient(host, string_IMEI_ID, new MemoryPersistence());
        } catch (MqttException e) {
            e.printStackTrace();
        }
        options = new MqttConnectOptions();//MQTT的连接设置
        options.setCleanSession(true);//设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
        options.setUserName(userName);//设置连接的用户名(自己的服务器没有设置用户名)
        options.setPassword(passWord.toCharArray());//设置连接的密码(自己的服务器没有设置密码)
        mqttClient.setCallback(new MqttCallback() {
            @Override//连接丢失后，会执行这里
            public void connectionLost(Throwable throwable) {
                IsConnect=false;
                MessageLog.ShowInfo("mqtt断开连接,尝试重新连接...");
                if(Disconnect!=null)
                {
                    Disconnect.Run();
                }
                Reconnect();
            }
            @Override//获取的消息会执行这里--arg0是主题,arg1是消息
            public void messageArrived(final String ssr, MqttMessage mqttMessage) throws Exception {
                final String mqtt_zhuti = ssr;//主题
                final String mqtt_message = mqttMessage.toString();//消息
                if(callback!=null)
                {
                    callback.MessageRecive(mqtt_zhuti,mqtt_message);
                }
            }
            @Override//订阅主题后会执行到这里
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    boolean status = false;
                    while (!status) {
                        try {
                            //status为0则代表通，为1则代表不通。
                            status =ping2(Ip,1,1);
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            MessageLog.ShowInfo("MQTT " + Ip + " 网络验证失败");
                        } catch (Exception e) {
                            MessageLog.ShowInfo("MQTT " + Ip+ " 网络验证失败");
                        }
                    }
                    ConnMqttBroken(true);
                } catch (Exception e) {

                }
            }
        }).start();

    }
    /**
     * Ping PLC地址是否通畅
     * @param address
     * @param pingTimes  ping的次数
     * @param timeOut  超时时间 10
     * @return
     */
    public static boolean ping2(String address, int pingTimes, int timeOut) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec( "ping "  + "-c " + pingTimes + " -w " + timeOut+ " "+address);
            InputStreamReader r = new InputStreamReader(process.getInputStream());

            LineNumberReader returnData = new LineNumberReader(r);

            String returnMsg="";

            String line = "";

            while ((line = returnData.readLine()) != null) {

                System.out.println(line);

                returnMsg += line;

            }

            if(returnMsg.indexOf("100% packet loss")!=-1){
                System.out.println("与 " +address +" 连接不畅通.");
                return  false;
            } else{

                System.out.println("与 " +address +" 连接畅通.");
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;

    }
    /**
     * 连接 或者断开MQTT
     * @param bloConn
     */
    public void ConnMqttBroken(final boolean bloConn)
    {
        // 必须开启新的线程执行
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (bloConn) {
                    try {
                        if (mqttClient.isConnected() == false) {
                            mqttClient.connect(options);//连接服务器,连接不上会阻塞在这
                        }
                        MessageLog.ShowInfo("mqtt连接成功!");
                        IsConnect=true;
                        if(ConnectOk!=null)
                        {
                            ConnectOk.Run();
                        }
                    } catch (MqttException e) {
                        Log.i("MQTT", "mqtt重连接失败!"+e.getMessage());
                    }
                } else {
                    try {
                        if (mqttClient!=null && mqttClient.isConnected()) {
                            mqttClient.disconnect();
                        }
                        IsConnect=false;
                        MessageLog.ShowInfo("mqtt断开成功!");
                    } catch (MqttException e) {
                        MessageLog.ShowError("mqtt断开失败!"+e.getMessage());
                    }
                }
            }
        }).start();
    }

    /**
     * 订阅主题
     * @param topic
     */
    public void Subscrib(String[] topic)
    {
        if (mqttClient == null || !mqttClient.isConnected())
        {
            return;
        }
        try
        {
            for (String str:topic)
            {
                MessageLog.ShowInfo("mqtt订阅主题:"+str);
                Log.v("IotMqttService：topic="+str, "订阅topic："+str);
                mqttClient.subscribe(str,2);
            }
        }
        catch(MqttException e)
        {
            MessageLog.ShowError("mqtt订阅主题失败!"+topic);
        }
    }

    /**
     * 发布 （向服务器发送消息）
     * @param topic
     * @param message
     */
    public void publish(String topic, String message) {
        Integer qos = 2;
        Boolean retained = false;
        try {
            if(mqttClient.isConnected())
            {
                //Log.v("IotMqttService：topic="+topic, "Mqtt发送消息："+message);
                //参数分别为：主题、消息的字节数组、服务质量、是否在服务器保留断开连接后的最后一条消息
                mqttClient.publish(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断网络是否连接
     */
    private boolean isConnectIsNomarl() {
        ConnectivityManager connectivityManager = (ConnectivityManager) ConfigName.getInstance().dishesCon.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()) {
            String name = info.getTypeName();
            Log.i("网络", "当前网络名称：" + name);
            return true;
        } else {
            Log.i("网络", "没有可用网络");
            /*没有可用网络的时候，延迟3秒再尝试重连*/
//            new Handler().postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    ConnMqttBroken(true);
//                }
//            }, 3000);
            return false;
        }
    }

    /**
     * 重新连接
     */
    private void Reconnect()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    if (isConnectIsNomarl())
                    {
                        while (!isConnectIsNomarl())
                        {
                            try {
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {

                            }
                        }
                    }
                } catch (InterruptedException e) {

                }


                boolean flag = false;
                while (!mqttClient.isConnected())
                {
                    try
                    {
                        Log.i("MQTT", "mqtt重连中！");
                        ConnMqttBroken(true);
                        Thread.sleep(3000);
                    }
                    catch (Exception ex)
                    {
                        if (!flag)
                        {
                            flag = true;
                        }
                    }
                }
            }
        }).start();
    }
    //endregion
}
