/*
 * @(#) $Id: MultipartUtility.java,v 1.5 2001/03/04 13:32:57 shin Exp $
 * $Revision: 1.5 $
 * Copyright (c) 2000 Shin Kinoshita All Rights Reserved.
 */
package com.sk_jp.mail;

import java.io.InputStream;
import java.io.IOException;

import javax.mail.Part;
import javax.mail.Multipart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.activation.DataHandler;

/**
 *
 * <p>
 * </p><p>
 * UnderDevelopment
 * </p>
 * @version $Revision: 1.5 $ $Date: 2001/03/04 13:32:57 $
 * @author Shin
 */
public class MultipartUtility {
    /**
     * 指定パートのボディを返します。
     * <P>
     * Part#getContent()の代わりです。
     * MIMEに準拠しないContent-Type:の補正を行います。
     * charset指定がない場合は"ISO-2022-JP"を補います。
     * </P><P>
     * パートがUTF-7の場合も正常に内容を取得出来ます。
     * </P>
     */
    public static Object getContent(Part part)
                throws MessagingException, IOException {
        return getContent(part, "ISO-2022-JP");
    }

    private static CorrectedContentTypeDataSource correctedDataSource =
            new CorrectedContentTypeDataSourceUTF7Support();
    private static DataHandler correctedDataHandler =
            new DataHandler(correctedDataSource);
    /**
     * 指定パートのボディを返します。
     * <P>
     * MIMEに準拠しないContent-Type:の補正を行います。
     * charset指定がない場合はcharsetで指定されたもので補います。
     * </P><P>
     * パートがUTF-7の場合も正常に内容を取得出来ます。
     * </P>
     */
    public static Object getContent(Part part, String charset)
                throws MessagingException, IOException {
        synchronized (correctedDataSource) {
            correctedDataSource.setPart(part);
            correctedDataSource.setDefaultCharset(charset);

            return correctedDataHandler.getContent();
//          return new DataHandler(correctedDataSource).getContent();
        }
    }

    /**
     * 指定パート配下で最初に見つけたテキストパートのボディを返します。
     * process()を呼び出して結果を返すだけのconvenience methodです。
     */
    public static String getFirstPlainText(Part part)
                throws MessagingException {
        FirstPlainPartExtractor h = new FirstPlainPartExtractor();
        process(part, h);
        return h.getText();
    }

    /**
     * 指定パート配下のinlineなテキストパートを集めて表示用のボディを返します。
     * process()を呼び出して結果を返すだけのconvenience methodです。
     */
    public static String getPlainText(Part part)
                throws MessagingException {
        PlainPartExtractor h = new PlainPartExtractor();
        process(part, h);
        return h.getText();
    }

    /**
     * 指定パート配下の各パートを処理します。
     * <P>
     * すべてのPartに対してPartHandlerが呼び出されます。<BR>
     * </P>
     */
    public static void process(Part part, PartHandler handler)
                throws MessagingException {
        process(part, handler, null);
    }

    private static boolean process(Part part, PartHandler handler,
                                   ContentType context)
                throws MessagingException {
        try {
            if (part.isMimeType("multipart/*")) {
                Multipart mp = (Multipart)part.getContent();
                ContentType cType = new ContentType(part.getContentType());
                for (int i = 0; i < mp.getCount(); i++) {
                    if (!process(mp.getBodyPart(i), handler, cType)) {
                        return false;
                    }
                }
                return true;
            }
            return handler.processPart(part, context);
        } catch (IOException e) {
            throw new MessagingException(
                    "Got exception \nin " + part + "\n", e);
        }
    }


    /**
     * 指定partにbodyPartを追加します。
     * partがマルチパーとコンテナの場合はそのコンテナにbodyPartを追加します。
     * そうでない場合はpartのボディとしてmultipart/mixedのコンテナを設定し、
     * 元のpartのボディとbodyPartのボディをそのコンテナに追加します。
     */
    public static void addBodyPart(Part part, MimeBodyPart bodyPart)
                throws MessagingException, IOException {
        if (part.isMimeType("multipart/*")) {
            ((MimeMultipart)part.getContent()).addBodyPart(bodyPart);
            return;
        }
        // 仮
        MimeMultipart mp = new MimeMultipart("mixed");
        MimeBodyPart original = new MimeBodyPart();
        original.setContent(part.getContent(), part.getContentType());
        mp.addBodyPart(original);
        mp.addBodyPart(bodyPart);
        part.setContent(mp);
    }


    /**
     * partのツリー構造をダンプするデバッグ用メソッドです。
     */
    public static void dump(Part part) {
        dump(part, 0);
    }

    private static void dump(Part part, int layer) {
        for (int i = 0; i < layer; i++) {
            System.out.print("    ");
        }
        try {
            System.out.println(part.getClass() + ":" + part.getContentType());
            if (part.isMimeType("multipart/*")) {
                MimeMultipart mp = (MimeMultipart)part.getContent();
                for (int i = 0; i < mp.getCount(); i++) {
                    dump(mp.getBodyPart(i), layer + 1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

