package com.brilliance.isc.doc.model;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;

/**
 * 报文树形结构【根节点固定只有HEAD,BODY两个根子节点，不提供构建方法，只能使用{@link #createDocTreeNode()}】
 */
public class DocTreeNode {
    private String tag;
    private String data;
    private List<DocTreeNode> children = new ArrayList<>();

    private DocTreeNode() {
    }

    private DocTreeNode(String tag) {
        this.tag = tag;
    }

    private DocTreeNode(String tag, String data) {
        this.tag = tag;
        this.data = data;
    }

    /**
     * 创建一个包含HEAD和BODY的初始报文树
     */
    public static DocTreeNode createDocTreeNode() {
        DocTreeNode root = new DocTreeNode("ROOT");
        DocTreeNode head = new DocTreeNode("HEAD");
        DocTreeNode body = new DocTreeNode("BODY");
        root.addChild(head);
        root.addChild(body);
        return root;
    }

    /**
     * 获取根节点的HEAD子节点
     */
    public DocTreeNode getHead() {
        Assert.state("ROOT".equals(tag), "当前节点不是根节点");
        return getChildren().get(0);
    }

    /**
     * 获取根节点的BODY子节点
     */
    public DocTreeNode getBody() {
        Assert.state("ROOT".equals(tag), "当前节点不是根节点");
        return getChildren().get(1);
    }

    /**
     * 获取当前节点TAG
     */
    public String getTag() {
        return tag;
    }

    /**
     * 获取当前节点值
     */
    public String getData() {
        return data;
    }

    /**
     * 设置当前节点值
     */
    public void setData(String data) {
        this.data = data;
    }

    /**
     * 获取当前节点的子节点
     */
    public List<DocTreeNode> getChildren() {
        return children;
    }

    /**
     * 增加一个不包含值的节点
     */
    public DocTreeNode add(String id) {
        return add(id, null);
    }

    /**
     * 增加一个包含值得叶子节点
     */
    public DocTreeNode add(String id, String val) {
        return addChild(new DocTreeNode(id, val));
    }

    /**
     * 判断本身是否为纯节点（没有值，但是有子节点集合）
     */
    public boolean isNode() {
        return ObjectUtils.isEmpty(data) && children.size() > 0;
    }

    /**
     * 如果当前
     *
     * @return
     */
    public boolean hasChildren() {
        return !CollectionUtils.isEmpty(children);
    }

    /**
     * 前序遍历树
     */
    public void preOrderTraversal(BiConsumer<DocTreeNode, Integer> consumer, int level) {
        consumer.accept(this, level);
        for (DocTreeNode child : children) {
            child.preOrderTraversal(consumer, level + 1);
        }
    }

    /**
     * 当前节点增加子节点，并返回这个子节点
     */
    private DocTreeNode addChild(DocTreeNode child) {
        this.children.add(child);
        return child;
    }
}
