<commit_before>/* 
 * Copyright (C) 2016 <NAME>
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license.  See the LICENSE file for details.
 */
package com.bouye.gw2.sab.text;

import api.web.gw2.mapping.core.CoinAmount;
import api.web.gw2.mapping.core.JsonpUtils;
import api.web.gw2.mapping.v2.items.ItemArmorType;
import api.web.gw2.mapping.v2.items.ItemInfixUpgradeAttribute;
import api.web.gw2.mapping.v2.items.ItemInfusionSlotFlag;
import api.web.gw2.mapping.v2.items.ItemRarity;
import api.web.gw2.mapping.v2.items.ItemTrinketType;
import api.web.gw2.mapping.v2.items.ItemType;
import api.web.gw2.mapping.v2.items.ItemWeaponDamageType;
import api.web.gw2.mapping.v2.items.ItemWeaponType;
import com.bouye.gw2.sab.SABConstants;
import com.bouye.gw2.sab.query.ImageCache;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.control.Hyperlink;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Utilities class used for label and rich text management.
 * @author <NAME>
 */
public enum LabelUtils {
    INSTANCE;

    private static final String CONTENT_TAG = "content"; // NOI18N.
    private static final String LINE_BREAK_TAG = "br"; // NOI18N.
    private static final String PARAGRAPH_TAG = "p"; // NOI18N.
    private static final String BOLD_TAG = "b"; // NOI18N.
    private static final String QUOTE_TAG = "quote"; // NOI18N.
    private static final String FONT_AWESOME_TAG = "font-awesome"; // NOI18N.
    private static final String COINS_TAG = "coins"; // NOI18N.
    private static final String STATS_UP_TAG = "stats-up"; // NOI18N.
    private static final String STATS_DOWN_TAG = "stats-down"; // NOI18N.
    private static final String NOTE_TAG = "note"; // NOI18N.
    private static final String LINK_TAG = "link"; // NOI18N.

    private static final String HREF_ATTR = "href"; // NOI18N.
    private static final String AMOUNT_ATTR = "amount"; // NOI18N.

    private final PseudoClass BOLD_PSEUDO_CLASS = PseudoClass.getPseudoClass("strong"); // NOI18N.
    private final PseudoClass QUOTE_PSEUDO_CLASS = PseudoClass.getPseudoClass(QUOTE_TAG); // NOI18N.
    private final PseudoClass FONT_AWESOME_PSEUDO_CLASS = PseudoClass.getPseudoClass(FONT_AWESOME_TAG);
    private final PseudoClass STATS_UP_PSEUDO_CLASS = PseudoClass.getPseudoClass(STATS_UP_TAG); // NOI18N.
    private final PseudoClass STATS_DOWN_PSEUDO_CLASS = PseudoClass.getPseudoClass(STATS_DOWN_TAG); // NOI18N.
    private final PseudoClass NOTE_PSEUDO_CLASS = PseudoClass.getPseudoClass(NOTE_TAG); // NOI18N.
    
    private static final String FLAVOR_START = "<c=@flavor>"; // NOI18N.
    private static final String FLAVOR_END = "</c>"; // NOI18N.

    /**
     * Provides a suitable label from an {@code Enum} instance.
     * @param value The value, may be {@code null}.
     * @return A {@code String}, may be {@code null} if {@code value} is {@code null}.
     */
    public String toLabel(final Enum value) {
        return (value == null) ? null : JsonpUtils.INSTANCE.javaEnumToJavaClassName(value);
    }

    /**
     * Provides a {@code PseudoClass} from an {@code Enum} instance.
     * @param value The value.
     * @return A {@code PseudoClass} instance, never {@code null}
     * @throws NullPointerException If {@code value} is {@code null}.
     */
    public PseudoClass toPseudoClass(final Enum value) throws NullPointerException {
        Objects.requireNonNull(value);
        final String pseudoClassName = toLabel(value);
        return PseudoClass.getPseudoClass(pseudoClassName);
    }

    /**
     * Split rich text content into nodes to display on screen.
     * @param string The source rich text, may be {@code null}.
     * @return A non-modifiable {@code List<Node>}, never {@code null}.
     */
    public List<Node> split(final String string) {
        return split(string, null);
    }

