package org.jboss.resteasy.plugins.providers.multipart;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

import org.jboss.resteasy.plugins.providers.multipart.i18n.LogMessages;
import org.jboss.resteasy.plugins.providers.multipart.i18n.Messages;

/**
 * Utility class to help generate, convert RFC compliant Content-ID and cid.
 *
 * @author Attila Kiraly
 *
 */
public class ContentIDUtils {
    public static final String CID_URL_SCHEME = "cid:";

    /**
     * Calls {@link #generateContentIDFromAddrSpec(String)} with
     * {@link #generateRFC822AddrSpec()} as parameter.
     *
     * @return the generated Content-ID
     */
    public static String generateContentID() {
        return generateContentIDFromAddrSpec(generateRFC822AddrSpec());
    }

    /**
     * Helper method to generate a standards-compliant Content-ID header value
     * from the supplied addrSpec.
     *
     * Used rfc-s: RFC2045, RFC822
     *
     * @param addrSpec addrSpec
     * @return the generated Content-ID
     */
    public static String generateContentIDFromAddrSpec(String addrSpec) {
        return "<" + addrSpec + ">";
    }

    /**
     * Helper method to generate a standards-compliant, random addr-spec as
     * described in RFC822.
     *
     * @return the generated addrSpec
     */
    public static String generateRFC822AddrSpec() {
        return UUID.randomUUID().toString() + "@resteasy-multipart";
    }

    /**
     * Helper method to generate a standards-compliant cid url from the supplied
     * addrSpec. This implementation URL encodes everything without considering
     * if it is needed or not.
     *
     * Used rfc-s: RFC2392, RFC822
     *
     * @param addrSpec addrSpec
     * @return the generated Content-ID
     */
    public static String generateCidFromAddrSpec(String addrSpec) {
        String cid = CID_URL_SCHEME;
        try {
            cid += URLEncoder.encode(addrSpec, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            LogMessages.LOGGER.error(Messages.MESSAGES.urlEncoderDoesNotSupportUtf8(), e);
        }
        return cid;
    }

    /**
     * @param cid
     *            the RFC2392 compliant cid
     * @return the RFC822 defined addr-spec decoded from the cid
     */
    public static String parseAddrSpecFromCid(String cid) {
        String addrSpec = cid.trim();
        if (addrSpec.startsWith(CID_URL_SCHEME))
            addrSpec = addrSpec.substring(CID_URL_SCHEME.length()).trim();

        try {
            addrSpec = URLDecoder.decode(addrSpec, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            LogMessages.LOGGER.error(Messages.MESSAGES.urlDecoderDoesNotSupportUtf8(), e);
        }

        return addrSpec;
    }

    /**
     * @param contentID
     *                  the RFC2045 compliant Content-ID
     * @return the RFC822 defined addr-spec decoded from the contentID
     */
    public static String parseAddrSpecFromContentID(String contentID) {
        String addrSpec = contentID.trim();

        if (addrSpec.startsWith("<") && addrSpec.endsWith(">"))
            addrSpec = addrSpec.substring(1, addrSpec.length() - 1).trim();

        return addrSpec;
    }

    /**
     * @param cid
     *            the RFC2392 compliant cid
     * @return the RFC2045 compliant Content-ID representing the cid
     */
    public static String convertCidToContentID(String cid) {
        return generateContentIDFromAddrSpec(parseAddrSpecFromCid(cid));
    }

    /**
     * @param contentID
     *                  the RFC2045 compliant Content-ID
     * @return the RFC2392 compliant cid representing the contentID
     */
    public static String convertContentIDToCid(String contentID) {
        return generateCidFromAddrSpec(parseAddrSpecFromContentID(contentID));
    }
}
