package org.diagbot.nlp.util;

import org.diagbot.nlp.participle.cfg.Configuration;
import org.diagbot.nlp.participle.cfg.DefaultConfig;
import org.diagbot.nlp.participle.word.Segment;

import java.util.*;

/**
 * @ClassName org.diagbot.nlp.util.NlpCache
 * @Description 词典库 同义词 大小类缓存
 * @Author fyeman
 * @Date 2019/1/11/011 14:04
 * @Version 1.0
 **/
public class NlpCache {
    //词典库
    public static Segment segment_cache = null;
    //词典库
    public static Segment segment_cache_pacs = null;
    //推送字典
    public static Map<String, String> standard_info_push_map = null;
    //词库同义词定义
    public static Map<String, Map<String, String>> standard_info_synonym_map = null;
    //词库大小类定义
    public static Map<String, String> standard_info_classify_map = null;
    //慢病推送
    public static Map<String, String> standard_info_chronic_map = null;
    //树形结构存储大小类
    public static Map<String, Node> standard_info_type_tree_map = null;
    //后结构化 有可能作为训练样本词性匹配对
    public static Map<String, List<String>> extract_relation_property_pair_map = null;

    public static void createSegmentCache() {
        Configuration configuration = new DefaultConfig();
        segment_cache = configuration.loadMainDict( "tc.dict");
    }

    public static void createSegmentCachePacs() {
        Configuration configuration = new DefaultConfig();
        segment_cache_pacs = configuration.loadMainDict("pacs-tc.dict");
    }

    public static void createPushCache() {
        Configuration configuration = new DefaultConfig();
        standard_info_push_map = configuration.loadMapDict( "push-tc.dict");
    }

    public static void createSynonymCache() {
        Configuration configuration = new DefaultConfig();
        List<String> lines = configuration.readFileContents("synonym.dict");

        String[] line_arr;
        Map<String, String> map = null;
        standard_info_synonym_map = new HashMap<>();
        for (String line : lines) {
            line_arr = org.apache.commons.lang3.StringUtils.split(line, "\\|");
            map = standard_info_synonym_map.get(line_arr[2]);
            if (map == null) {
                map = new HashMap<>();
            }
            map.put(line_arr[0], line_arr[1]);
            standard_info_synonym_map.put(line_arr[2], map);
        }
    }

    public static void createClassifyCache() {
        Configuration configuration = new DefaultConfig();

        standard_info_classify_map = configuration.loadMapDict("classify.dict");
    }

    public static void createChronicCache() {
        Configuration configuration = new DefaultConfig();
        standard_info_chronic_map = configuration.loadMapDict("chronic.dict");
    }

    public static void createClassifyTreeCache() {
        Configuration configuration = new DefaultConfig();
        standard_info_classify_map = configuration.loadMapDict("classify.dict");
    }

    public static void createPropertyPairCache() {
        Configuration configuration = new DefaultConfig();
        List<String> lines = configuration.readFileContents("relation.dict");

        extract_relation_property_pair_map = new HashMap<>();
        List<String> list = null;
        for (String line : lines) {
            String[] prop = line.split("\\|");
            if(prop.length != 2) {
                continue;
            }
            String prop1_id = prop[0];
            String prop2_id = prop[1];

            list = extract_relation_property_pair_map.get(prop1_id);
            if (list == null) {
                list = new ArrayList<>();
                list.add(prop2_id);
                extract_relation_property_pair_map.put(prop1_id, list);
            } else {
                if (!list.contains(prop2_id)) {
                    list.add(prop2_id);
                    extract_relation_property_pair_map.put(prop1_id, list);
                }
            }

            list = extract_relation_property_pair_map.get(prop2_id);
            if (list == null) {
                list = new ArrayList<>();
                list.add(prop1_id);
                extract_relation_property_pair_map.put(prop2_id, list);
            } else {
                if (!list.contains(prop1_id)) {
                    list.add(prop1_id);
                    extract_relation_property_pair_map.put(prop2_id, list);
                }
            }
        }
    }

    public static Segment getSegment_cache() {
        if (segment_cache == null) {
            createSegmentCache();
        }
        return segment_cache;
    }

    public static Segment getSegment_cache_pacs() {
        if (segment_cache_pacs == null) {
            createSegmentCachePacs();
        }
        return segment_cache_pacs;
    }

    public static Map<String, String> getStandard_info_push_map() {
        if (standard_info_push_map == null) {
            createPushCache();
        }
        return standard_info_push_map;
    }

    public static Map<String, Map<String, String>> getStandard_info_synonym_map() {
        if (standard_info_synonym_map == null) {
            createSynonymCache();
        }
        return standard_info_synonym_map;
    }

    public static Map<String, String> getStandard_info_classify_map() {
        if (standard_info_classify_map == null) {
            createClassifyCache();
        }
        return standard_info_classify_map;
    }

    public static Map<String, String> getStandard_info_chronic_map() {
        if (standard_info_chronic_map == null) {
            createChronicCache();
        }
        return standard_info_chronic_map;
    }

    public static Map<String, List<String>> getExtract_relation_property_pair_map() {
        if (extract_relation_property_pair_map == null) {
            createPropertyPairCache();
        }
        return extract_relation_property_pair_map;
    }


    public static Map<String, Node> getStandard_info_type_tree_map() {
        if (standard_info_type_tree_map == null) {
            standard_info_type_tree_map = new HashMap<>();
            for (Map.Entry<String, String> entry : getStandard_info_classify_map().entrySet()) {
                Node parent_node = standard_info_type_tree_map.get(entry.getValue());
                if (parent_node == null) {
                    parent_node = new Node();
                    parent_node.setName(entry.getValue());
                }
                Node child_node = standard_info_type_tree_map.get(entry.getKey());
                if (child_node == null) {
                    child_node = new Node();
                    child_node.setName(entry.getKey());
                }
                parent_node.add(parent_node, child_node);
                standard_info_type_tree_map.put(entry.getValue(), parent_node);
                standard_info_type_tree_map.put(entry.getKey(), child_node);
            }
        }
        return standard_info_type_tree_map;
    }

    private void addChilds(Node root, Map<String, String> standardInfoTypeMap, List<String> hasAddList) {
        for (Node node : root.getChilds()) {
            for (Map.Entry<String, String> entry : standardInfoTypeMap.entrySet()) {
                if (node.getName().equals(entry.getValue())) {
                    node.add(node, entry.getKey());
                    hasAddList.add(entry.getKey());
                }
            }
        }
    }

    public static class Node {
        private String name;
        private Node parent;
        private Set<Node> childs = new HashSet<>();

        public Node add(Node parent, String name) {
            Node node = new Node();
            node.setName(name);
            node.setParent(parent);
            parent.getChilds().add(node);
            return parent;
        }

        public Node add(Node parent, Node node) {
            node.setParent(parent);
            parent.getChilds().add(node);
            return parent;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Set<Node> getChilds() {
            return childs;
        }

        public void setChilds(Set<Node> childs) {
            this.childs = childs;
        }

        public Node getParent() {
            return parent;
        }

        public void setParent(Node parent) {
            this.parent = parent;
        }
    }
}
