UbrexUrlBuilder.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.url;

import java.util.List;

import com.plantuml.ubrex.TextNavigator;
import com.plantuml.ubrex.UMatcher;
import com.plantuml.ubrex.UnicodeBracketedExpression;

// UrlUbrexTest
public class UbrexUrlBuilder {
	// ::remove file when __HAXE__

//	public static final IRegex MANDATORY = new RegexLeaf("URL", "(" + UbrexUrlBuilder.getRegexp() + ")");
//	public static final IRegex OPTIONAL = new RegexOptional(MANDATORY);

	private static final String START_PART = "[[ 〇*〴s";
	private static final String END_PART = "〇*〴s  ]]";

	private static final String S_QUOTED = START_PART + //
			"〃  〶$URL=〇+「〤〃」 〃" + // Quoted part
			"〇?〘 〇*〴s { 〶$TOOLTIP=〇*「〤{}」 } 〙" + // Optional tooltip
			"〇?〘 〴s 〶$LABEL=〘「〤〴s{}[]」  〇*「〤[]」〙  〙" + // Optional label
			END_PART;

	private static final String S_ONLY_TOOLTIP = START_PART + //
			"{  〶$TOOLTIP=〄>〘 }〇*〴s]]〙"; // Tooltip WARNING!! Not exactly the same

	private static final String S_ONLY_TOOLTIP_AND_LABEL = START_PART + //
			"{  〶$TOOLTIP=〇+「〤{}」 }" + // Tooltip
			"〇*〴s" + //
			"〶$LABEL=〘「〤〴s[]{}」 〇*「〤[]」〙" // Label
			+ END_PART;

	private static final String S_LINK_TOOLTIP_NOLABEL = START_PART + //
			"〶$URL=〇+「〤〴s〴g{}[]」" + // Link
			"〇*〴s" + //
			"{  〶$TOOLTIP=〄>〘 }〇*〴s]]〙"; // Tooltip

	private static final String S_LINK_WITH_OPTIONAL_TOOLTIP_WITH_OPTIONAL_LABEL = START_PART + //
			"〶$URL=〇+「〤〴s〴g{}[]」" + // Link
			"〇?〘  〇*〴s  {  〶$TOOLTIP=〇*「〤{}」  } 〙" + // Optional tooltip
			"〇?〘  〴s 〶$LABEL=〘「〤〴s{}[]」 〇*「〤[]」〙  〙" + // Optional label
			END_PART;

	private static final String S_LINK_NOTOOLTIP_WITH_OPTIONAL_LABEL = START_PART + //
			"〶$URL=〇+「〤〴s〴g[]」" + // Link
			"〇?〘  〴s 〶$LABEL=〘「〤〴s{}[]」 〇*「〤[]」〙  〙" + // Optional label
			END_PART;

//	public static String getRegexp() {
//		return S_QUOTED + "|" + //
//				S_ONLY_TOOLTIP + "|" + //
//				S_ONLY_TOOLTIP_AND_LABEL + "|" + //
//				S_LINK_TOOLTIP_NOLABEL + "|" + //
//				S_LINK_WITH_OPTIONAL_TOOLTIP_WITH_OPTIONAL_LABEL;
//	}
//
	private static final UnicodeBracketedExpression QUOTED = UnicodeBracketedExpression.build(S_QUOTED);
	private static final UnicodeBracketedExpression ONLY_TOOLTIP = UnicodeBracketedExpression.build(S_ONLY_TOOLTIP);
	private static final UnicodeBracketedExpression ONLY_TOOLTIP_AND_LABEL = UnicodeBracketedExpression
			.build(S_ONLY_TOOLTIP_AND_LABEL);
	private static final UnicodeBracketedExpression LINK_TOOLTIP_NOLABEL = UnicodeBracketedExpression
			.build(S_LINK_TOOLTIP_NOLABEL);
	private static final UnicodeBracketedExpression LINK_WITH_OPTIONAL_TOOLTIP_WITH_OPTIONAL_LABEL = UnicodeBracketedExpression
			.build(S_LINK_WITH_OPTIONAL_TOOLTIP_WITH_OPTIONAL_LABEL);
	private static final UnicodeBracketedExpression LINK_NOTOOLTIP_WITH_OPTIONAL_LABEL = UnicodeBracketedExpression
			.build(S_LINK_NOTOOLTIP_WITH_OPTIONAL_LABEL);

	private final String topurl;
	private UrlMode mode;

	public UbrexUrlBuilder(String topurl, UrlMode mode) {
		this.topurl = topurl;
		this.mode = mode;
	}

	public Url getUrl(String s) {
		UMatcher m;
		m = getMatcher(QUOTED, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		m = getMatcher(ONLY_TOOLTIP, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		m = getMatcher(ONLY_TOOLTIP_AND_LABEL, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		m = getMatcher(LINK_TOOLTIP_NOLABEL, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		m = getMatcher(LINK_WITH_OPTIONAL_TOOLTIP_WITH_OPTIONAL_LABEL, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		m = getMatcher(LINK_NOTOOLTIP_WITH_OPTIONAL_LABEL, s);
		if (matchesOrFind(m))
			return buildUrl(m);

		return null;
	}

	private UMatcher getMatcher(UnicodeBracketedExpression ubrex, String s) {
		if (mode == UrlMode.STRICT)
			return ubrex.match(s);
		final TextNavigator tn = TextNavigator.build(s);
		for (int i = 0; i < tn.length() - 2; i++) {
			final UMatcher matcher = ubrex.match(tn, i);
			if (matcher.startMatch())
				return matcher;
		}
		return new UMatchNone();
	}

	private Url buildUrl(UMatcher m) {
		final String url = getValue(m, "URL");
		final String tooltip = getValue(m, "TOOLTIP");
		final String label = getValue(m, "LABEL");
		return new Url(withTopUrl(url), tooltip, label);
	}

	private String getValue(UMatcher m, String key) {
		final List<String> list = m.getCapture(key);
		if (list.size() == 0)
			return null;
		return list.get(0);
	}

	private boolean matchesOrFind(UMatcher m) {
		if (mode == UrlMode.STRICT)
			return m.exactMatch();
		else if (mode == UrlMode.ANYWHERE)
			return m.startMatch();
		else
			throw new IllegalStateException();

	}

	private String withTopUrl(String url) {
		if (url == null)
			return "";
		if (url.startsWith("http:") == false && url.startsWith("https:") == false && url.startsWith("file:") == false
				&& topurl != null)
			return topurl + url;

		return url;
	}

	static class UMatchNone implements UMatcher {

		@Override
		public boolean startMatch() {
			return false;
		}

		@Override
		public boolean exactMatch() {
			return false;
		}

		@Override
		public String getAcceptedMatch() {
			throw new UnsupportedOperationException();
		}

		@Override
		public List<String> getCapture(String path) {
			throw new UnsupportedOperationException();
		}

		@Override
		public List<String> getKeysToBeRefactored() {
			throw new UnsupportedOperationException();
		}

	}

}