package com.ozacc.mail.xml.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.mail.internet.InternetAddress;

import org.jdom.CDATA;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.DOMOutputter;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import com.ozacc.mail.Mail;
import com.ozacc.mail.xml.XMLBuildException;
import com.ozacc.mail.xml.XMLBuilder;

/**
 * XMLBuilderの実装クラス。
 * 
 * @since 1.0
 * @author Tomohiro Otsuka
 * @version $Id: JDomXMLBuilder.java,v 1.6 2004/09/18 00:39:17 otsuka Exp $
 */
public class JDomXMLBuilder implements XMLBuilder {

	public static final String DOCTYPE_PUBLIC = "-//OZACC//DTD MAIL//EN";

	public static final String DOCTYPE_SYSTEM = "http://www.ozacc.com/library/dtd/ozacc-mail.dtd";

	private String charset = "UTF-8";

	/**
	 * コンストラクタ。
	 */
	public JDomXMLBuilder() {}

	/**
	 * コンストラクタ。
	 * 出力XMLファイルの文字コードを指定します。デフォルトはUTF-8。
	 * 
	 * @param charset 出力XMLファイルの文字コード
	 */
	public JDomXMLBuilder(String charset) {
		this();
		setCharset(charset);
	}

	/**
	 * 出力XMLファイルの文字コードを指定します。デフォルトはUTF-8。
	 * 
	 * @param charset 出力XMLファイルの文字コード
	 */
	public void setCharset(String charset) {
		this.charset = charset;
	}

	/**
	 * 出力XMLファイルの文字コードを返します。
	 * 
	 * @return 出力XMLファイルの文字コード
	 */
	public String getCharset() {
		return charset;
	}

	/**
	 * @see com.ozacc.mail.xml.XMLBuilder#buildDocument(com.ozacc.mail.Mail)
	 */
	public org.w3c.dom.Document buildDocument(Mail mail) throws XMLBuildException {
		Document doc = buildJDomDocument(mail);
		DOMOutputter outputter = new DOMOutputter();
		try {
			return outputter.output(doc);
		} catch (JDOMException e) {
			throw new XMLBuildException("DOM Documentの生成に失敗しました。", e);
		}
	}

	/**
	 * 指定されたMailインスタンスからJDOMドキュメントを生成します。
	 * 
	 * @return 生成されたJDOMドキュメント
	 */
	public Document buildJDomDocument(Mail mail) {

		Element mailElem = new Element("mail");

		// Return-Path
		if (mail.getReturnPath() != null) {
			InternetAddress returnPath = mail.getReturnPath();
			Element returnPathElem = convertInternetAddressIntoElement(returnPath, "returnPath");
			mailElem.addContent(returnPathElem);
		}

		// From
		if (mail.getFrom() != null) {
			InternetAddress from = mail.getFrom();
			Element fromElem = convertInternetAddressIntoElement(from, "from");
			mailElem.addContent(fromElem);
		}

		if (mail.getTo().length > 0 || mail.getCc().length > 0 || mail.getBcc().length > 0) {
			Element recipientsElem = new Element("recipients");

			// To
			if (mail.getTo().length > 0) {
				for (int i = 0; i < mail.getTo().length; i++) {
					InternetAddress to = mail.getTo()[i];
					Element toElem = convertInternetAddressIntoElement(to, "to");
					recipientsElem.addContent(toElem);
				}
			}
			// Cc
			if (mail.getCc().length > 0) {
				for (int i = 0; i < mail.getCc().length; i++) {
					InternetAddress cc = mail.getCc()[i];
					Element ccElem = convertInternetAddressIntoElement(cc, "cc");
					recipientsElem.addContent(ccElem);
				}
			}
			// Bcc
			if (mail.getBcc().length > 0) {
				for (int i = 0; i < mail.getBcc().length; i++) {
					InternetAddress bcc = mail.getBcc()[i];
					Element bccElem = convertInternetAddressIntoElement(bcc, "bcc");
					recipientsElem.addContent(bccElem);
				}
			}
			mailElem.addContent(recipientsElem);
		}

		// Reply-To
		if (mail.getReplyTo() != null) {
			InternetAddress replyTo = mail.getReplyTo();
			Element replyToElem = convertInternetAddressIntoElement(replyTo, "replyTo");
			mailElem.addContent(replyToElem);
		}

		// Subject
		if (mail.getSubject() != null) {
			Element subjectElem = new Element("subject");
			subjectElem.setText(mail.getSubject());
			mailElem.addContent(subjectElem);
		}

		// Body
		if (mail.getText() != null) {
			Element textElem = new Element("body");
			textElem.setText(mail.getText());
			mailElem.addContent(textElem);
		}

		// Html
		if (mail.isHtmlMail()) {
			Element htmlElem = new Element("html");
			htmlElem.setContent(new CDATA(mail.getHtmlText()));
			mailElem.addContent(htmlElem);
		}

		Document doc = new Document(mailElem);
		DocType docType = new DocType("mail", DOCTYPE_PUBLIC, DOCTYPE_SYSTEM);
		doc.setDocType(docType);
		return doc;
	}

	/**
	 * 
	 * @param address
	 * @param elemName
	 * @return
	 */
	private Element convertInternetAddressIntoElement(InternetAddress address, String elemName) {
		Element element = new Element(elemName);
		element.setAttribute("email", address.getAddress());
		if (address.getPersonal() != null) {
			element.setAttribute("name", address.getPersonal());
		}
		return element;
	}

	/**
	 * @see com.ozacc.mail.xml.XMLBuilder#saveDocument(com.ozacc.mail.Mail, java.io.File)
	 */
	public void saveDocument(Mail mail, File destFile) throws XMLBuildException {
		// JDOM Documentを生成
		Document doc = buildJDomDocument(mail);

		// ファイル出力
		try {
			FileOutputStream fos = new FileOutputStream(destFile);
			XMLOutputter outputter = getXMLOutputter();
			outputter.output(doc, fos);
			fos.close();
		} catch (IOException e) {
			throw new XMLBuildException("DOM Documentのファイル出力に失敗しました。", e);
		}
	}

	public XMLOutputter getXMLOutputter() {
		Format format = Format.getPrettyFormat();
		format.setEncoding(charset);
		XMLOutputter outputter = new XMLOutputter(format);
		return outputter;
	}
}