package org.jabref.logic.layout.format;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.jabref.logic.bst.BibtexNameFormatter;
import org.jabref.logic.layout.LayoutFormatter;
import org.jabref.model.entry.AuthorList;
/**
* This layout formatter uses the Bibtex name.format$ method and provides ultimate flexibility:
*
* The formatter needs a parameter to be passed in that follows the following format:
*
* <case1>@<range11>@"<format>"@<range12>@"<format>"@<range13>...@@
*
* <case2>@<range21>@... and so on.
*
* Individual cases are separated by @@ and items in a case by @.
*
* Cases are just integers or the character * and will tell the formatter to apply the following formats if there are
* less or equal authors given to it. The cases must be in strict increasing order with the * in the last position.
*
* For instance:
*
* case1 = 2
* case2 = 3
* case3 = *
*
* Ranges are either <integer>..<integer>, <integer> or the character * using a 1 based index for indexing
* authors from the given authorlist. Integer indexes can be negative to denote them to start from
* the end of the list where -1 is the last author.
*
* For instance with an authorlist of "Joe Doe and Mary Jane and Bruce Bar and Arthur Kay":
*
* 1..3 will affect Joe, Mary and Bruce
*
* 4..4 will affect Arthur
*
* * will affect all of them
*
* 2..-1 will affect Mary, Bruce and Arthur
*
* The <format> uses the Bibtex formatter format:
*
* The four letter v, f, l, j indicate the name parts von, first, last, jr which
* are used within curly braces. A single letter v, f, l, j indicates that the name should be abbreviated.
* To put a quote in the format string quote it using \" (mh. this doesn't work yet)
*
* I give some examples but would rather point you to the bibtex documentation.
*
* "{ll}, {f}." Will turn "Joe Doe" into "Doe, J."
*
* Complete example:
*
* To turn:
*
* "Joe Doe and Mary Jane and Bruce Bar and Arthur Kay"
*
* into
*
* "Doe, J., Jane, M., Bar, B. and Kay, A."
*
* you would use
*
* 1@*@{ll}, {f}.@@2@1@{ll}, {f}.@2@ and {ll}, {f}.@@*@1..-3@{ll}, {f}., @-2@{ll}, {f}.@-1@ and {ll}, {f}.
*
* Yeah this is trouble-some to write, but should work.
*
* For more examples see the test-cases.
*
*/
public class NameFormatter implements LayoutFormatter {
public static final String DEFAULT_FORMAT = "1@*@{ff }{vv }{ll}{, jj}@@*@1@{ff }{vv }{ll}{, jj}@*@, {ff }{vv }{ll}{, jj}";
private String parameter = NameFormatter.DEFAULT_FORMAT;
private static String format(String toFormat, AuthorList al, String[] formats) {
StringBuilder sb = new StringBuilder();
int n = al.getNumberOfAuthors();
for (int i = 1; i <= al.getNumberOfAuthors(); i++) {
for (int j = 1; j < formats.length; j += 2) {
if ("*".equals(formats[j])) {
sb.append(BibtexNameFormatter.formatName(toFormat, i, formats[j + 1], null));
break;
} else {
String[] range = formats[j].split("\\.\\.");
int s;
int e;
if (range.length == 2) {
s = Integer.parseInt(range[0]);
e = Integer.parseInt(range[1]);
} else {
s = e = Integer.parseInt(range[0]);
}
if (s < 0) {
s += n + 1;
}
if (e < 0) {
e += n + 1;
}
if (e < s) {
int temp = e;
e = s;
s = temp;
}
if ((s <= i) && (i <= e)) {
sb.append(BibtexNameFormatter.formatName(toFormat, i, formats[j + 1], null));
break;
}
}
}
}
return sb.toString();
}
public String format(String toFormat, String inParameters) {
AuthorList al = AuthorList.parse(toFormat);
String parameters;
if ((inParameters == null) || inParameters.isEmpty()) {
parameters = "*:*:\"{ff}{vv}{ll}{,jj} \"";
} else {
parameters = inParameters;
}
String[] cases = parameters.split("@@");
for (String aCase : cases) {
String[] formatString = aCase.split("@");
if (formatString.length < 3) {
// Error
return toFormat;
}
if ("*".equals(formatString[0])) {
return format(toFormat, al, formatString);
} else {
if (al.getNumberOfAuthors() <= Integer.parseInt(formatString[0])) {
return format(toFormat, al, formatString);
}
}
}
return toFormat;
}
@Override
public String format(String fieldText) {
return format(fieldText, parameter);
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
public static Map<String, String> getNameFormatters(NameFormatterPreferences prefs) {
Objects.requireNonNull(prefs);
Map<String, String> result = new HashMap<>();
List<String> names = prefs.getNameFormatterKey();
List<String> formats = prefs.getNameFormatterValue();
for (int i = 0; i < names.size(); i++) {
if (i < formats.size()) {
result.put(names.get(i), formats.get(i));
} else {
result.put(names.get(i), DEFAULT_FORMAT);
}
}
return result;
}
}