1package im.conversations.android.xmpp.model.stanza;
  2
  3import com.google.common.base.Joiner;
  4import com.google.common.base.Strings;
  5import com.google.common.collect.ImmutableMultimap;
  6import com.google.common.collect.Iterables;
  7import com.google.common.collect.Maps;
  8import eu.siacs.conversations.Config;
  9import eu.siacs.conversations.xml.Element;
 10import eu.siacs.conversations.xml.LocalizedContent;
 11import im.conversations.android.annotation.XmlElement;
 12import im.conversations.android.xmpp.model.Extension;
 13import im.conversations.android.xmpp.model.jabber.Body;
 14import im.conversations.android.xmpp.model.jabber.Subject;
 15import java.util.Locale;
 16
 17@XmlElement
 18public class Message extends Stanza {
 19
 20    public Message() {
 21        super(Message.class);
 22    }
 23
 24    public Message(Type type) {
 25        this();
 26        this.setType(type);
 27    }
 28
 29    public LocalizedContent getBody() {
 30        return getLocalizedContent(Body.class);
 31    }
 32
 33    public LocalizedContent getSubject() {
 34        return getLocalizedContent(Subject.class);
 35    }
 36
 37    private LocalizedContent getLocalizedContent(final Class<? extends Extension> clazz) {
 38        final var builder = new ImmutableMultimap.Builder<String, String>();
 39        final var messageLanguage = this.getAttribute("xml:lang");
 40        final var parentLanguage =
 41                Strings.isNullOrEmpty(messageLanguage)
 42                        ? LocalizedContent.STREAM_LANGUAGE
 43                        : messageLanguage;
 44        for (final var element : this.getExtensions(clazz)) {
 45            final var elementLanguage = element.getAttribute("xml:lang");
 46            final var language =
 47                    Strings.isNullOrEmpty(elementLanguage) ? parentLanguage : elementLanguage;
 48            final var content = element.getContent();
 49            if (content == null) {
 50                continue;
 51            }
 52            builder.put(language, content);
 53        }
 54        final var multiMap = builder.build().asMap();
 55        if (Config.TREAT_MULTI_CONTENT_AS_INVALID
 56                && Iterables.any(multiMap.values(), v -> v.size() > 1)) {
 57            return null;
 58        }
 59        return LocalizedContent.get(Maps.transformValues(multiMap, v -> Joiner.on('\n').join(v)));
 60    }
 61
 62    public Type getType() {
 63        final var value = this.getAttribute("type");
 64        if (value == null) {
 65            return Type.NORMAL;
 66        } else {
 67            try {
 68                return Type.valueOf(value.toUpperCase(Locale.ROOT));
 69            } catch (final IllegalArgumentException e) {
 70                return null;
 71            }
 72        }
 73    }
 74
 75    public void setType(final Type type) {
 76        if (type == null || type == Type.NORMAL) {
 77            this.removeAttribute("type");
 78        } else {
 79            this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
 80        }
 81    }
 82
 83    public void setBody(final String text) {
 84        removeChild(findChild("body"));
 85        this.addExtension(new Body(text));
 86    }
 87
 88    public void setAxolotlMessage(Element axolotlMessage) {
 89        removeChild(findChild("body"));
 90        prependChild(axolotlMessage);
 91    }
 92
 93    public enum Type {
 94        ERROR,
 95        NORMAL,
 96        GROUPCHAT,
 97        HEADLINE,
 98        CHAT
 99    }
100}