001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.search.advanced.utils; 017 018import java.util.List; 019import java.util.function.Function; 020 021import org.ametys.cms.search.advanced.AbstractTreeNode; 022import org.ametys.cms.search.advanced.TreeInternalNode; 023import org.ametys.cms.search.advanced.TreeLeaf; 024 025/** 026 * Helper to {@link #print(AbstractTreeNode) print} a tree for debug purposes. 027 */ 028public final class TreePrinter 029{ 030 private TreePrinter() 031 { 032 // Nothing 033 } 034 035 /** 036 * Prints the given tree 037 * <br>Use for debug purposes only. 038 * @param <T> the type of the values of the leaves of the tree. 039 * @param tree The tree to print 040 * @return The string representing the tree 041 */ 042 public static <T> String print(AbstractTreeNode<T> tree) 043 { 044 return print(tree, Object::toString); 045 } 046 047 /** 048 * Prints the given tree 049 * <br>Use for debug purposes only. 050 * @param <T> the type of the values of the leaves of the tree. 051 * @param tree The tree to print 052 * @param leafStringifier The function to transform a leaf value to a readable String 053 * @return The string representing the tree 054 */ 055 public static <T> String print(AbstractTreeNode<T> tree, Function<T, String> leafStringifier) 056 { 057 StringBuilder sb = new StringBuilder(); 058 _print(sb, tree, leafStringifier, new StringBuffer(), true); 059 return sb.toString(); 060 } 061 062 private static <T> void _print(StringBuilder sb, AbstractTreeNode<T> tree, Function<T, String> leafStringifier, StringBuffer prefix, boolean isTail) 063 { 064 String name; 065 if (tree instanceof TreeLeaf<?>) 066 { 067 name = leafStringifier.apply(((TreeLeaf<T>) tree).getValue()); 068 } 069 else if (tree instanceof TreeInternalNode<?>) 070 { 071 name = ((TreeInternalNode<T>) tree).getLogicalOperator().toString(); 072 } 073 else 074 { 075 throw new IllegalArgumentException("Wrong type of TreeNode. It must only be a TreeInternalNode or a TreeLeaf."); 076 } 077 sb.append(prefix).append(isTail ? "└── " : "├── ").append(name).append("\n"); 078 079 if (tree instanceof TreeInternalNode<?>) 080 { 081 List<AbstractTreeNode<T>> children = ((TreeInternalNode<T>) tree).getChildren(); 082 StringBuffer newPrefix = new StringBuffer(prefix).append(isTail ? " " : "│ "); 083 int i = 1; 084 for (AbstractTreeNode<T> child : children) 085 { 086 boolean childIsTail = i == children.size(); 087 _print(sb, child, leafStringifier, newPrefix, childIsTail); 088 i++; 089 } 090 } 091 } 092}