/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.model.api.utils; import com.google.common.collect.Lists; import com.qcadoo.model.api.DataDefinition; import com.qcadoo.model.api.Entity; import com.qcadoo.model.api.EntityTree; import com.qcadoo.model.api.EntityTreeNode; import com.qcadoo.model.api.types.TreeType; import com.qcadoo.model.internal.EntityTreeImpl; import com.qcadoo.model.internal.api.PriorityService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; import static com.google.common.collect.Lists.newLinkedList; @Service public class TreeNumberingServiceImpl implements TreeNumberingService { private static final String ROOT_NODE_NUMBER = "1"; @Autowired private PriorityService priorityService; @Override public final void generateTreeNumbers(final EntityTree tree) { if (tree.getRoot() == null) { return; } generateTreeNumbers(tree.getRoot()); } @Override public final void generateTreeNumbers(final EntityTreeNode treeNode) { assignNumberToTreeNode(treeNode, Lists.newLinkedList(Lists.newArrayList(ROOT_NODE_NUMBER))); } @Override @Transactional public final void generateNumbersAndUpdateTree(final EntityTree tree) { if (tree.getRoot() == null) { return; } generateTreeNumbers(tree); for (Entity treeNode : tree) { treeNode.getDataDefinition().save(treeNode); } } @Override public final void generateNumbersAndUpdateTree(final DataDefinition dd, final String joinFieldName, final Long belongsToEntityId) { EntityTree tree = new EntityTreeImpl(dd, joinFieldName, belongsToEntityId); generateNumbersAndUpdateTree(tree); } @Override public final Comparator<Entity> getTreeNodesNumberComparator() { return new TreeNodesNumberComparator(); } final void assignNumberToTreeNode(final EntityTreeNode treeNode, final Deque<String> chain) { treeNode.setField(TreeType.NODE_NUMBER_FIELD, convertCollectionToString(chain)); List<EntityTreeNode> childrens = newLinkedList(treeNode.getChildren()); Collections.sort(childrens, priorityService.getEntityPriorityComparator()); int charNumber = 0; for (EntityTreeNode child : childrens) { Deque<String> newBranch = Lists.newLinkedList(chain); if (childrens.size() == 1) { incrementLastChainNumber(newBranch); } else { incrementLastChainCharacter(newBranch, charNumber++); } assignNumberToTreeNode(child, newBranch); } } public static void incrementLastChainNumber(final Deque<String> chain) { Integer nextNumber = Integer.valueOf(chain.pollLast()) + 1; chain.addLast(nextNumber.toString()); } public static void incrementLastChainCharacter(final Deque<String> chain, final int charNumber) { int quotient = charNumber / 26; int modulo = charNumber % 26; if (quotient <= 0) { chain.addLast(String.valueOf((char) (65 + charNumber))); } else { chain.addLast(String.valueOf((char) (65 + (quotient - 1))).concat(String.valueOf((char) (65 + modulo)))); } chain.addLast("1"); } public static String convertCollectionToString(final Collection<String> collection) { return StringUtils.join(collection, '.') + '.'; } private final class TreeNodesNumberComparator implements Comparator<Entity> { @Override public int compare(final Entity e1, final Entity e2) { String n1 = e1.getStringField(TreeType.NODE_NUMBER_FIELD); String n2 = e2.getStringField(TreeType.NODE_NUMBER_FIELD); if (n1 == null) { if (n2 == null) { return 0; } return 1; } if (n2 == null) { return -1; } return n1.compareTo(n2); } } }