package com.github.czyzby.lml.parser.impl.tag.macro;
import com.badlogic.gdx.utils.Array;
import com.github.czyzby.kiwi.util.common.Nullables;
import com.github.czyzby.kiwi.util.common.Strings;
import com.github.czyzby.kiwi.util.gdx.collection.GdxArrays;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.impl.tag.AbstractMacroLmlTag;
import com.github.czyzby.lml.parser.tag.LmlTag;
/** Allows to assign LML parser arguments from within LML templates. Arguments will be available after macro evaluation
* with the given name, by default: {accessedLikeThis}. First macro attribute is the name of the argument to assign.
* Other - optional - arguments will be joined with space and assigned as argument value. Alternatively, argument value
* can be the data between macro tags. For example: <blockquote>
*
* <pre>
* <:assign arg0 Value/>
* <:assign arg1 Complex value with many parts./>
* <:assign arg2>Data between macro tags.</:assign>
* </pre>
*
* </blockquote>Assigned values:
* <ul>
* <li>{arg0}: {@code "Value"}
* <li>{arg1}: {@code "Complex value with many parts."}
* <li>{arg2}: {@code "Data between macro tags."}
* </ul>
* Of course, data between assignment macro tags can contain any other tags (including nested assign macros) and can be
* used to effectively assign template parts to convenient-to-use arguments.
*
* <p>
* Assignment macro supports optional named attributes:<blockquote>
*
* <pre>
* <:assign key="arg0" value="Value"/>
* <:assign key="arg1" value="Complex value with many parts."/>
* <:assign key="arg2">Data between macro tags.</:assign>
* </pre>
*
* </blockquote>
*
* @author MJ */
public class AssignLmlMacroTag extends AbstractMacroLmlTag {
/** Optional name of the first attribute: name of the argument to set. */
public static final String KEY_ATTRIBUTE = "key";
/** Optional name of the second attribute: value to assign. */
public static final String VALUE_ATTRIBUTE = "value";
private CharSequence argument;
public AssignLmlMacroTag(final LmlParser parser, final LmlTag parentTag, final StringBuilder rawTagData) {
super(parser, parentTag, rawTagData);
}
@Override
public void handleDataBetweenTags(final CharSequence rawMacroContent) {
if (Strings.isNotEmpty(rawMacroContent)) {
argument = rawMacroContent;
}
}
@Override
public void closeTag() {
if (hasArgumentName()) {
getParser().getData().addArgument(getArgumentName(), processArgumentValue(getArgumentValue()));
} else {
getParser().throwErrorIfStrict(
"Assignment macro needs at least one attribute: name of the argument to assign. If you use named attributes, use 'key' attribute to set the argument name.");
}
}
/** @param argumentValue should be evaluated according to macro specification.
* @return evaluated value. */
protected String processArgumentValue(final CharSequence argumentValue) {
// Assignment macro does parse the value, it just assigns it.
return argumentValue.toString();
}
/** @return argument value that should be assigned. */
protected CharSequence getArgumentValue() {
if (argument != null) {
if (hasArgumentValue()) {
getParser().throwErrorIfStrict(
"Assignment macro cannot have both argument value to assign (second macro attribute) and content between tags. Only 1 value can be assigned to 1 argument name.");
}
return argument;
}
if (hasArgumentValue()) {
return getArgumentValueFromAttributes();
}
getParser().throwErrorIfStrict(
"Assignment macro has to have a value to assign. Pass second attribute name or add content between macro tags.");
return Nullables.DEFAULT_NULL_STRING;
}
/** @return true if has at least one attribute. */
protected boolean hasArgumentName() {
return GdxArrays.isNotEmpty(getAttributes());
}
/** @return true if has the argument value to assign. */
protected boolean hasArgumentValue() {
return hasAttribute(VALUE_ATTRIBUTE) || GdxArrays.sizeOf(getAttributes()) > 1;
}
/** @return attribute assigned to argument name. */
protected String getArgumentName() {
return hasAttribute(KEY_ATTRIBUTE) ? getAttribute(KEY_ATTRIBUTE) : getAttributes().get(0);
}
/** @return attribute assigned to argument value. */
protected String getArgumentValueFromAttributes() {
if (hasAttribute(VALUE_ATTRIBUTE)) {
return getAttribute(VALUE_ATTRIBUTE);
}
final Array<String> attributes = getAttributes();
if (GdxArrays.sizeOf(attributes) == 2) {
return attributes.get(1);
}
final StringBuilder builder = new StringBuilder();
final char separator = getAttributeSeparator();
for (int index = 1, length = GdxArrays.sizeOf(attributes); index < length; index++) {
if (builder.length() > 0) {
builder.append(separator);
}
builder.append(attributes.get(index));
}
return builder.toString();
}
/** @return character will be used to separate multiple macro attributes. */
protected char getAttributeSeparator() {
return ' ';
}
@Override
public String[] getExpectedAttributes() {
return new String[] { KEY_ATTRIBUTE, VALUE_ATTRIBUTE };
}
}