package org.tyrannyofheaven.bukkit.util.configuration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.file.YamlConstructor;
import org.bukkit.configuration.file.YamlRepresenter;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import com.google.common.base.Joiner;
/**
* Version of {@link YamlConfiguration} that supports comments with every root-level
* property.
*
* @author zerothangel
*/
public class AnnotatedYamlConfiguration extends YamlConfiguration {
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
// Map from property key to comment. Comment may have multiple lines that are newline-separated.
private final Map<String, String> comments = new HashMap<>();
@Override
public String saveToString() {
// Wish these were protected...
yamlOptions.setIndent(options().indent());
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
StringBuilder builder = new StringBuilder();
builder.append(buildHeader());
if (builder.length() > 0)
builder.append('\n'); // Newline after header, if present
// Iterate over each root-level property and dump
for (Iterator<Map.Entry<String, Object>> i = getValues(false).entrySet().iterator(); i.hasNext();) {
Map.Entry<String, Object> entry = i.next();
// Output comment, if present
String comment = comments.get(entry.getKey());
if (comment != null) {
builder.append(buildComment(comment));
}
// Dump property
builder.append(yaml.dump(Collections.singletonMap(entry.getKey(), entry.getValue())));
// Output newline, if not the last
if (i.hasNext())
builder.append('\n');
}
String dump = builder.toString();
if (dump.equals(BLANK_CONFIG)) {
dump = "";
}
return dump;
}
/**
* Format a multi-line property comment.
*
* @param comment the original comment string
* @return the formatted comment string
*/
protected String buildComment(String comment) {
StringBuilder builder = new StringBuilder();
for (String line : comment.split("\r?\n")) {
builder.append(COMMENT_PREFIX);
builder.append(line);
builder.append('\n');
}
return builder.toString();
}
/**
* Returns a root-level comment.
*
* @param key the property key
* @return the comment or <code>null</code>
*/
public String getComment(String key) {
return comments.get(key);
}
/**
* Set a root-level comment.
*
* @param key the property key
* @param comment the comment. May be <code>null</code>, in which case the comment
* is removed.
*/
public void setComment(String key, String... comment) {
if (comment != null && comment.length > 0) {
String s = Joiner.on('\n').join(comment);
comments.put(key, s);
}
else {
comments.remove(key);
}
}
/**
* Returns root-level comments.
*
* @return map of root-level comments
*/
public Map<String, String> getComments() {
return Collections.unmodifiableMap(comments);
}
/**
* Set root-level comments from a map.
*
* @param comments comment map
*/
public void setComments(Map<String, String> comments) {
this.comments.clear();
if (comments != null)
this.comments.putAll(comments);
}
}