StyleBuilder.java

/* ========================================================================
 * PlantUML : a free UML diagram generator
 * ========================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/paypal
 *
 * This file is part of PlantUML.
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PlantUML 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 General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 *
 * Original Author:  Arnaud Roques
 *
 *
 */
package net.sourceforge.plantuml.style;

import java.util.Collection;
import java.util.EnumMap;

import net.sourceforge.plantuml.style.parser2.StyleQuery;

public class StyleBuilder implements AutomaticCounter {

	// The trie-backed replacement for the old, plain-linear-scan StyleStorage -- see
	// StyleIndex's own documentation for why: resolving a style is by far the hottest path
	// through this class (once per diagram element, not once per file), so this is the part
	// that actually had to change; how styles are parsed into Style objects in the first
	// place (loadInternal/muteStyle's callers) is untouched.
	private StyleIndex index = StyleIndex.empty();
	// private final Set<StyleSignature> printedForLog;
	private int counter;

	public void printMe() {
		for (Style style : index.getAllStyles())
			style.printMe();
	}

//	private StyleBuilder(Set<StyleSignature> printedForLog) {
//		this.printedForLog = new LinkedHashSet<>();
//	}

	public StyleBuilder() {
		// this(new LinkedHashSet<StyleSignature>());
	}

	public StyleBuilder cloneMe() {
		final StyleBuilder result = new StyleBuilder();
		result.index = this.index;
		result.counter = this.counter;
		return result;

	}

	public Style createStyleStereotype(String name) {
		if (name.contains(Style.STAR))
			throw new IllegalArgumentException();

		name = name.toLowerCase();
		final StyleQuery signature = StyleQuery.empty().withStereotype(name);

		// An exact-signature lookup, not a cascade: only a bare ".name { ... }" declared with
		// no SName scoping at all can ever match. Several such declarations (repeated in the
		// file) are folded together here rather than pre-merged at load time, since this index
		// no longer deduplicates by exact signature as it is populated -- see StyleIndex.
		Style result = null;
		for (Style style : index.getAllStyles())
			if (style.getQuery().equals(signature))
				result = result == null ? style : result.mergeWith(style, MergeStrategy.OVERWRITE_EXISTING_VALUE);

		if (result == null)
			return new Style(signature, new EnumMap<PName, Value>(PName.class));

		return result;
	}

	public StyleBuilder muteStyle(Collection<Style> modifiedStyles) {
		final StyleBuilder result = new StyleBuilder(/*this.printedForLog*/);
		result.counter = this.counter;
		result.index = this.index.withMuted(modifiedStyles);
		return result;
	}

	public void loadInternal(StyleQuery signature, Style newStyle) {
		if (signature.getLevelConstraint().isStar())
			throw new IllegalArgumentException();

		this.index = this.index.withLoaded(newStyle);
	}

	@Override
	public int getNextInt() {
		return ++counter;
	}

	public Style getMergedStyle(StyleQuery query) {
		return index.getMergedStyle(query);
	}

	public Style getMergedStyleSpecial(StyleQuery query, int ancestorRank) {
//		boolean added = this.printedForLog.add(query);
//		if (added)
//			Log.info(() -> "Using style " + query);

		Style mergedStyle = null;
		for (Style style : index.findMatching(query)) {
			final StyleQuery key = style.getQuery();

			Style tmp = style;
			if (key.getLevelConstraint().isStar())
				tmp = tmp.withAncestorRank(ancestorRank);

			if (mergedStyle == null)
				mergedStyle = tmp;
			else
				mergedStyle = mergedStyle.mergeWith(tmp, MergeStrategy.OVERWRITE_EXISTING_VALUE);

		}
		return mergedStyle;
	}

}