package org.nl.acs.opc;

import cn.hutool.core.util.StrUtil;
import org.jinterop.dcom.common.JIException;
import org.nl.acs.auto.initial.ApplicationAutoInitial;
import org.nl.acs.device_driver.driver.ItemValue;
import org.nl.acs.opc.service.dto.OpcServerManageDto;
import org.openscada.opc.lib.common.NotConnectedException;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.UnknownGroupException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author ldjun
 * @version 1.0
 * @date 2023年02月01日 11:27
 * @desc desc
 */
@Service
public class OpcServerServiceImpl implements OpcServerService, ApplicationAutoInitial {

    private static final Logger log = LoggerFactory.getLogger(OpcServerServiceImpl.class);
    @Autowired
    OpcServerManageService opcServerManageService;
    Map<String, OpcServerManageDto> opcServerManageDtos = new HashMap();
    Map<String, Server> servers = Collections.synchronizedMap(new HashMap());
    Map<String, Group> groups = Collections.synchronizedMap(new HashMap());

    public OpcServerServiceImpl() {
    }

    /**
     * 加载opc服务，启动opc线程
     *
     * @throws Exception
     */
    @Override
    public void autoInitial() throws Exception {
        this.reload(); // 加载opc服务
        if (OpcConfig.auto_start_opc) {
            Thread t =
                    new Thread(() -> {
                        Iterator var1 = OpcServerServiceImpl.this.opcServerManageDtos.values().iterator();

                        while (var1.hasNext()) {
                            OpcServerManageDto dto = (OpcServerManageDto) var1.next();

                            try {
                                OpcServerServiceImpl.this.getServer(dto.getOpc_code());
                                OpcServerServiceImpl.log.info("加载opc server {}", dto.getOpc_code());
                            } catch (Exception var4) {
                                OpcServerServiceImpl.log.warn("启动无法载入servers", var4);
                            }
                        }
                    });
            t.start();
        }
    }

    @Override
    public synchronized void reload() {
        this.opcServerManageDtos = this.opcServerManageService.queryAllServerMap();
        this.opcServerManageDtos = Collections.synchronizedMap(this.opcServerManageDtos);
    }

    @Override
    public synchronized Group getServer(String code) {
        synchronized (this.buildLock(code)) {
            Group group = null;
            group = (Group) this.groups.get(code);
            if (group != null) {
                label68:
                {
                    Group var10000;
                    try {
                        if (!group.isActive()) {
                            break label68;
                        }

                        var10000 = group;
                    } catch (JIException var14) {
                        log.error(code, var14);
                        break label68;
                    }

                    return var10000;
                }
            }

            Server server = (Server) this.servers.get(code);
            boolean needcreate = false;
            String groupName = code;
            if (server == null) {
                needcreate = true;
            } else {
                try {
                    group = server.findGroup(groupName);
                } catch (UnknownHostException | JIException | UnknownGroupException | NotConnectedException |
                         IllegalArgumentException var13) {
                    log.error(code, var13);
                    needcreate = true;
                }
            }

            if (needcreate) {
                OpcServerManageDto dto = (OpcServerManageDto) this.opcServerManageDtos.get(code);
                if (dto == null) {
                    throw new RuntimeException(code + "不存在");
                }

//        if (server!=null){
//          server.disconnect();
//          server=null;
//        }

                if (server == null) {
                    server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain()));
                }

                try {
                    group = server.addGroup(groupName);
                } catch (Exception var12) {
                    this.clearServer(code);
                    ThreadUtl.sleep(5000L);
                    log.warn("获取opc出错重新获取", code, var12);
                    server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain()));
                    try {
                        group = server.addGroup(groupName);
                    } catch (Exception var11) {
                        throw new RuntimeException(var12);
                    }
                }

                this.servers.put(code, server);
                this.groups.put(code, group);
            }

            return group;
        }
    }

    @Override
    public Group getServerByNewConn(String code) {
        synchronized (this.buildLock(code)) {

            Server server = (Server) this.servers.get(code);
            if (server != null) {
                this.clearServer(code);
            }

            OpcServerManageDto dto = (OpcServerManageDto) this.opcServerManageDtos.get(code);
            if (dto == null) {
                throw new RuntimeException(code + "不存在");
            }

//        if (server == null) {
            server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain()));
//        }
            String groupName = code;
            Group group = null;

            try {
                group = server.addGroup(groupName);
            } catch (Exception var12) {
                this.clearServer(code);
                ThreadUtl.sleep(2000L);
                log.warn("获取opc出错重新获取", code, var12);
                server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain()));
                try {
                    group = server.addGroup(groupName);
                } catch (Exception var11) {
                    throw new RuntimeException(var12);
                }
            }

            this.servers.put(code, server);
            this.groups.put(code, group);
            return group;
        }
    }

    @Override
    public synchronized void clearServer(String code) {
        try {
            Server server = (Server) this.servers.get(code);
            if (server != null) {
                server.disconnect();
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("清理server异常,", e.getMessage());
        }

        this.servers.remove(code);
        this.groups.remove(code);
    }

    public void cleanGroups(String opcCode) {
        Group group = (Group)this.groups.get(opcCode);
        if (group != null) {
            Server server = group.getServer();

            try {
                group.remove();
            } catch (JIException var5) {
                var5.printStackTrace();
            }

            this.groups.remove(opcCode);
            server.disconnect();
            this.servers.remove(opcCode);
        }

    }

    @Override
    public void writeInteger(String code, ItemValue... values) {
        try {
            Group group = this.getServer(code);
            OpcUtl.writeValue(group, values);
        } catch (Exception var4) {
            this.clearServer(code);
            log.warn("写入出错opc server {} 重新加载", code, var4);
            ThreadUtl.sleep(5000L);
            throw var4;
        }
    }

    @Override
    public void writeIntegerByNewConn(String code, ItemValue... values) {
        try {
            Group group = this.getServerByNewConn(code);
            OpcUtl.writeValue(group, values);
        } catch (Exception var4) {
            this.clearServer(code);
            log.info("写入出错opc server {} 重新加载", code, var4);
            ThreadUtl.sleep(1000L);
            throw var4;
        }
    }

    private String buildLock(String key) {
        if (StrUtil.isEmpty(key)) {
            key = "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("OpcServerService.");
        builder.append(key);
        String lock = builder.toString().intern();
        return lock;
    }
}
