package jp.agentec.sinaburocast.logic;

import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.transaction.UserTransaction;

import jp.agentec.sinaburocast.common.util.PropertyUtil;
import jp.agentec.sinaburocast.common.util.SinaburoUtil;
import jp.agentec.sinaburocast.entity.EnqueteMail;
import jp.agentec.sinaburocast.entity.EnqueteMailSendResult;
import jp.agentec.sinaburocast.entity.NotifyMailSendResult;
import jp.agentec.sinaburocast.enumration.ErrorMailStatus;
import jp.agentec.sinaburocast.enumration.ErrorMailStatus.SmtpErrorType;
import jp.agentec.sinaburocast.enumration.ErrorMailStatus.SmtpStatusType;
import jp.agentec.sinaburocast.service.EnqueteMailSendResultService;
import jp.agentec.sinaburocast.service.EnqueteMailService;
import jp.agentec.sinaburocast.service.NotifyMailSendResultService;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.seasar.framework.container.annotation.tiger.Component;
import org.seasar.framework.container.annotation.tiger.InstanceType;

@Component(instance=InstanceType.PROTOTYPE)
public class ErrorMailCheckBatchLogic {
	private final Logger logger = Logger.getLogger(getClass());

	public EnqueteMailSendResultService enqueteMailSendResultService;
	public NotifyMailSendResultService notifyMailSendResultService;

	public EnqueteMailService enqueteMailService;

	public UserTransaction userTransaction;

	@TransactionAttribute(TransactionAttributeType.NEVER)
	public void errMailCheck(String insId) throws Exception{

		String pop3host = PropertyUtil.getProperty("SMTP_HOST");
		String pop3userid = PropertyUtil.getProperty("MAIL_FROM_USER");
		String pop3pass = PropertyUtil.getProperty("MAIL_FROM_PASS");

		Properties props = System.getProperties();
		Session session = Session.getDefaultInstance(props, null);
		session.setDebug(PropertyUtil.getBoolean("JAVA_MAIL_DEBUG"));

		Store store = null;
		Folder folder = null;
		try{
			
			store = session.getStore("pop3");
			store.connect(pop3host, pop3userid, pop3pass);
			
			folder = store.getFolder("INBOX");
			folder.open(Folder.READ_WRITE);

			// メッセージ一覧を取得
			final Message messages[] = folder.getMessages();
			logger.info("folder.getMessages():" + messages.length);

			for (int index = 0; index < messages.length; index++) {
				final Message message = messages[index];

				boolean isTransaction = false;
				try {
					String messageId = null;
					String status = null;
					SmtpErrorType smtpErrorType = SmtpErrorType.ERR_999;
					SmtpStatusType smtpStatusType = SmtpStatusType.Status_999;

					if (message.getFrom() == null || message.getFrom().length == 0) {
						logger.warn("No From header. Ignored.");
						message.setFlag(Flags.Flag.DELETED, true);
						continue;
					}

					final InternetAddress addrFrom = (InternetAddress) message.getFrom()[0];
					//logger.info("addrFrom.getAddress():" + addrFrom.getAddress());
					
					if (addrFrom.getAddress().indexOf("MAILER-DAEMON") < 0) {
						message.setFlag(Flags.Flag.DELETED, true);
						continue;
					}

					final Object objContent = message.getContent();
					if (objContent instanceof Multipart) {
						final Multipart multiPart = (Multipart) objContent;
						for (int indexPart = 0; indexPart < multiPart.getCount(); indexPart++) {
							final Part part = multiPart.getBodyPart(indexPart);
							final String disposition = part.getDisposition();
							if (!Part.ATTACHMENT.equals(disposition) && !Part.INLINE.equals(disposition)) {

								InputStreamReader reader = null;
								
								StringBuilder builder;
								try {
									reader = new InputStreamReader(part.getInputStream());
									builder = new StringBuilder();
									char[] buf = new char[1024];
									int numRead;
									while (0 <= (numRead = reader.read(buf))) {
										builder.append(buf, 0, numRead);
									}
								} finally {
									if (reader != null) {
										//logger.info("reader.close()");
										reader.close();
									}
								}
								
								Pattern pattern = Pattern.compile("^Message-ID:(.*)$", Pattern.MULTILINE);
								Matcher matcher = pattern.matcher(builder.toString());
								if (matcher.find()) {
									messageId = matcher.group(1).trim();
								}

								pattern = Pattern.compile("^Status:(.*)$", Pattern.MULTILINE);
								matcher = pattern.matcher(builder.toString());
								if (matcher.find()) {
									status = matcher.group(1).trim();
									smtpStatusType = ErrorMailStatus.SmtpStatusType.toEnum(status);
								}

								if (smtpErrorType.getCode() == SmtpErrorType.ERR_999.getCode()) {
									smtpErrorType = ErrorMailStatus.SmtpErrorType.toEnum(builder.toString());
								}
							}
						}
					}

					if (!StringUtils.isBlank(messageId)) {
						//logger.info("messageId:" + messageId);
						
						userTransaction.begin();
						isTransaction = true;

						if (!updateEnqueteMailSendResult(messageId, smtpErrorType, smtpStatusType, insId)) {
							updateNotifyMailSendResult(messageId, smtpErrorType, smtpStatusType, insId);
						}

						userTransaction.commit();

					}
					message.setFlag(Flags.Flag.DELETED, true);
					
				} catch (Exception e) {
					// エラーメール削除
					logger.fatal("Mail check failed ", e);
					message.setFlag(Flags.Flag.DELETED, true);
					
					//if (isTransaction) {
					//	try {
					//		userTransaction.rollback();
					//	} catch (Exception e2) {
					//		logger.error("userTransaction.rollback() failed ", e2);
					//	}
					//}
				}
			}
		} catch (Exception e) {
			logger.fatal("Mail check failed ", e);
		} finally {
			if (folder != null) {
				folder.close(true);
			}
			if (store != null) {
				store.close();
			}
		}

	}

