<commit_before>package de.undercouch.citeproc.csl.internal.rendering;

import de.undercouch.citeproc.csl.CSLName;
import de.undercouch.citeproc.csl.internal.RenderContext;
import de.undercouch.citeproc.csl.internal.SElement;
import de.undercouch.citeproc.helper.NodeHelper;
import org.w3c.dom.Node;

import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * A name element from a style file
 * @author <NAME>
 */
public class SName implements SElement {
    private final String variable;
    private final String and;
    private final String initializeWith;

    /**
     * Create the name element from an XML node
     * @param node the XML node
     * @param variable the variable that holds the name
     */
    public SName(Node node, String variable) {
        this.variable = variable;
        and = NodeHelper.getAttrValue(node, "and");
        initializeWith = NodeHelper.getAttrValue(node, "initialize-with");
    }

    @Override
    public void render(RenderContext ctx) {
        CSLName[] names = ctx.getNameVariable(variable);
        if (names == null) {
            throw new IllegalStateException("Selected names are empty");
        }

        String delimiter;
        if ("text".equals(and)) {
            delimiter = ctx.getTerm("and");
        } else if ("symbol".equals(and)) {
            delimiter = "&";
        } else {
            throw new IllegalArgumentException("Unknown value for `and' " +
                    "attribute: " + and);
        }
        delimiter = " " + delimiter + " ";

        String result = Arrays.stream(names)
                .map(this::render)
                .collect(Collectors.joining(delimiter));
        ctx.emit(result);
    }

    private String render(CSLName name) {
        StringBuilder result = new StringBuilder();

        String given = name.getGiven();
        if (initializeWith != null) {
            // produce initials for each given name and append
            // 'initializeWith' to each of them
            boolean found = true;
            for (int i = 0; i < given.length(); ++i) {
                char c = given.charAt(i);
                if (Character.isWhitespace(c) || c == '.') {
                    found = true;
                } else if (found) {
                    result.append(c).append(initializeWith);
                    found = false;
                }
            }
        } else {
            result.append(given);
        }

        return result.append(name.getFamily()).toString();<commit_msg>Correctly render delimiters in name lists<commit_after>package de.undercouch.citeproc.csl.internal.rendering;

import de.undercouch.citeproc.csl.CSLName;
import de.undercouch.citeproc.csl.internal.RenderContext;
import de.undercouch.citeproc.csl.internal.SElement;
import de.undercouch.citeproc.helper.NodeHelper;
import org.w3c.dom.Node;

/**
 * A name element from a style file
 * @author <NAME>
 */
public class SName implements SElement {
    private final String variable;
    private final String and;
    private final String delimiter;
    private final String delimiterPrecedesLast;
    private final String initializeWith;

    /**
     * Create the name element from an XML node
     * @param node the XML node
     * @param variable the variable that holds the name
     */
    public SName(Node node, String variable) {
        this.variable = variable;
        and = NodeHelper.getAttrValue(node, "and");

        String delimiter = NodeHelper.getAttrValue(node, "delimiter");
        if (delimiter == null) {
            delimiter = ", ";
        }
        this.delimiter = delimiter;

        String delimiterPrecedesLast = NodeHelper.getAttrValue(node,
                "delimiter-precedes-last");
        if (delimiterPrecedesLast == null) {
            delimiterPrecedesLast = "contextual";
        }
        this.delimiterPrecedesLast = delimiterPrecedesLast;

        initializeWith = NodeHelper.getAttrValue(node, "initialize-with");
    }

    @Override
    public void render(RenderContext ctx) {
        CSLName[] names = ctx.getNameVariable(variable);
        if (names == null) {
            throw new IllegalStateException("Selected names are empty");
        }

        String and;
        if ("text".equals(this.and)) {
            and = ctx.getTerm("and");
        } else if ("symbol".equals(this.and)) {
            and = "&";
        } else {
            throw new IllegalArgumentException("Unknown value for `and' " +
                    "attribute: " + this.and);
        }

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < names.length; ++i) {
            builder.append(render(names[i]));
            if (i < names.length - 1) {
                if (i == names.length - 2) {
                    switch (delimiterPrecedesLast) {
                        case "contextual":
                            if (names.length > 2) {
                                builder.append(delimiter);
                            }
                            break;

                        case "always":
                            builder.append(delimiter);
                            break;

                        default:
                            break;
                    }
                    appendAnd(builder, and);
                } else {
                    builder.append(delimiter);
                }
            }
        }
        ctx.emit(builder.toString());
    }

    private void appendAnd(StringBuilder builder, String and) {
        if (!Character.isWhitespace(builder.charAt(builder.length() - 1))) {
            builder.append(" ");
        }
        builder.append(and).append(" ");
    }

    private String render(CSLName name) {
        StringBuilder result = new StringBuilder();

        String given = name.getGiven();
        if (initializeWith != null) {
            // produce initials for each given name and append
            // 'initializeWith' to each of them
            boolean found = true;
            for (int i = 0; i < given.length(); ++i) {
                char c = given.charAt(i);
                if (Character.isWhitespace(c) || c == '.') {
                    found = true;
                } else if (found) {
                    result.append(c).append(initializeWith);
                    found = false;
                }
            }
        } else {
            result.append(given);
        }

        return result.append(name.getFamily()).toString();
{'fraction_non_alphanumeric': 0.10582419280086514, 'fraction_numerical': 0.001390390854317936, 'mean_word_length': 1.7385786802030456, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7253670', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1676, 'n_words': 422}