package com.bg7yoz.ft8cn.flex;
/**
 * 简单封装的Tcp类，用于Flex的命令操作
 * @author BGY70Z
 * @date 2023-03-20
 */

import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RadioTcpClient {
    private static final String TAG = "RadioTcpClient";
    private static RadioTcpClient radioTcpClient = null;
    private String ip;
    private int port;
    public static final int MAX_BUFFER_SIZE=1024 * 64;

    private final ExecutorService sendByteThreadPool = Executors.newCachedThreadPool();
    private final SendByteRunnable sendByteRunnable=new SendByteRunnable(this);

    public static RadioTcpClient getInstance() {
        if (radioTcpClient == null) {
            synchronized (RadioTcpClient.class) {
                radioTcpClient = new RadioTcpClient();
            }
        }
        return radioTcpClient;
    }

    private Socket mSocket;
    private OutputStream mOutputStream;
    private InputStream mInputStream;

    private SocketThread mSocketThread;
    private boolean isStop = false;//thread flag

    private OnDataReceiveListener onDataReceiveListener = null;

    public boolean isConnect() {
        boolean flag = false;
        if (mSocket != null) {
            flag = mSocket.isConnected();
        }
        return flag;
    }

    public void connect(String ip, int port) {
        this.ip = ip;
        this.port = port;
        //mSocketThread = new SocketThread(ip, port);
        mSocketThread = new SocketThread();
        mSocketThread.start();
    }

    public void disconnect() {
        isStop = true;
        try {
            if (mOutputStream != null) {
                mOutputStream.close();
            }

            if (mInputStream != null) {
                mInputStream.close();
            }

            if (mSocket != null) {
                mSocket.close();
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (mSocketThread != null) {
            mSocketThread.interrupt();//not intime destory thread,so need a flag
        }
    }


    private class SocketThread extends Thread {
        @Override
        public void run() {
            Log.d(TAG, "TcpSocketThread start...");
            super.run();
            try {
                if (mSocket != null) {
                    mSocket.close();
                    mSocket = null;
                }
                InetAddress ipAddress = InetAddress.getByName(ip);
                mSocket = new Socket(ipAddress, port);
                //设置不延时发送
                //mSocket.setTcpNoDelay(true);
                //设置输入输出缓冲流大小
                //mSocket.setSendBufferSize(8*1024);
                //mSocket.setReceiveBufferSize(8*1024);
                if (isConnect()) {
                    mOutputStream = mSocket.getOutputStream();
                    mInputStream = mSocket.getInputStream();


                    isStop = false;
                    connectSuccess();
                }
                /* 此处这样做没什么意义不大，真正的socket未连接还是靠心跳发送，等待服务端回应比较好，一段时间内未回应，则socket未连接成功 */
                else {
                    connectFail();
                    return;
                }

            } catch (IOException e) {

                connectFail();
                Log.e(TAG, "SocketThread connect io exception = " + e.getMessage());
                e.printStackTrace();
                return;
            }

            //read ...
            while (isConnect() && !isStop && !isInterrupted()) {
                int size;
                try {
                    byte[] buffer = new byte[MAX_BUFFER_SIZE];
                    if (mInputStream == null) return;
                    size = mInputStream.read(buffer);//null data -1 , zrd serial rule size default 10
                    if (size > 0) {
                        if (onDataReceiveListener != null) {
                            byte[] temp = Arrays.copyOf(buffer, size);
                            onDataReceiveListener.onDataReceive(temp);
                        }
                    }
                } catch (IOException e) {
                    //uiHandler.sendEmptyMessage(-1);
                    Log.e(TAG, "SocketThread read io exception = " + e.getMessage());
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    private void connectFail() {
        if (onDataReceiveListener != null) {
            onDataReceiveListener.onConnectFail();
        }
    }

    private void connectSuccess() {
        if (onDataReceiveListener != null) {
            onDataReceiveListener.onConnectSuccess();
        }
    }

    /**
     * send byte[] cmd
     * Exception : android.os.NetworkOnMainThreadException
     */
    public synchronized void sendByte(final byte[] mBuffer) {
        sendByteRunnable.mBuffer=mBuffer;
        sendByteThreadPool.execute(sendByteRunnable);
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    if (mOutputStream != null) {
//                        mOutputStream.write(mBuffer);
//                        mOutputStream.flush();
//                    }
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();
    }

    private static class SendByteRunnable implements Runnable{
        RadioTcpClient client;
        byte[] mBuffer;
        public SendByteRunnable(RadioTcpClient client) {
            this.client = client;
        }

        @Override
        public void run() {
            try {
                if (mBuffer==null) return;
                if (client.mOutputStream != null) {
                    client.mOutputStream.write(mBuffer);
                    client.mOutputStream.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public interface OnDataReceiveListener {
        void onConnectSuccess();

        void onConnectFail();

        void onDataReceive(byte[] buffer);
    }

    public void setOnDataReceiveListener(
            OnDataReceiveListener dataReceiveListener) {
        onDataReceiveListener = dataReceiveListener;
    }

    public String getIp() {
        return ip;
    }

    public int getPort() {
        return port;
    }
}
