Generator.java 18.6 KB
package com.viontech.storage.entity;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.viontech.storage.config.Dict;
import com.viontech.storage.model.Caption;
import com.viontech.storage.model.PicConfig;
import com.viontech.storage.model.StorageConfig;
import com.viontech.storage.service.CaptionService;
import com.viontech.storage.service.PicConfigService;
import com.viontech.storage.service.StorageConfigService;
import com.viontech.storage.vo.CaptionVo;
import com.viontech.storage.vo.PicConfigVo;
import com.viontech.storage.vo.StorageConfigVo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import java.util.*;
import java.util.stream.Collectors;

/**
 * .
 *
 * @author 谢明辉
 * @date 2021/11/9
 */


public class Generator {
    private static final String ROOT_ELEMENT_NAME = "StorageConfig";
    private static final String FILE_VERSION = "001-012-000-000";

    private static final TimedCache<Long, String> STORAGE_CONFIG_ID_RESULT_CACHE = CacheUtil.newTimedCache(20 * 1000);
    private final Document document = XmlUtil.createXml("StorageConfig");
    private final List<Context> contexts;
    /** key: picConfigVoId */
    private final Map<Long, PicConfigVo> picConfigMap;
    /** key: captionSetId */
    private final Map<Long, List<CaptionVo>> captionSetMap;

    public Generator(Long storageConfigId) {
        StorageConfigService storageConfigService = SpringUtil.getBean(StorageConfigService.class);
        PicConfigService picConfigService = SpringUtil.getBean(PicConfigService.class);
        CaptionService captionService = SpringUtil.getBean(CaptionService.class);

        StorageConfig storageConfig0 = storageConfigService.getById(storageConfigId);
        this.contexts = StorageConfigVo.copy(storageConfig0).getContexts();
        if (contexts == null || contexts.size() == 0) {
            throw new RuntimeException("无法构建改配置");
        }

        List<Long> picConfigIds = contexts.stream().map(Context::getPicConfigId).collect(Collectors.toList());

        List<PicConfig> picConfigs = picConfigService.listByIds(picConfigIds);
        this.picConfigMap = new HashMap<>(picConfigs.size());
        ArrayList<Long> captionSetIds = new ArrayList<>();
        for (PicConfig item : picConfigs) {
            PicConfigVo copy = PicConfigVo.copy(item);
            picConfigMap.put(copy.getId(), copy);
            captionSetIds.add(copy.getCaptionSetId());
        }

        List<Caption> captions = captionService.list(
                captionService.query().in("caption_set_id", captionSetIds).getWrapper()
        );

        this.captionSetMap = captions.stream().map(CaptionVo::copy).collect(Collectors.groupingBy(CaptionVo::getCaptionSetId, Collectors.toList()));
    }

    public String build() {
        Node rootNode = document.getFirstChild();
        rootNode.appendChild(createTextNode("FileVersion", FILE_VERSION));
        Element standard = document.createElement("Standard");
        rootNode.appendChild(standard);
        standard.appendChild(createTextNode("SolutionNum", String.valueOf(contexts.size())));
        Element switchPathConfig = document.createElement("SwitchPathConfig");
        switchPathConfig.appendChild(createTextNode("Flag", "1"));
        switchPathConfig.appendChild(createTextNode("RootPaths", "/VionData/RecordData/viondata0;/VionData/RecordData/viondata1;/VionData/RecordData/viondata2;/VionData/RecordData/viondata3;"));
        switchPathConfig.appendChild(createTextNode("VolumeThreshold", "2048"));
        switchPathConfig.appendChild(createTextNode("CountThreshold", "64"));
        standard.appendChild(switchPathConfig);

        for (Context context : contexts) {
            Node solution = buildSolution(context);
            if (solution != null) {
                standard.appendChild(solution);
            }
        }
        return XmlUtil.toStr(document, "GBK", false);
    }