	private boolean updateEnqueteMailSendResult(String messageId,SmtpErrorType smtpErrorType,SmtpStatusType smtpStatusType,String insId) throws Exception{

		List<EnqueteMailSendResult> result = enqueteMailSendResultService.findMailByMessageId(messageId);

		if (!result.isEmpty()){

			EnqueteMailSendResult enqueteMailSendResult = result.get(0);
			boolean countUpFlg = true;
			// すでに失敗がカウントされている場合、二重にカウントしない
			if(enqueteMailSendResult.sendResultCd != 0){
				countUpFlg = false;
			}

			enqueteMailSendResult.sendResultCd = smtpErrorType.getCode();
			enqueteMailSendResult.sendResult = smtpErrorType.getMessage();
			enqueteMailSendResult.statusCd = smtpStatusType.getCode();
			enqueteMailSendResult.status = smtpStatusType.getMessage();
			enqueteMailSendResult.updateDate = SinaburoUtil.getTimestamp();
			enqueteMailSendResult.upId = insId;

			enqueteMailSendResultService.update(enqueteMailSendResult);

			if (countUpFlg) {
				EnqueteMail enqueteMail = enqueteMailService.findById(enqueteMailSendResult.enqueteMailId);
				enqueteMail.deliverySuccessNum = enqueteMail.deliverySuccessNum - 1;
				enqueteMail.deliveryFailNum = enqueteMail.deliveryFailNum + 1;
				enqueteMail.updateDate = SinaburoUtil.getTimestamp();
				enqueteMail.upId = insId;

				enqueteMailService.update(enqueteMail);
			}

			return true;

		}
		return false;

	}

	private boolean updateNotifyMailSendResult(String messageId, SmtpErrorType smtpErrorType, SmtpStatusType smtpStatusType, String insId) {
		List<NotifyMailSendResult> result = notifyMailSendResultService.findByMessageId(messageId);
		if (!result.isEmpty()) {
			NotifyMailSendResult notifyMailSendResult = result.get(0);
			notifyMailSendResult.sendResultCd = smtpErrorType.getCode();
			notifyMailSendResult.sendResult = smtpErrorType.getMessage();
			notifyMailSendResult.statusCd = smtpStatusType.getCode();
			notifyMailSendResult.status = smtpStatusType.getMessage();
			notifyMailSendResult.updateDate = SinaburoUtil.getTimestamp();
			notifyMailSendResult.upId = insId;

			notifyMailSendResultService.update(notifyMailSendResult);
			return true;
		}
		return false;
	}
}