package com.xydl.cac.iec;

import com.xydl.cac.entity.*;
import com.xydl.cac.entity.constants.Constants;
import com.xydl.cac.exception.BusinessException;
import com.xydl.cac.model.StaticVariable;
import com.xydl.cac.repository.IcdFileRepository;
import com.xydl.cac.service.IcdTransformService;
import com.xydl.cac.util.IcdXmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.*;

@Service
@Slf4j
public class IecServerService {

    @Resource
    IcdFileRepository fileRepository;
    @Resource
    IcdTransformService transformService;

    @PostConstruct
    private void init() {
        List<IcdFile> list = fileRepository.findBySrvAndStart(Constants.Server, Constants.TRUE);
        if (!CollectionUtils.isEmpty(list)) {
            for (IcdFile icdFile : list) {
                try {
                    this.startServer(icdFile.getId(), icdFile.getPort());
                } catch (Exception ignore) {
                }
            }
        }
    }

    public void startServer(Integer fileId, int port) throws BusinessException {
        Optional<IcdFile> optional = fileRepository.findById(fileId);
        if (!optional.isPresent()) {
            throw new BusinessException("未找到该文件fileId=" + fileId);
        }
        IcdFile icdFile = optional.get();
        if (icdFile.getSrv() != Constants.Server) {
            throw new BusinessException("该文件不是服务端文件");
        }
        try {
            IecServer iecServer = new IecServer(transformService);
            iecServer.start(icdFile.getXml(), port);
            iecServer.filename = icdFile.getFilename();
            StaticVariable.iecServerMap.put(fileId, iecServer);
            icdFile.setStart(Constants.TRUE);
            icdFile.setPort(port);
            fileRepository.save(icdFile);
        } catch (Exception e) {
            icdFile.setStart(Constants.FALSE);
            fileRepository.save(icdFile);
            log.error("启动IEC61850服务端异常.", e);
            throw new BusinessException(e.getMessage());
        }
    }

    public void stopServer(Integer fileId) {
        this.doStopServer(fileId);
        Optional<IcdFile> optional = fileRepository.findById(fileId);
        if (optional.isPresent()) {
            IcdFile icdFile = optional.get();
            icdFile.setStart(Constants.FALSE);
            fileRepository.save(icdFile);
        }
    }

    private void doStopServer(Integer fileId) {
        IecServer iecServer = StaticVariable.iecServerMap.get(fileId);
        if (iecServer != null) {
            iecServer.stop();
            StaticVariable.iecServerMap.remove(fileId);
        }
    }

    @PreDestroy
    private void stop() {
        StaticVariable.shutdown = 1;
        Iterator<Integer> it = StaticVariable.iecServerMap.keySet().iterator();
        while (it.hasNext()) {
            Integer key = it.next();
            this.doStopServer(key);
        }
    }

    public List<IcdConfigTypeInst> listParamindex(Integer fileId) throws Exception {
        Optional<IcdFile> optional = fileRepository.findById(fileId);
        if (!optional.isPresent()) {
            throw new BusinessException("未找到该文件fileId=" + fileId);
        }
        IcdFile icdFile = optional.get();
        if (icdFile.getSrv() != Constants.Server) {
            throw new BusinessException("该文件不是服务端文件");
        }
        List<IcdConfigTypeInst> result = new ArrayList<>();
        icdFile = IcdXmlUtil.loadIcdType(icdFile.getXml());
        for (IcdConfigType config : icdFile.getConfigList()) {
            if (config.getAttMap() != null && config.getInstMap() != null) {
                Collection<IcdConfigTypeInst> instList = config.getInstMap().values();
                Collection<IcdConfigTypeAtt> attList = config.getAttMap().values();
                for (IcdConfigTypeInst inst : instList) {
                    String param = config.getIedName() + config.getLdeviceInst() + "/" + config.getLnClass()
                            + inst.getInst();
                    inst.setParamIndex(param);
                    for (IcdConfigTypeAtt att : attList) {
                        if (att.containInst(inst.getInst())) {
                            String paramindex = param + "." + att.getDoName();
                            inst.addAtt(paramindex);
                        }
                    }
                }
                result.addAll(instList);
            }
        }
        return result;
    }
}