    private Node buildSolution(Context context) {
        String conditions = combineConditions(context.getDataTypes());
        Integer order = context.getOrder();
        Long picConfigId = context.getPicConfigId();
        PicConfigVo picConfig = picConfigMap.get(picConfigId);
        if (picConfig == null || !picConfig.getEnabled()) {
            return null;
        }

        Element solution = document.createElement("Solution" + order);
        solution.appendChild(createTextNode("SolutionName", picConfig.getName()));
        solution.appendChild(createTextNode("Conditions", conditions));
        Element iniInfo = document.createElement("IniInfo");
        iniInfo.appendChild(createTextNode("infContent", "(开始时间:YYYY-MM-DD HH:mm:SS_xxx)+(换行分隔符)+EndTime=+(结束时间:YYYY-MM-DD HH:mm:SS xxx)+(换行分隔符)+"));
        solution.appendChild(iniInfo);
        Element pathConfig = document.createElement("PathConfig");
        pathConfig.appendChild(createTextNode("PicRelativePath", "/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+.jpg;/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+_2+.jpg;/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+_3+.jpg;/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+_4+.jpg;/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+_5+.jpg;;"));
        pathConfig.appendChild(createTextNode("PicRootPath", "/kk/shuju;;;;;"));
        pathConfig.appendChild(createTextNode("INIRelativePath", "/+(设备编号)+/+(开始时间:YYYYMM/DD/HH)+/+(开始时间:YYYYMMDDHHmmSSxxx)+_+(车牌号码)+_+车道+(车道号)+.ini"));
        pathConfig.appendChild(createTextNode("INIRootPath", "/kk/ini;;;;;"));
        pathConfig.appendChild(document.createTextNode("VideoRelativePath"));
        pathConfig.appendChild(createTextNode("VideoRootPath", "/kk/video;;;;;"));
        solution.appendChild(pathConfig);
        Node picConfigNode = buildPicConfig(picConfig);
        solution.appendChild(picConfigNode);
        return solution;
    }

