package com.github.czyzby.lml.parser.impl; import com.badlogic.gdx.utils.ObjectMap; import com.github.czyzby.kiwi.util.gdx.asset.lazy.provider.ObjectProvider; import com.github.czyzby.kiwi.util.gdx.collection.GdxMaps; import com.github.czyzby.kiwi.util.gdx.collection.immutable.ImmutableObjectMap; import com.github.czyzby.kiwi.util.gdx.collection.lazy.LazyObjectMap; import com.github.czyzby.lml.parser.LmlSyntax; import com.github.czyzby.lml.parser.LssSyntax; import com.github.czyzby.lml.parser.tag.LmlActorBuilder; import com.github.czyzby.lml.parser.tag.LmlAttribute; import com.github.czyzby.lml.parser.tag.LmlBuildingAttribute; import com.github.czyzby.lml.parser.tag.LmlTagProvider; import com.github.czyzby.lml.util.collection.IgnoreCaseStringMap; /** This is a semi-abstract class that implements all {@link LmlSyntax} methods. Returns standard (default) values for * all markers. Implements internal mechanisms of storing tag and attribute providers, but registers none: while this * syntax recognizes all LML markers, it does not know about any tags, attributes or macros by default. Using this * syntax directly allows you to manually choose which tags and attributes are supported, optimizing * * @author MJ * @see DefaultLmlSyntax */ public class EmptyLmlSyntax implements LmlSyntax { /** Key: tag name (ignoring case); value: tag provider. */ private final ObjectMap<String, LmlTagProvider> tagProviders = new IgnoreCaseStringMap<LmlTagProvider>(); /** Key: tag name (ignoring case); value: macro tag provider. */ private final ObjectMap<String, LmlTagProvider> macroTagProviders = new IgnoreCaseStringMap<LmlTagProvider>(); /** Key: class of actor; value: map with attributes assigned to the widget (key: attribute name, ignoring case). */ private final ObjectMap<Class<?>, ObjectMap<String, LmlAttribute<?>>> attributeProcessors = getLazyMapOfIgnoreCaseMaps(); /** Key: class of actor builder; value: map with building attributes assigned to the builder (key: attribute name, * ignoring case, value: processor). */ private final ObjectMap<Class<?>, ObjectMap<String, LmlBuildingAttribute<?>>> buildingAttributeProcessors = getLazyMapOfIgnoreCaseMaps(); private final LssSyntax lssSyntax = createLssSyntax(); /** @return a new instance of object map storing maps with keys as values, ignoring their case. Utility provider. * @param <Key> type of map keys. * @param <Value> type of stored maps values. */ protected static <Key, Value> ObjectMap<Key, ObjectMap<String, Value>> getLazyMapOfIgnoreCaseMaps() { // This map returns a new IgnoreCaseStringMap on each get(Key) call if there is no map assigned to the passed // key. This is very convenient for maps of collections, as you do not have to go through the whole lazy // initiation process. return LazyObjectMap.newMap(new ObjectProvider<ObjectMap<String, Value>>() { @Override public ObjectMap<String, Value> provide() { return new IgnoreCaseStringMap<Value>(); } }); } /** @return {@link LssSyntax} implementation. */ protected LssSyntax createLssSyntax() { return new DefaultLssSyntax(); } @Override public LssSyntax getLssSyntax() { return lssSyntax; } // Warning: before any syntax changes, make sure that LmlUtilities are also updated. @Override public char getTagOpening() { return '<'; } @Override public char getTagClosing() { return '>'; } @Override public char getClosedTagMarker() { return '/'; } @Override public char getCommentOpening() { return '!'; } @Override public char getSchemaCommentMarker() { return '?'; } @Override public char getCommentClosing() { return '-'; } @Override public String getDocumentTypeOpening() { return "DOCTYPE"; } @Override public char getArgumentOpening() { return '{'; } @Override public char getArgumentClosing() { return '}'; } @Override public char getMacroMarker() { return ':'; } @Override public char getIdSeparatorMarker() { return '.'; } @Override public char getPreferenceMarker() { return '#'; } @Override public char getBundleLineMarker() { return '@'; } @Override public char getBundleLineArgumentMarker() { return '|'; } @Override public char getAttributeSeparator() { return '='; } @Override public char getMethodInvocationMarker() { return '$'; } @Override public char getArrayElementSeparator() { return ';'; } @Override public char getRangeArrayOpening() { return '['; } @Override public char getRangeArraySeparator() { return ','; } @Override public char getRangeArrayClosing() { return ']'; } @Override public char getEquationMarker() { return '='; } @Override public char getConditionMarker() { return '?'; } @Override public char getTernaryMarker() { return ':'; } @Override public LmlTagProvider getTagProvider(final String tagName) { return tagProviders.get(tagName); } @Override public void addTagProvider(final LmlTagProvider provider, final String... supportedTagNames) { for (final String name : supportedTagNames) { tagProviders.put(name, provider); } } @Override public void removeTagProvider(final String tagName) { tagProviders.remove(tagName); } @Override public LmlTagProvider getMacroTagProvider(final String tagName) { return macroTagProviders.get(tagName); } @Override public void addMacroTagProvider(final LmlTagProvider provider, final String... supportedTagNames) { for (final String name : supportedTagNames) { macroTagProviders.put(name, provider); } } @Override public void removeMacroTagProvider(final String tagName) { macroTagProviders.remove(tagName); } @Override @SuppressWarnings("unchecked") public <Actor> LmlAttribute<Actor> getAttributeProcessor(final Actor forActor, final String attributeName) { return (LmlAttribute<Actor>) getAttributeProcessor(forActor.getClass(), attributeName); } @Override @SuppressWarnings("unchecked") public <Actor> LmlAttribute<Actor> getAttributeProcessor(final Class<Actor> forActorType, final String attributeName) { Class<?> actorClass = forActorType; while (actorClass != null) { if (attributeProcessors.containsKey(actorClass)) { final ObjectMap<String, LmlAttribute<?>> processors = attributeProcessors.get(actorClass); if (processors.containsKey(attributeName)) { return (LmlAttribute<Actor>) processors.get(attributeName); } } actorClass = actorClass.getSuperclass(); } return null; } @Override public <Actor> void addAttributeProcessor(final LmlAttribute<Actor> attributeProcessor, final String... names) { final ObjectMap<String, LmlAttribute<?>> processors = attributeProcessors .get(attributeProcessor.getHandledType()); for (final String name : names) { processors.put(name, attributeProcessor); } } @Override public void removeAttributeProcessor(final String name, final Class<?> handledActorType) { attributeProcessors.get(handledActorType).remove(name); } @Override @SuppressWarnings("unchecked") public <Builder extends LmlActorBuilder> LmlBuildingAttribute<Builder> getBuildingAttributeProcessor( final Builder builder, final String attributeName) { Class<?> builderClass = builder.getClass(); while (builderClass != null) { if (buildingAttributeProcessors.containsKey(builderClass)) { final ObjectMap<String, LmlBuildingAttribute<?>> processors = buildingAttributeProcessors .get(builderClass); if (processors.containsKey(attributeName)) { return (LmlBuildingAttribute<Builder>) processors.get(attributeName); } } builderClass = builderClass.getSuperclass(); } return null; } @Override public <Builder extends LmlActorBuilder> void addBuildingAttributeProcessor( final LmlBuildingAttribute<Builder> buildingAttributeProcessor, final String... names) { final ObjectMap<String, LmlBuildingAttribute<?>> processors = buildingAttributeProcessors .get(buildingAttributeProcessor.getBuilderType()); for (final String name : names) { processors.put(name, buildingAttributeProcessor); } } @Override public void removeBuildingAttributeProcessor(final String name, final Class<?> handledActorType) { buildingAttributeProcessors.get(handledActorType).remove(name); } // DTD utility methods: @Override public ObjectMap<String, LmlAttribute<?>> getAttributesForActor(final Object actor) { final ObjectMap<String, LmlAttribute<?>> attributes = GdxMaps.newObjectMap(); if (actor == null) { return attributes; } Class<?> actorClass = actor.getClass(); while (actorClass != null) { attributes.putAll(attributeProcessors.get(actorClass)); actorClass = actorClass.getSuperclass(); } return attributes; } @Override public ObjectMap<String, LmlBuildingAttribute<?>> getAttributesForBuilder(final LmlActorBuilder builder) { final ObjectMap<String, LmlBuildingAttribute<?>> attributes = GdxMaps.newObjectMap(); if (builder == null) { return attributes; } Class<?> builderClass = builder.getClass(); while (builderClass != null) { attributes.putAll(buildingAttributeProcessors.get(builderClass)); builderClass = builderClass.getSuperclass(); } return attributes; } @Override public ObjectMap<String, LmlTagProvider> getMacroTags() { return ImmutableObjectMap.copyOf(macroTagProviders); } @Override public ObjectMap<String, LmlTagProvider> getTags() { return ImmutableObjectMap.copyOf(tagProviders); } }