package com.hubspot.jinjava.lib.filter;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.lang3.BooleanUtils;
import com.google.common.collect.Lists;
import com.hubspot.jinjava.doc.annotations.JinjavaDoc;
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
import com.hubspot.jinjava.doc.annotations.JinjavaSnippet;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.util.ObjectIterator;
import com.hubspot.jinjava.util.Variable;
@JinjavaDoc(
value = "Sort an iterable.",
params = {
@JinjavaParam(value = "value", type = "iterable", desc = "The sequence or dict to sort through iteration"),
@JinjavaParam(value = "reverse", type = "boolean", defaultValue = "False", desc = "Boolean to reverse the sort order"),
@JinjavaParam(value = "case_sensitive", type = "boolean", defaultValue = "False", desc = "Determines whether or not the sorting is case sensitive"),
@JinjavaParam(value = "attribute", desc = "Specifies an attribute to sort by")
},
snippets = {
@JinjavaSnippet(
code = "{% for item in iterable|sort %}\n" +
" ...\n" +
"{% endfor %}"),
@JinjavaSnippet(
desc = "This filter requires all parameters to sort by an attribute in HubSpot. Below is a set of posts that are retrieved and alphabetized by 'name'.",
code = "{% set my_posts = blog_recent_posts('default', limit=5) %}\n" +
"{% for item in my_posts|sort(False, False,'name') %}\n" +
" {{ item.name }}<br>\n" +
"{% endfor %}")
})
public class SortFilter implements Filter {
@Override
public String getName() {
return "sort";
}
@Override
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
if (var == null) {
return var;
}
boolean reverse = false;
if (args.length > 0) {
reverse = BooleanUtils.toBoolean(args[0]);
}
boolean caseSensitive = false;
if (args.length > 1) {
caseSensitive = BooleanUtils.toBoolean(args[1]);
}
String attr = null;
if (args.length > 2) {
attr = args[2];
}
List<?> result = Lists.newArrayList(ObjectIterator.getLoop(var));
Collections.sort(result, new ObjectComparator(interpreter, reverse, caseSensitive, attr));
return result;
}
private static class ObjectComparator implements Comparator<Object> {
private final boolean reverse;
private final boolean caseSensitive;
private final Variable variable;
public ObjectComparator(JinjavaInterpreter interpreter, boolean reverse, boolean caseSensitive, String attr) {
this.reverse = reverse;
this.caseSensitive = caseSensitive;
if (attr != null) {
this.variable = new Variable(interpreter, "o." + attr);
}
else {
this.variable = null;
}
}
@SuppressWarnings("unchecked")
@Override
public int compare(Object o1, Object o2) {
int result = 0;
if (variable != null) {
o1 = variable.resolve(o1);
o2 = variable.resolve(o2);
}
if (o1 instanceof String && !caseSensitive) {
result = ((String) o1).compareToIgnoreCase((String) o2);
}
else if (Comparable.class.isAssignableFrom(o1.getClass()) && Comparable.class.isAssignableFrom(o2.getClass())) {
result = ((Comparable<Object>) o1).compareTo(o2);
}
if (reverse) {
result = -1 * result;
}
return result;
}
}
}