    private Node buildPicConfig(PicConfigVo picConfig) {
        Element configNode = document.createElement("PicConfig");
        configNode.appendChild(createTextNode("PicCount", "1"));
        configNode.appendChild(createTextNode("DigPicFlag", "1"));
        configNode.appendChild(createTextNode("scImagePrptyCnt", "-858993460"));
        configNode.appendChild(createTextNode("CoverCapFlag", "0"));
        configNode.appendChild(createTextNode("ImageQualityGlobalFlag", "0"));
        Element gamm = XmlUtil.appendChild(configNode, "Gamm");
        Element denoiser = XmlUtil.appendChild(configNode, "Denoiser");
        Element picQuality = XmlUtil.appendChild(configNode, "PicQuality");
        gamm.appendChild(createTextNode("GammFlag", "0"));
        gamm.appendChild(createTextNode("GammValue", "0.600000"));
        denoiser.appendChild(createTextNode("EnableFlag", "0"));
        denoiser.appendChild(createTextNode("Type", "3"));
        denoiser.appendChild(createTextNode("Param1", "3"));
        denoiser.appendChild(createTextNode("Param2", "3"));
        denoiser.appendChild(createTextNode("Param3", "0.000000"));
        denoiser.appendChild(createTextNode("Param4", "0.000000"));

        Element fixedSizeQuality = XmlUtil.appendChild(picQuality, "FixedSizeQuality");
        Element st200wImageQuality = XmlUtil.appendChild(picQuality, "st200WImageQuality");
        Element st500wImageQuality = XmlUtil.appendChild(picQuality, "st500WImageQuality");
        fixedSizeQuality.appendChild(createTextNode("DayQuality", "500"));
        fixedSizeQuality.appendChild(createTextNode("NightQuality", "500"));
        st200wImageQuality.appendChild(createTextNode("DayQuality", "80"));
        st200wImageQuality.appendChild(createTextNode("NightQuality", "80"));
        st500wImageQuality.appendChild(createTextNode("DayQuality", "60"));
        st500wImageQuality.appendChild(createTextNode("NightQuality", "60"));
        picQuality.appendChild(createTextNode("LightThreshold", "40"));
        picQuality.appendChild(createTextNode("UseFixedSize", "0"));

        Element pic1 = XmlUtil.appendChild(configNode, "Pic1");
        pic1.appendChild(createTextNode("OriPicCount", String.valueOf(picConfig.calPicCount())));
        pic1.appendChild(createTextNode("DirectSaveFlag", "0"));
        PicConfigCalculator calculator = new PicConfigCalculator(picConfig);
        Coordinate[] coordinates = calculator.coordinates;
        HashMap<Integer, Coordinate> coordinateMap = calculator.coordinateMap;
        for (int i = 0; i < coordinates.length; i++) {
            Coordinate item = coordinates[i];
            Element oriPic = XmlUtil.appendChild(pic1, "OriPic" + (i + 1));
            XmlUtil.appendChild(oriPic, "Content").setTextContent(item.getName());
            XmlUtil.appendChild(oriPic, "Type").setTextContent("0");
            Element srcCoordinate = XmlUtil.appendChild(oriPic, "SrcCoordinate");
            Element desCoordinate = XmlUtil.appendChild(oriPic, "DesCoordinate");
            XmlUtil.appendChild(srcCoordinate, "left").setTextContent("0");
            XmlUtil.appendChild(srcCoordinate, "top").setTextContent("0");
            XmlUtil.appendChild(srcCoordinate, "width").setTextContent(item.getName() + "宽");
            XmlUtil.appendChild(srcCoordinate, "height").setTextContent(item.getName() + "高");
            XmlUtil.appendChild(desCoordinate, "left").setTextContent(item.getX());
            XmlUtil.appendChild(desCoordinate, "top").setTextContent(item.getY());
            XmlUtil.appendChild(desCoordinate, "width").setTextContent("全景1宽");
            XmlUtil.appendChild(desCoordinate, "height").setTextContent("全景1高");
        }
        // 字幕
        Long captionSetId = picConfig.getCaptionSetId();
        List<CaptionVo> captionVos = captionSetMap.get(captionSetId);
        Element captionsElement = XmlUtil.appendChild(pic1, "Captions");
        int captionCount = 0;
        for (int i = 0; i < captionVos.size(); i++) {
            CaptionVo caption = captionVos.get(i);
            Integer picType = caption.getPicType();
            Coordinate coordinate = coordinateMap.get(picType);
            if (coordinate == null) {
                continue;
            }

            List<Context> contexts = caption.getContexts();
            String dateFormat = (caption.getMillisecond() != null && caption.getMillisecond()) ? caption.getDateFormat() + ":xxx" : caption.getDateFormat();
            Pair<String, Integer> combine = combineCaptionContent(picType, contexts, dateFormat);
            String content = combine.getKey();
            Integer wrapCount = combine.getValue();
            Element ele = XmlUtil.appendChild(captionsElement, "Caption" + (i + 1));
            XmlUtil.appendChild(ele, "Content").setTextContent(content);
            XmlUtil.appendChild(ele, "bgColor").setTextContent(caption.getBgColor().toString());
            XmlUtil.appendChild(ele, "Font").setTextContent(caption.getFont().toString());
            XmlUtil.appendChild(ele, "FontSize").setTextContent(caption.getFontSize().toString());
            XmlUtil.appendChild(ele, "fgColor").setTextContent(caption.getFgColor().toString());
            XmlUtil.appendChild(ele, "ShadowColor").setTextContent("4");
            XmlUtil.appendChild(ele, "ShadowSize").setTextContent("0");
            XmlUtil.appendChild(ele, "bgTransparency").setTextContent(caption.getBgTransparency().toString());
            Element coordinateElement = XmlUtil.appendChild(ele, "Coordinate");
            // 坐标需要根据positionType来搞
            Integer positionType = caption.getPositionType();
            String y = coordinate.getY();
            if (positionType == 1) {
                y = y + "+全景1高";
            } else if (positionType == 0) {
                y = y + "-80";
            } else if (positionType == 3) {
                y = y + "+全景1高-80";
            }
            XmlUtil.appendChild(coordinateElement, "left").setTextContent(coordinate.getX());
            XmlUtil.appendChild(coordinateElement, "top").setTextContent(y);
            XmlUtil.appendChild(coordinateElement, "width").setTextContent("全景1宽");
            int height = wrapCount == 0 ? 80 : caption.getFontSize() * wrapCount;
            XmlUtil.appendChild(coordinateElement, "height").setTextContent(String.valueOf(height));
            captionCount++;
        }
        XmlUtil.appendChild(captionsElement, "Count").setTextContent(String.valueOf(captionCount));
        return configNode;
    }

    private Element createTextNode(String name, String text) {
        Element node = document.createElement(name);
        node.setTextContent(text);
        return node;
    }

    private String combineConditions(List<String> dataTypes) {
        return dataTypes.stream().map(x -> "数据类型=" + x).collect(Collectors.joining("+"));
    }

