package com.vtence.molecule.http;
import com.vtence.molecule.helpers.Joiner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.toList;
public class Header {
private static final String ZERO_OR_EVEN_NUMBER_OF_QUOTES_AHEAD = "(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
private static Pattern ignoringQuotedStrings(String delimiter) {
return Pattern.compile("\\s*" + delimiter + "\\s*" + ZERO_OR_EVEN_NUMBER_OF_QUOTES_AHEAD);
}
private static final Pattern VALUES_DELIMITER = ignoringQuotedStrings(",");
private static final Pattern TOKENS_DELIMITER = ignoringQuotedStrings(";");
private static final Pattern NAME_VALUE_DELIMITER = ignoringQuotedStrings("=");
private final List<Value> values;
public Header(String header) {
this.values = sortByQuality(parseValues(header));
}
public List<Value> all() {
return Collections.unmodifiableList(values);
}
public Value first() {
return values.get(0);
}
public List<String> values() {
return values.stream().filter(Value::acceptable).map(Value::value).collect(toList());
}
private List<Value> parseValues(String header) {
List<Value> values = new ArrayList<>();
for (String value : VALUES_DELIMITER.split(header)) {
String[] tokens = TOKENS_DELIMITER.split(value);
values.add(new Value(value(tokens), parameters(tokens)));
}
return values;
}
private String value(String[] tokens) {
return tokens[0];
}
private List<Parameter> parameters(String[] tokens) {
List<Parameter> pairs = new ArrayList<>();
for (int i = 1; i < tokens.length; i++) {
String token = tokens[i];
String[] parts = NAME_VALUE_DELIMITER.split(token);
String attribute = parts[0];
String value = parts.length > 1 ? parts[1] : null;
pairs.add(new Parameter(attribute, value));
}
return pairs;
}
public String toString() {
return Joiner.on(", ").join(values);
}
private List<Value> sortByQuality(List<Value> entries) {
Collections.sort(entries);
return entries;
}
public static class Value implements Comparable<Value> {
private final String value;
private final double quality;
private final List<Parameter> parameters;
public Value(String value, List<Parameter> parameters) {
this.value = value.trim();
this.parameters = parameters;
this.quality = parseQuality();
}
public String value() {
return value;
}
public boolean is(String value) {
return this.value.equals(value);
}
public double quality() {
return quality;
}
public boolean acceptable() {
return quality > 0;
}
public List<Parameter> parameters() {
return parameters;
}
public String parameter(String name) {
for (Parameter parameter : parameters()) {
if (parameter.is(name)) return parameter.value();
}
return null;
}
private double parseQuality() {
if (parameters.isEmpty()) return 1.0;
Parameter first = parameters.get(0);
if (!first.is("q") || first.value() == null) return 1.0;
try {
return Double.parseDouble(first.value());
} catch (NumberFormatException e) {
return 1.0;
}
}
public int compareTo(Value other) {
return Double.compare(other.quality(), quality);
}
public String toString() {
if (parameters.isEmpty()) return value;
return value + "; " + Joiner.on("; ").join(parameters);
}
}
public static class Parameter {
private final String name;
private final String value;
public Parameter(String name, String value) {
this.name = name.trim();
this.value = value != null ? value.trim() : null;
}
public String name() {
return name;
}
public boolean is(String name) {
return this.name().equals(name);
}
public String value() {
return value;
}
public String toString() {
return name + (value != null ? "=" + value : "");
}
}
}