package com.github.czyzby.lml.parser.impl.tag.macro;
import com.github.czyzby.kiwi.util.gdx.collection.GdxArrays;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.impl.tag.macro.util.Equation;
import com.github.czyzby.lml.parser.tag.LmlTag;
/** Constructs an equation from passed attribute, evaluates it and converts its result to a boolean. Spaces in
* attributes are supported and stripped. Equations can work on booleans, int, floats and Strings (types determined at
* runtime). Numbers are converted to true if greater than 0; Strings return true if they are not blank, "false" or
* "null". If no macro attributes are passed, condition returns false. Supported operators:
*
* <ul>
* <li>+: adds ints and floats; concats Strings.
* <li>-: subtracts ints and floats; uses {@link String#replace(CharSequence, CharSequence)} (replacing with empty
* string) on first string, removing occurrences of the second.
* <li>=: compares booleans, ints and floats; uses {@link String#equalsIgnoreCase(String)} on strings.
* <li>==: works like =, except uses regular equals method on strings.
* <li>!=, !==: negated equality operators.
* <li><, <=, >, >=: compares ints and floats; compares strings's lengths. If one of the strings is an int,
* compares numeric int value to the other's length. For example, "string>t" returns true, as "string" is longer than
* "t", but "string>9" returns false, because "string" has less characters than 9. Since > is also the char that
* closes the tag it cannot be used directly - alias for > is {@literal >}. < does not have to be escaped, so
* there's no alias.
* <li>*, /: multiples and divides ints and floats.
* <li>^: {@link java.lang.Math#pow(double, double)} on numbers; XOR on booleans.
* <li>&, &&, |, ||: logical "and" and "or" on booleans. Bit "and" and "or" on ints.
* <li>%: modulo on ints and floats.
* <li>!: negates booleans, ints and floats. Clears strings to empty string. Negates operators (!= becomes "not equals",
* !< becomes >, etc).
* <li>~: negates booleans. Bit negation on ints.
* <li>--, ++: increments or decrements numbers. Has to appear BEFORE the value to modify: will have no effect or throw
* exception otherwise. Has similar effect to +1 or -1, but is evaluated before most other operators; for example, --3^2
* returns 4, while 3-1^2 returns 2. If you want to simulate -- or ++, use parenthesis: (3-1)^2 returns 4.
* </ul>
*
* Example usage:
*
* <blockquote>
*
* <pre>
* <:if {loop:index}%4=0>
* <label row=true/>
* </:if>
* </pre>
*
* </blockquote> This macro appends label tag only if "loop:index" argument modulo 4 equals 0.
*
* <blockquote>
*
* <pre>
* <:if 100<{@literal @}bundleLine>
* <textButton text=@bundleLine width=256 expandX=true/>
* <:if:else/>
* <textButton text=@bundleLine width=128/>
* </:if>
* </pre>
*
* </blockquote>This macro finds i18n bundle line mapped to "bundleLine" and checks if its longer than 100 chars. If it
* is, it creates a bigger, expanding button. Otherwise, creates a smaller button.
*
* <blockquote>
*
* <pre>
* <:if ($action = (--{for:index})) || ({marker} = continue)>
* </pre>
*
* </blockquote>This condition evaluates to true if result of method mapped to "action" equals decremented "for:index"
* argument value or if the "marker" argument equals ignore case "continue" string. As you can see, parenthesis support
* is available.
*
* <p>
* This macro can also be used with named attributes: <blockquote>
*
* <pre>
* <:if test="{loop:index}%4=0">
* <label row="true"/>
* </:if>
* </pre>
*
* </blockquote>
*
* @author MJ */
public class ConditionalLmlMacroTag extends AbstractConditionalLmlMacroTag {
public ConditionalLmlMacroTag(final LmlParser parser, final LmlTag parentTag, final StringBuilder rawTagData) {
super(parser, parentTag, rawTagData);
}
@Override
protected boolean checkCondition() {
if (GdxArrays.isEmpty(getAttributes())) {
return false;
}
final String conditionContent = hasAttribute(TEST_ATTRIBUTE) ? getAttribute(TEST_ATTRIBUTE)
: convertAttributesToEquation();
return new Equation(getParser(), getActor()).getBooleanResult(conditionContent);
}
}