    /**
     * Split rich text content into nodes to display on screen.
     * <br>given text is imported as XML and given to a SAX parser.
     * @param string The source rich text, may be {@code null}.
     * @param linkActivator A {@code Consumer<String>} called when clicking on a {@code Hyperlink}, may be {@code null}.
     * @return A non-modifiable {@code List<Node>}, never {@code null}.
     */
    public List<Node> split(final String string, final Consumer<String> linkActivator) {
        List<Node> result = Collections.emptyList();
        if (string != null) {
            final List<Node> nodeList = new LinkedList();
            try {
                final SAXParserFactory spf = SAXParserFactory.newInstance();
                spf.setValidating(false);
                final SAXParser saxParser = spf.newSAXParser();
                String escapedContent = string.replaceAll("&", "&amp;"); // NOI18N.
                if (escapedContent.contains(FLAVOR_START) && !escapedContent.contains(FLAVOR_END)) {
                    escapedContent += FLAVOR_END;
                }
                final String xmlString = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><%s>%s</%s>", CONTENT_TAG, escapedContent, CONTENT_TAG); // NOI18N.
                final Map<String, Boolean> styleAttributes = initializeAttributeMap();
                try (final InputStream source = new ByteArrayInputStream(xmlString.getBytes("UTF-8"))) { // NOI18N.
                    saxParser.parse(source, new DefaultHandler() {
                        private Node node;

                        @Override
                        public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
                            node = null;
                            switch (qName) {
                                case BOLD_TAG:
                                case QUOTE_TAG:
                                case FONT_AWESOME_TAG:
                                case STATS_UP_TAG:
                                case STATS_DOWN_TAG:
                                case NOTE_TAG: {
                                    styleAttributes.put(qName, Boolean.TRUE);
                                }
                                break;
                                case LINK_TAG: {
                                    styleAttributes.put(LINK_TAG, Boolean.TRUE);
                                    final String href = attributes.getValue(HREF_ATTR);
                                    final Hyperlink hyperlink = new Hyperlink(string);
                                    hyperlink.setId("Hyperlink"); // NOI18N.
                                    hyperlink.setUserData(href);
                                    hyperlink.setOnAction(actionEvent -> {<commit_msg>Replacing flavored text with quotes.<commit_after>/* 
 * Copyright (C) 2016 <NAME>
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license.  See the LICENSE file for details.
 */
package com.bouye.gw2.sab.text;

import api.web.gw2.mapping.core.CoinAmount;
import api.web.gw2.mapping.core.JsonpUtils;
import api.web.gw2.mapping.v2.items.ItemArmorType;
import api.web.gw2.mapping.v2.items.ItemInfixUpgradeAttribute;
import api.web.gw2.mapping.v2.items.ItemInfusionSlotFlag;
import api.web.gw2.mapping.v2.items.ItemRarity;
import api.web.gw2.mapping.v2.items.ItemTrinketType;
import api.web.gw2.mapping.v2.items.ItemType;
import api.web.gw2.mapping.v2.items.ItemWeaponDamageType;
import api.web.gw2.mapping.v2.items.ItemWeaponType;
import com.bouye.gw2.sab.SABConstants;
import com.bouye.gw2.sab.query.ImageCache;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.control.Hyperlink;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Utilities class used for label and rich text management.
 * @author <NAME>
 */
public enum LabelUtils {
    INSTANCE;

    private static final String CONTENT_TAG = "content"; // NOI18N.
    private static final String LINE_BREAK_TAG = "br"; // NOI18N.
    private static final String PARAGRAPH_TAG = "p"; // NOI18N.
    private static final String BOLD_TAG = "b"; // NOI18N.
    private static final String QUOTE_TAG = "quote"; // NOI18N.
    private static final String FONT_AWESOME_TAG = "font-awesome"; // NOI18N.
    private static final String COINS_TAG = "coins"; // NOI18N.
    private static final String STATS_UP_TAG = "stats-up"; // NOI18N.
    private static final String STATS_DOWN_TAG = "stats-down"; // NOI18N.
    private static final String NOTE_TAG = "note"; // NOI18N.
    private static final String LINK_TAG = "link"; // NOI18N.

    private static final String HREF_ATTR = "href"; // NOI18N.
    private static final String AMOUNT_ATTR = "amount"; // NOI18N.

    private final PseudoClass BOLD_PSEUDO_CLASS = PseudoClass.getPseudoClass("strong"); // NOI18N.
    private final PseudoClass QUOTE_PSEUDO_CLASS = PseudoClass.getPseudoClass(QUOTE_TAG); // NOI18N.
    private final PseudoClass FONT_AWESOME_PSEUDO_CLASS = PseudoClass.getPseudoClass(FONT_AWESOME_TAG);
    private final PseudoClass STATS_UP_PSEUDO_CLASS = PseudoClass.getPseudoClass(STATS_UP_TAG); // NOI18N.
    private final PseudoClass STATS_DOWN_PSEUDO_CLASS = PseudoClass.getPseudoClass(STATS_DOWN_TAG); // NOI18N.
    private final PseudoClass NOTE_PSEUDO_CLASS = PseudoClass.getPseudoClass(NOTE_TAG); // NOI18N.
    
    private static final String FLAVOR_START = "<c=@flavor>"; // NOI18N.
    private static final String FLAVOR_END = "</c>"; // NOI18N.

    /**
     * Provides a suitable label from an {@code Enum} instance.
     * @param value The value, may be {@code null}.
     * @return A {@code String}, may be {@code null} if {@code value} is {@code null}.
     */
    public String toLabel(final Enum value) {
        return (value == null) ? null : JsonpUtils.INSTANCE.javaEnumToJavaClassName(value);
    }

    /**
     * Provides a {@code PseudoClass} from an {@code Enum} instance.
     * @param value The value.
     * @return A {@code PseudoClass} instance, never {@code null}
     * @throws NullPointerException If {@code value} is {@code null}.
     */
    public PseudoClass toPseudoClass(final Enum value) throws NullPointerException {
        Objects.requireNonNull(value);
        final String pseudoClassName = toLabel(value);
        return PseudoClass.getPseudoClass(pseudoClassName);
    }

    /**
     * Split rich text content into nodes to display on screen.
     * @param string The source rich text, may be {@code null}.
     * @return A non-modifiable {@code List<Node>}, never {@code null}.
     */
    public List<Node> split(final String string) {
        return split(string, null);
    }

    /**
     * Split rich text content into nodes to display on screen.
     * <br>given text is imported as XML and given to a SAX parser.
     * @param string The source rich text, may be {@code null}.
     * @param linkActivator A {@code Consumer<String>} called when clicking on a {@code Hyperlink}, may be {@code null}.
     * @return A non-modifiable {@code List<Node>}, never {@code null}.
     */
    public List<Node> split(final String string, final Consumer<String> linkActivator) {
        List<Node> result = Collections.emptyList();
        if (string != null) {
            final List<Node> nodeList = new LinkedList();
            try {
                final SAXParserFactory spf = SAXParserFactory.newInstance();
                spf.setValidating(false);
                final SAXParser saxParser = spf.newSAXParser();
                String escapedContent = string.replaceAll("&", "&amp;"); // NOI18N.
                if (escapedContent.contains(FLAVOR_START) && !escapedContent.contains(FLAVOR_END)) {
                    escapedContent += FLAVOR_END;
                }
                escapedContent = escapedContent.replaceAll(FLAVOR_START, String.format("<%s>", QUOTE_TAG)); // NOI18N.
                escapedContent = escapedContent.replaceAll(FLAVOR_END, String.format("</%s>", QUOTE_TAG)); // NOI18N.
                final String xmlString = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><%s>%s</%s>", CONTENT_TAG, escapedContent, CONTENT_TAG); // NOI18N.
                final Map<String, Boolean> styleAttributes = initializeAttributeMap();
                try (final InputStream source = new ByteArrayInputStream(xmlString.getBytes("UTF-8"))) { // NOI18N.
                    saxParser.parse(source, new DefaultHandler() {
                        private Node node;

                        @Override
                        public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
                            node = null;
                            switch (qName) {
                                case BOLD_TAG:
                                case QUOTE_TAG:
                                case FONT_AWESOME_TAG:
                                case STATS_UP_TAG:
                                case STATS_DOWN_TAG:
                                case NOTE_TAG: {
                                    styleAttributes.put(qName, Boolean.TRUE);
                                }
                                break;
                                case LINK_TAG: {
                                    styleAttributes.put(LINK_TAG, Boolean.TRUE);
                                    final String href = attributes.getValue(HREF_ATTR);
                                    final Hyperlink hyperlink = new Hyperlink(string);
                                    hyperlink.setId("Hyperlink"); // NOI18N.
                                    hyperlink.setUserData(href);
                                    hyperlink.setOnAction(actionEvent -> {
{'fraction_non_alphanumeric': 0.10183968462549277, 'fraction_numerical': 0.01038107752956636, 'mean_word_length': 2.49666896393292, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 2, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '929155', 'n_tokens_mistral': 4657, 'n_tokens_neox': 4419, 'n_words': 1132}