    private Pair<String, Integer> combineCaptionContent(Integer picType, List<Context> contexts, String dateFormat) {
        if (CollectionUtil.isEmpty(contexts)) {
            return Pair.of(null, null);
        }
        String picTypeName = Dict.INSTANCE.picType.get(picType);
        StringBuilder sb = new StringBuilder();
        int wrapCount = 0;
        for (Context context : contexts) {
            Integer type = context.getType();
            sb.append(Dict.INSTANCE.captionType.get(type)).append(": + ");
            switch (type) {
                case 1:
                    sb.append("(").append(picTypeName).append("时间:").append(dateFormat).append(")");
                    break;
                case 9:
                    sb.append("(用户车辆类型1)");
                    break;
                case 10:
                    sb.append("(用户车身颜色1)");
                    break;
                case 11:
                    sb.append("(车辆子品牌)");
                    break;
                case 15:
                    sb.append("(合成图1防伪码)");
                    break;
                case 16:
                    sb.append(context.getContent());
                    break;
                case 17:
                    sb.append("(违法类型代码)");
                    break;
                default:
                    sb.append("(").append(Dict.INSTANCE.captionType.get(type)).append(")");
            }

            if (context.getWrap()) {
                wrapCount++;
                sb.append("+(换行分隔符)");
            }
            sb.append("+");
        }
        sb.setLength(sb.length() - 1);
        return Pair.of(sb.toString(), wrapCount);
    }


    private static class PicConfigCalculator {

        public final Coordinate[] coordinates;
        /** key : picType */
        public final HashMap<Integer, Coordinate> coordinateMap = new HashMap<>();
        private final int layoutType;

        public PicConfigCalculator(PicConfigVo picConfigVo) {
            List<Context> contexts = picConfigVo.getContexts().stream().sorted(Comparator.comparingInt(Context::getOrder)).collect(Collectors.toList());
            layoutType = picConfigVo.getType();
            this.coordinates = new Coordinate[contexts.size()];
            for (int i = 0; i < contexts.size(); i++) {
                Context context = contexts.get(i);
                Integer picType = context.getType();
                calCoordinate(i, picType);
            }
        }

        private void calCoordinate(Integer index, Integer picType) {
            String x = "0";
            String y = "80";
            if (index != 0) {
                Coordinate pre = coordinates[index - 1];
                switch (layoutType) {
                    case 21:
                    case 31:
                    case 41:
                    case 51:
                    case 61:
                        x = pre.x + "+" + "全景1宽";
                        y = "80";
                        break;
                    case 12:
                    case 13:
                    case 14:
                    case 15:
                    case 16:
                        x = "0";
                        y = pre.y + "+" + "全景1高";
                        break;
                    case 22:
                    case 23:
                        if (index == 1) {
                            x = "全景1宽";
                            y = "80";
                        } else if (index == 2) {
                            x = "0";
                            y = "80" + "+" + "全景1高";
                        } else if (index == 3) {
                            x = "全景1宽";
                            y = "80" + "+" + "全景1高";
                        } else if (index == 4) {
                            x = "0";
                            y = coordinates[2].y + "+" + "全景1高";
                        } else if (index == 5) {
                            x = "全景1宽";
                            y = coordinates[3].y + "+" + "全景1高";
                        }
                        break;
                    case 32:
                        if (index == 1) {
                            x = "全景1宽";
                            y = "80";
                        } else if (index == 2) {
                            x = "全景1宽" + "+" + "全景1宽";
                            y = "80";
                        } else if (index == 3) {
                            x = "0";
                            y = "80" + "+" + "全景1高";
                        } else if (index == 4) {
                            x = "全景1宽";
                            y = "80" + "+" + "全景1高";
                        } else if (index == 5) {
                            x = "全景1宽 + 全景1宽";
                            y = "80" + "+" + "全景1高";
                        }
                        break;
                    default:
                        throw new RuntimeException("no such type");
                }
            }
            Coordinate coordinate = new Coordinate(picType, Dict.INSTANCE.picType.get(picType), x, y);
            coordinates[index] = coordinate;
            coordinateMap.put(picType, coordinate);
        }
    }


    public @Getter
    @Setter
    @AllArgsConstructor
    static class Coordinate {
        private Integer type;
        private String name;
        private String x;
        private String y;
    }

}