package com.comphenix.xp.parser;
import java.util.List;
import org.apache.commons.lang.NullArgumentException;
import org.bukkit.configuration.ConfigurationSection;
import com.comphenix.xp.SampleRange;
import com.comphenix.xp.expressions.VariableFunction;
import com.comphenix.xp.parser.text.StringRangeParser;
/**
* Responsible for reading ranges.
*
* @author Kristian
*/
public class RangeParser extends ConfigurationParser<VariableFunction> {
protected TextParser<VariableFunction> textParser;
public RangeParser() {
// Automatically convert the string parser to a function parser
this(StringRangeParser.toFunctionParser(new StringRangeParser()));
}
/**
* Constructs a range parser with a specified text parser.
* @param textParser - text parser to use.
*/
public RangeParser(TextParser<VariableFunction> textParser) {
this.textParser = textParser;
}
@Override
public VariableFunction parse(ConfigurationSection input, String key) throws ParsingException {
VariableFunction result = null;
if (key.equals("Player")) {
result = null;
}
try {
result = parse(input, key, null, true);
} catch (Exception e) {
// Convert to parsing exception
throw new ParsingException(
String.format("Range error: %s", e.getMessage()), e);
}
// Turn default value into an exception
if (result != null)
return result;
else
throw ParsingException.fromFormat("Range error at key %s.", key );
}
@Override
public VariableFunction parse(ConfigurationSection input, String key, VariableFunction defaultValue) {
try {
return parse(input, key, defaultValue, false);
} catch (Exception e) {
// You and I know this can never happen. The compiler, however ...
throw new IllegalStateException("This should never occur.", e);
}
}
private VariableFunction parse(ConfigurationSection input, String key, VariableFunction defaultValue, boolean throwException) throws Exception {
Object root = input.get(key);
SampleRange result = null;
if (root instanceof Double) {
result = new SampleRange((Double) root);
} else if (root instanceof Integer) {
result = new SampleRange((Integer) root);
} else if (root instanceof List) {
@SuppressWarnings("rawtypes")
List attempt = (List) root;
try {
// Try to extract two or one elements from the list
if (attempt != null && attempt.size() == 2)
result = new SampleRange(tryParse(attempt.get(0)), tryParse(attempt.get(1)));
else if (attempt != null && attempt.size() == 1)
result = new SampleRange(tryParse(attempt.get(0)));
else if (!throwException)
return defaultValue;
else
// Make errors more descriptive
throw new ParsingException("Too many elements in range - must be one or two.");
} catch (Exception e) {
// Parsing error
if (throwException)
throw e;
else
return defaultValue;
}
} else if (root instanceof String) {
// Parse it as a string
try {
return textParser.parse((String) root);
} catch (Exception e) {
// Error here too
if (throwException)
throw e;
else
return defaultValue;
}
} else if (root instanceof ConfigurationSection) {
ConfigurationSection section = (ConfigurationSection) root;
Double first = toDouble(section.get("first"));
Double last = toDouble(section.get("last"));
// Backwards compatibility
if (first != null && last != null && section.getValues(false).size() == 2) {
result = new SampleRange(first, last);
} else {
return defaultValue;
}
}
// Convert to a function at the end
return VariableFunction.fromRange(result);
}
private Double toDouble(Object value) {
// Handle integers as well as doubles
if (value instanceof Integer)
return ((Integer) value).doubleValue();
else if (value instanceof Double)
return (Double) value;
else
return null;
}
/**
* Constructs a similar range parser with the given text parser.
* @param parser - text parser to handle string ranges.
* @return New range parser.
*/
public RangeParser withParser(TextParser<VariableFunction> parser) {
return new RangeParser(parser);
}
private double tryParse(Object obj) {
if (obj == null)
throw new NullArgumentException("obj");
// Handle different types
if (obj instanceof Double)
return (Double) obj;
else if (obj instanceof Integer)
return (int) ((Integer) obj);
else if (obj instanceof String)
return Double.parseDouble((String) obj);
else
throw new IllegalArgumentException("Unknown argument type.");
}
}