package org.maachang.comet.httpd.engine.script.service.mail;

import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
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 javax.mail.util.ByteArrayDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.httpd.HttpdVersionDef;
import org.maachang.util.StringUtil;

/**
 * メール送信サービス.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class SendMailService {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( SendMailService.class ) ;
    
    /**
     * メールキャラクターセット.
     */
    private static final String CHARSET = "ISO-2022-JP" ;
    
    /**
     * メールを送信.
     * <BR><BR>
     * 対象の条件でメールを送信します.
     * <BR>
     * @param sendMail 送信条件を設定します.
     * @return boolean 送信結果が返されます.
     */
    public static final boolean sendMailTo( SendMail sendMail ) {
        try {
            sendMail( sendMail ) ;
        } catch( Exception e ) {
            LOG.error( "sendMailError",e ) ;
            return false ;
        }
        return true ;
    }
    
    /**
     * メールを送信.
     * <BR><BR>
     * 対象の条件でメールを送信します.
     * <BR>
     * @param sendMail 送信条件を設定します.
     * @exception Exception 例外.
     */
    public static final void sendMail( SendMail sendMail )
        throws Exception {
        if( sendMail == null || sendMail.check() == false ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        
        Properties props = new Properties() ;
        props.put( "mail.smtp.host",sendMail.getHost() ) ;
        if( sendMail.getPort() > 0 ) {
            props.put( "mail.smtp.port", String.valueOf( sendMail.getPort() ) ) ;
        }
        
        // タイムアウト設定.
        if( sendMail.getTimeout() > 0L ) {
            props.setProperty( "mail.smtp.connectiontimeout", String.valueOf( sendMail.getTimeout() ) ) ;
            props.setProperty( "mail.smtp.timeout", String.valueOf( sendMail.getTimeout() ) ) ;
        }
        
        // SSL接続.
        if( sendMail.isSsl() == true ) {
            props.setProperty( "mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory" );
            props.setProperty( "mail.smtp.socketFactory.fallback", "false" );
            if( sendMail.getPort() > 0 ) {
                props.setProperty( "mail.smtp.socketFactory.port", String.valueOf( sendMail.getPort() ) );
            }
        }
        
        Session session = null ;
        
        // 認証あり.
        if( sendMail.isAuth() == true ) {
            props.setProperty( "mail.smtp.auth", "true" ) ;
            session = Session.getInstance( props, new MailAuth( sendMail.getUser(),sendMail.getPasswd() ) ) ;
        }
        // 認証なし.
        else {
            session = Session.getInstance( props, null ) ;
        }
        
        //session.setDebug(true);
        
        try {
            
            // 送信データ生成.
            Message msg = new MimeMessage( session ) ;
            msg.setFrom( new InternetAddress( sendMail.getFrom() ) ) ;
            InternetAddress[] address = getTo( sendMail ) ;
            msg.setRecipients( Message.RecipientType.TO, address ) ;
            msg.setSubject( MimeUtility.encodeText( convertSJIS( sendMail.getSubject() ), CHARSET, "B" ) ) ;
            msg.setHeader("Content-Type","text/plain; charset="+CHARSET);
            msg.setHeader( "Content-Transfer-Encoding", "7bit" ) ;
            msg.setHeader( "X-Mailer",HttpdVersionDef.getServerName() ) ;
            
            Multipart multipart = new MimeMultipart() ;
            MimeBodyPart textPart = new MimeBodyPart() ;
            textPart.setText( convertSJIS( sendMail.getBody() )+"\r\n",CHARSET ) ;
            textPart.setHeader( "Content-Transfer-Encoding", "7bit" ) ;
            textPart.setHeader( "Content-Type", "text/plain; charset=\""+CHARSET+"\"" ); 
            multipart.addBodyPart( textPart ) ;
            
            // 添付内容ありのメールメッセージ.
            if( sendMail.getAttached() != null && sendMail.getAttached().size() > 0 ) {
                ArrayList<ResultAttached> lst = sendMail.getAttached() ;
                BodyPart attachmentPart = new MimeBodyPart() ;
                int len = lst.size() ;
                for( int i = 0 ; i < len ; i ++ ) {
                    ResultAttached ra = lst.get( i ) ;
                    if( ra != null && ra.getAttached() != null && ra.getAttached().length > 0 ) {
                        ByteArrayDataSource ba = new ByteArrayDataSource(
                            ra.getAttached(),"application/octet-stream" ) ;
                        attachmentPart.setDataHandler( new DataHandler( ba ) ) ;
                        if( ra.getFileName() != null && ra.getFileName().length() > 0 ) {
                            attachmentPart.setFileName(
                                MimeUtility.encodeText( ra.getFileName(), CHARSET, null ) ) ;
                        }
                        multipart.addBodyPart( attachmentPart ) ;
                    }
                }
            }
            msg.setContent( multipart ) ;
            
            // 送信処理.
            msg.setSentDate( new Date() );
            Transport.send(msg) ;
            
        } catch( Exception e ){
            throw e ;
        }
    }
    
    /**
     * 送信先の情報を生成.
     */
    private static InternetAddress[] getTo( SendMail sendMail )
        throws Exception {
        int len = sendMail.getTo().size() ;
        InternetAddress[] ret = new InternetAddress[ len ] ;
        for( int i = 0 ; i < len ; i ++ ) {
            ret[ i ] = new InternetAddress( sendMail.getTo().get( i ) ) ;
        }
        return ret ;
    }
    
    /**
     * デフォルトエンコードがWindows31Jの場合、文字化け変換を行う.
     */
    private static final String convertSJIS( String body ) {
        if( body == null ) {
            return "" ;
        }
        if( "MS932".equals( System.getProperty("file.encoding") ) ) {
            return StringUtil.toSJIS( body ) ;
        }
        return body ;
    }
    
}

