package org.jivesoftware.smackx.ikey.element;

import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.util.EqualsUtil;
import org.jivesoftware.smack.util.HashCode;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.ikey.provider.SubordinateListElementProvider;

import java.io.IOException;

public class SignedElement implements NamedElement {

    public static final String ELEMENT = "signed";

    private final String base64Encoded;
    private final SubordinateListElement childElement;
    private final byte[] utf8Bytes;

    public SignedElement(SubordinateListElement childElement) {
        this(childElement, null);
    }

    public SignedElement(String base64Encoded) throws IOException, XmlPullParserException, SmackParsingException {
        this(SubordinateListElementProvider.INSTANCE.parse(
                PacketParserUtils.getParserFor(Base64.decodeToString(base64Encoded))),
                base64Encoded);
    }

    private SignedElement(SubordinateListElement childElement, String base64Encoded) {
        this.childElement = Objects.requireNonNull(childElement);
        this.base64Encoded = base64Encoded == null ? childElement.toBase64EncodedString() : base64Encoded;
        this.utf8Bytes = Base64.decode(this.base64Encoded);
    }

    public String getBase64Encoded() {
        return base64Encoded;
    }

    public byte[] getUtf8Bytes() {
        return utf8Bytes;
    }

    public SubordinateListElement getChildElement() {
        return childElement;
    }

    @Override
    public String getElementName() {
        return ELEMENT;
    }

    @Override
    public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
        return new XmlStringBuilder(this)
                .rightAngleBracket()
                .append(getBase64Encoded())
                .closeElement(this);
    }

    @Override
    public int hashCode() {
        return HashCode.builder()
                .append(getElementName())
                .append(getBase64Encoded())
                .build();
    }

    @Override
    public boolean equals(Object other) {
        return EqualsUtil.equals(this, other, (e, o) -> e
                .append(getElementName(), o.getElementName())
                .append(getBase64Encoded(), o.getBase64Encoded()));
    }
}
