package hayashi.yuu.tools.mail;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.Vector;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import hayashi.yuu.tools.mail.SiteData;

/**
 * <p>Ｅメールを送信するためのクラス<br/>
 * JavaMailを使用する</p>
 * @see <a href="http://java.sun.com/products/javamail/javadocs/index.html">JavaMail API</a>
 *
 * @author hayashi
 * @version 2010/02/05	SMTPサーバーのポート番号指定を追加
 */
public class SendMail
{
    public static void main(java.lang.String[] args) {
        try {
    		SiteData siteData = new SiteData("sendmail.properties");
			SendMail mail = new SendMail(siteData);
            mail.setSubject("[SendMail] SendMail テスト");
            mail.setContent("本文\n");
            mail.setAttachment(new File("attache.jpg"));
            mail.send();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected Vector<String> toVector = new Vector<String>(); // プロパティ 送信先(to) の値
    protected Vector<String> ccVector = new Vector<String>(); // プロパティ 送信先(Cc) の値
    protected Vector<String> bccVector = new Vector<String>();    // プロパティ 送信先(Bcc) の値
    protected String from = null;         // プロパティ 発信元(from) の値
    protected String subject;             // プロパティ 題名(subject) の値
    protected String content;             // プロパティ 本文(content) の値
    protected String mailHost;            // プロパティ SMTP(mail.smtp.host) の値
    protected String mailHostPort;        // プロパティ SMTP_PORT(mail.smtp.port) の値

    protected Vector<File> attachments = new Vector<File>();	// 添付ファイル
    protected Vector<String> attachNames = new Vector<String>();		// 添付ファイル名

    protected boolean POP_before_SMTP = false;
    protected boolean STARTTLS = false;
    protected boolean USER_AUTH = false;
    protected String popServer = "";
    protected String userId = "";
    protected String password ="";
    protected Session session = null;

    /**
     * 新しい YuuMail　インスタンスを作成する
     * @param mailProp	メール設定ファイルのパス名称
     */
    public SendMail(String mailProp) {
        this(new SiteData(mailProp));
    }

    /**
     * 新しい インスタンスを作成する
     * @param siteData メール設定値を包含したオブジェクト
     */
    public SendMail(SiteData siteData) {
        super();

        if (checkItem(siteData.MAIL_SMTP)) {
            this.setMailHost(siteData.MAIL_SMTP);
        }
        if (checkItem(siteData.MAIL_SMTP_PORT)) {
            this.setMailPort(siteData.MAIL_SMTP_PORT);
        }
        if (checkItem(siteData.MAIL_TO)) {
            this.toVector.add(siteData.MAIL_TO);
        }
        if (checkItem(siteData.MAIL_CC)) {
            this.ccVector.add(siteData.MAIL_CC);
        }
        if (checkItem(siteData.MAIL_BCC)) {
            this.bccVector.add(siteData.MAIL_BCC);
        }
        if (checkItem(siteData.MAIL_FROM)) {
            this.from = siteData.MAIL_FROM;
        }

        this.POP_before_SMTP = siteData.POP_before_SMTP;
        this.STARTTLS = siteData.STARTTLS;
        this.USER_AUTH = siteData.USER_AUTH;
        this.popServer = siteData.MAIL_POP;
        this.userId = siteData.USER_ID;
        this.password = siteData.PASSWORD;

        // メール(MimeMessageオブジェクト)を生成する
        Properties props = System.getProperties();
        props.put("mail.smtp.host", getMailHost());
        props.put("mail.smtp.port", getMailPort());
        if (this.USER_AUTH) {
        	props.put("mail.smtp.auth", "true");
        }
        if (this.STARTTLS) {
        	props.put("mail.smtp.starttls.enable", "true");
        }
        this.session = Session.getDefaultInstance(props, null);
    }
    private boolean checkItem(String itemStr) {
    	if (itemStr == null) {
    		return false;
    	}
    	if (itemStr.trim().equals("")) {
    		return false;
    	}
    	return true;
    }

    /**
     * プロパティ mailHost の取得メソッド。
     * @return プロパティ mailHost の値。
     */
    public String getMailHost() {
        return this.mailHost;
    }

    /**
     * SMTPサーバーを設定
     *  @param mailHost SMTPサーバー名またはSMTPサーバーのIPアドレス
    */
    public void setMailHost(String mailHost) {
        this.mailHost = mailHost;
    }

    /**
     * プロパティ SMTPポート番号 の取得メソッド。
     * @return SMTPポート番号を表す文字列（デシマル）
     */
    public String getMailPort() {
        return this.mailHostPort;
    }

    /**
     * SMTPポート番号を設定
     *  @param portStr SMTPポート番号を表す文字列（デシマル）
     */
    public void setMailPort(String portStr) {
        this.mailHostPort = portStr;
    }

    /**
     * 送信先(To)を設定.数設定可
     * @param to 送信先(To)
     */
    public void setTo(String to) {
        if (!to.equals("")) {
            toVector.addElement(to);
        }
    }

    /**
     * 送信先(Cc)を設定。複数設定可
     * @param cc 送信先(cc)
     */
    public void setCc(String cc) {
        if (!cc.equals("")) {
            ccVector.addElement(cc);
        }
    }

    /**
     * 送信先(Bco)を設定.複数選択可
     * @param bcc 送信先(Bcc)
     */
    public void setBcc(String bcc) {
        if (!bcc.equals("")) {
            bccVector.addElement(bcc);
        }
    }

    /**
     * プロパティ from の取得メソッド。
     * @return プロパティ from の値。
     */
    public String getFrom() {
        return from;
    }

    /**
     * プロパティ 送信元(from) の設定メソッド。
     * @param from 送信元メールアドレス
     */
    public void setFrom(String from) {
        this.from = from;
    }

    /**
     * プロパティ subject の取得メソッド。
     * @return プロパティ subject の値。
     */
    public String getSubject() {
        return subject;
    }

    /**
     * プロパティ 題名（subject） の設定メソッド。
     * メールタイトル（題名）を設定
     * @param subject メールタイトル（題名）
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * 本文(content)の取得メソッド。
     * @return 本文の値。
     */
    public String getContent() {
        return this.content;
    }

    /**
     * 本文(content)の設定メソッド。
     * 本文(content)を設定
     * @param content 本文(content)
     */
    public void setContent(String content) {
        this.content = content;
    }

    /**
     * 添付ファイルの設定メソッド。
     * 添付するファイル(attachment)を設定.添付ファイルは複数設定可。
     * @param attachment 添付するファイル(attachment)
     * @throws FileNotFoundException 添付するファイルが見つからなかった。
     */
    @SuppressWarnings("resource")
	public void setAttachment(File attachment) throws FileNotFoundException {
    	new FileInputStream(attachment);    // ファイルが実存することをチェックする。
        attachments.addElement(attachment);
        attachNames.addElement(attachment.getName());
    }

    /**
     * 添付ファイルの設定メソッド。
     * 添付するファイル(attachment)を設定.添付ファイルは複数設定可。
     * @param attachment 添付するファイル(attachment)
     * @param name 添付するファイルの表示名
     * @throws FileNotFoundException 添付するファイルが見つからなかった。
     */
     @SuppressWarnings("resource")
	public void setAttachment(File attachment, String name) throws FileNotFoundException {
         new FileInputStream(attachment);    // ファイルが実存することをチェックする。
         attachments.addElement(attachment);
         attachNames.addElement(name);
     }

    /**
     * メールを送信
     * @throws MessagingException エラー：メールの送信に失敗しました。
     * @throws UnsupportedEncodingException エラー：メールの文字エンコードに失敗しました。
     */
    public void send() throws MessagingException, UnsupportedEncodingException {
        //-------------------------
        // POP before SMTP 対応
        //--
        Store store = null;
        if (this.POP_before_SMTP == true) {
	        System.out.println("store.connect('"+ popServer +"', '"+ userId +"', '"+ password +"')");
	        store = this.session.getStore("pop3");
	        store.connect(popServer, userId, password);
        }
        else {
        	System.out.println("no POP_before_SMTP!");
        }

        MimeMessage message = createMessage();

        if (this.USER_AUTH) {
        	System.out.println("transport.connect(null, '"+ userId +"', '"+ password+"')");
            Transport transport = this.session.getTransport("smtp");
        	transport.connect(null, userId, password);
        	Address[] addrs = message.getAllRecipients();
        	for (Address addr : addrs) {
        		System.out.println("[Addr] "+ addr.toString());
        	}
            transport.sendMessage(message, message.getAllRecipients());
        }
        else {
        	System.out.println("no SMTP_AUTH!");
        	Transport.send(message);
        }

        if (this.POP_before_SMTP == true) {
            store.close();
        }
    }

    /**
     * 新規にメールインスタンスを生成する。
     * @return	メールインスタンス
     * @throws MessagingException メール送信に失敗しました。
     * @throws UnsupportedEncodingException 文字エンコーディングに失敗した。
     */
    protected MimeMessage createMessage() throws MessagingException, UnsupportedEncodingException {
        MimeMessage msg = new MimeMessage(this.session);

        // 送信先(To)
        InternetAddress[] toList = new InternetAddress[toVector.size()];
        for (int i=0; i < toVector.size(); i++) {
            toList[i] = new InternetAddress(toVector.elementAt(i));
        }
        msg.setRecipients(Message.RecipientType.TO, toList);

        // 送信先(Cc)
        InternetAddress[] ccList = new InternetAddress[ccVector.size()];
        for (int i=0; i < ccVector.size(); i++) {
            ccList[i] = new InternetAddress(ccVector.elementAt(i));
        }
        msg.setRecipients(Message.RecipientType.CC, ccList);

        // 送信先(Bcc)
        InternetAddress[] bccList = new InternetAddress[bccVector.size()];
        for (int i=0; i < bccVector.size(); i++) {
            bccList[i] = new InternetAddress(bccVector.elementAt(i));
        }
        msg.setRecipients(Message.RecipientType.BCC, bccList);

        // 送信元(From)
        msg.setFrom(new InternetAddress(getFrom()));

        // 件名(Subject)
        msg.setSubject(MimeUtility.encodeText(getSubject(), "iso-2022-jp", "B"));

        // 本文(Content)
        MimeMultipart naiyou = new MimeMultipart();
        msg.setContent(naiyou);

        MimeBodyPart honbun = new MimeBodyPart();
        honbun.setContent(getContent(), "text/plain; charset=\"iso-2022-jp\"");
        naiyou.addBodyPart(honbun);

        // 添付(Attachment)
        for (int i=0; i < attachments.size(); i++) {
            File attachFile = attachments.elementAt(i);
            MimeBodyPart tenpu = new MimeBodyPart();
            javax.activation.FileDataSource dfs = new javax.activation.FileDataSource(attachFile);
            javax.activation.DataHandler dh = new javax.activation.DataHandler(dfs);
            tenpu.setDataHandler(dh);
            tenpu.setFileName(attachNames.elementAt(i));
            naiyou.addBodyPart(tenpu);
        }

        return msg;
    }
}
