package com.iailab.module.data.channel.opcda.collector;

import com.iailab.module.data.channel.opcda.entity.ChannelOPCDADeviceEntity;
import com.iailab.module.data.channel.opcda.service.ChannelOPCDADeviceService;
import com.iailab.module.data.common.enums.CommonConstant;
import com.iailab.module.data.common.enums.DataSourceType;
import com.iailab.module.data.common.utils.TagUtils;
import lombok.extern.slf4j.Slf4j;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
@Component
public class OpcDACollector {

    @Autowired
    private OpcDAUtils opcDAUtils;

    @Autowired
    private ChannelOPCDADeviceService channelOPCDADeviceService;

    private Map<String, Server> serverMap = new ConcurrentHashMap<>();
    private Map<String, Group> groupMap = new ConcurrentHashMap<>();

    private Map<String, ChannelOPCDADeviceEntity> deviceMap = new HashMap<>();

    private Server getServer(String sourceId) throws Exception {
        try {
            if (!serverMap.containsKey(sourceId)) {
                log.info("根据数据源获取opcDAServer,sourceId=" + sourceId);
                ChannelOPCDADeviceEntity OPCDADevice = channelOPCDADeviceService.info(sourceId);
                deviceMap.put(sourceId, OPCDADevice);
                Server server = opcDAUtils.createServer(OPCDADevice);
                if (server != null) {
                    serverMap.put(sourceId, server);
                }
            }
        } catch (Exception ex) {
            log.info("=========getOPCDAServer Exception============");
            log.info("ex.message+" + ex.getMessage());
            ex.printStackTrace();
            throw new Exception(ex.getMessage());
        }
        return serverMap.get(sourceId);
    }

    public Map<String, Object> getTagValues(List<String[]> tags) {
        if (CollectionUtils.isEmpty(tags)) {
            return new HashMap<>();
        }
        Map<String, Object> result = new HashMap<>(tags.size());
        // 按照sourceId分组
        Map<String, List<String[]>> sourceIdTagMap = tags.stream().collect(Collectors.groupingBy(t -> t[0]));

        for (Map.Entry<String, List<String[]>> entry : sourceIdTagMap.entrySet()) {
            try {
                Server server = this.getServer(entry.getKey());
                Group group = this.getGroup(server, entry.getKey());
                Map<Item, ItemState> read = OpcDAUtils.readA(group, entry.getValue());

                for (Map.Entry<Item, ItemState> itemStateEntry : read.entrySet()) {
                    try {
                        result.put(TagUtils.genTagId(DataSourceType.OPCDA.getCode(), deviceMap.get(entry.getKey()).getServerName(), itemStateEntry.getKey().getId()), OpcDAUtils.getObjectValue(itemStateEntry.getValue()));
                    } catch (JIException e) {
                        result.put(TagUtils.genTagId(DataSourceType.OPCDA.getCode(), deviceMap.get(entry.getKey()).getServerName(), itemStateEntry.getKey().getId()), CommonConstant.BAD_VALUE);
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                for (String[] tag : entry.getValue()) {
                    result.put(TagUtils.genTagId(DataSourceType.OPCDA.getCode(), deviceMap.get(entry.getKey()).getServerName(), tag[1]), CommonConstant.BAD_VALUE);
                }
            }
        }
        return result;
    }

    private Group getGroup(Server server, String sourceId) throws Exception {
        try {
            if (!groupMap.containsKey(sourceId)) {
                log.info("根据数据源获取opcDAGroup,sourceId=" + sourceId);
                Group group = server.addGroup(sourceId);
                if (group != null) {
                    groupMap.put(sourceId, group);
                }
            }
        } catch (Exception ex) {
            log.info("=========getOPCDAGroup Exception============");
            log.info("ex.message+" + ex.getMessage());
            ex.printStackTrace();
            throw new Exception(ex.getMessage());
        }
        return groupMap.get(sourceId);
    }

    public void write(String serverId) throws Exception {
        Server server = this.getServer(serverId);
        Group group = server.addGroup();
        Item item = group.addItem("通道 1.设备 1.item001");
        OpcDAUtils.write(item, new JIVariant("999"));
    }
}