package com.xydl.cac.iec104;

import com.xydl.cac.model.StaticVariable;
import com.xydl.cac.socket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.openmuc.j60870.*;
import org.openmuc.j60870.ie.*;

import java.io.IOException;
import java.net.InetAddress;

@Slf4j
public class Iec104Client implements ConnectionEventListener {
    public String ip;
    public Integer port;
    Connection connection = null;
    ClientConnectionBuilder clientConnectionBuilder = null;
    private WebSocketServer webSocketServer;
    public boolean keep = false;
    public boolean connected = false;
    public int retry = 0;
    public int seconds = 0;
    private boolean inRetry = false;

    public Iec104Client(WebSocketServer _webSocketServer) {
        webSocketServer = _webSocketServer;
    }

    public void connect(String _ip, Integer _port) throws Exception {
        ip = _ip;
        port = _port;
        InetAddress address = InetAddress.getByName(ip);
        clientConnectionBuilder = new ClientConnectionBuilder(address)
                .setMessageFragmentTimeout(5_000)
                .setConnectionTimeout(20_000)
                .setPort(port)
                .setConnectionEventListener(this);
        connection = clientConnectionBuilder.build();
        connection.startDataTransfer();
        log.info("IEC104客户端已连接上" + ip + ":" + port);
        connected = true;
    }

    public void disconnect() {
        try {
            connected = false;
            connection.stopDataTransfer();
            connection.close();
            connection = null;
            log.info("IEC104客户端已断开" + ip + ":" + port);
        } catch (Exception ignore) {
        }
    }

    private void reconnect() throws Exception {
        if (StaticVariable.shutdown == 1) {
            return;
        }
        retry++;
        seconds = 0;
        connection = clientConnectionBuilder.build();
        connection.startDataTransfer();
        log.info("IEC104客户端断线重连成功, ip=" + ip + ", port=" + port);
        connected = true;
        retry = 0;
    }

    public void interrogation() throws Exception {
        connection.interrogation(1, CauseOfTransmission.ACTIVATION,
                new IeQualifierOfInterrogation(20));
    }

    @Override
    public void newASdu(Connection connection, ASdu aSdu) {
        if (aSdu == null)
            return;
        InformationObject[] objs = aSdu.getInformationObjects();
        if (objs != null && objs.length > 0) {
            for (InformationObject obj : objs) {
                int addr = obj.getInformationObjectAddress();
                InformationElement[][] elements = obj.getInformationElements();
            }
        }
    }

    @Override
    public void connectionClosed(Connection connection, IOException e) {
        if (keep && !inRetry) {
            inRetry = true;
            retry = 0;
            seconds = 0;
            this.disconnect();
            while (!connected && StaticVariable.shutdown == 0) {
                try {
                    Thread.sleep(1000);
                    seconds++;
                    if (retry < 10 && seconds > 60) {
                        this.reconnect();
                    } else if (seconds > 60 * 60) {
                        this.reconnect();
                    }
                } catch (Exception ignore) {
                    String err = "IEC104客户端断线重连失败" + retry + "次, ip=" + ip + ", port=" + port;
                    log.warn(err);
                    if (webSocketServer != null && retry >= 10) {
                        webSocketServer.sendMessage(err, null);
                    }
                }
            }
            inRetry = false;
        }
    }

    @Override
    public void dataTransferStateChanged(Connection connection, boolean b) {

    }

    public static void main(String[] args) {
        Iec104Client client = new Iec104Client(null);
        try {
            client.connect("192.168.1.177", 2404);
            client.interrogation();
            while (true) {
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
