/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2008 Aimluck,Inc.
 * http://aipostyle.com/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.aimluck.eip.webmail;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.Address;
import javax.mail.Message;

import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.commons.utils.ALStringUtil;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipManager;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.fileupload.beans.FileuploadLiteBean;
import com.aimluck.eip.fileupload.util.FileuploadUtils;
import com.aimluck.eip.mail.ALFolder;
import com.aimluck.eip.mail.ALLocalMailMessage;
import com.aimluck.eip.mail.ALMailFactoryService;
import com.aimluck.eip.mail.ALMailHandler;
import com.aimluck.eip.mail.ALMailSenderContext;
import com.aimluck.eip.mail.ALSmtpMailContext;
import com.aimluck.eip.mail.ALSmtpMailSender;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.DatabaseOrmService;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.webmail.util.WebMailUtils;

/**
 * Webメールフォームデータを管理するためのクラスです。 <br />
 */
public class WebMailFormData extends ALAbstractFormData {
  private static final JetspeedLogger logger = JetspeedLogFactoryService
      .getLogger(WebMailFormData.class.getName());

  /** 件名の最大文字数 */
  private final int FIELD_SUBJECT_MAX_LEN = 256;

  /** 宛先（To，CC，BCC）の最大文字数 */
  private final int FIELD_RECIPIENT_MAX_LEN = 512;

  /** メール本文の最大文字数 */
  private final int FIELD_BODY_MAX_LEN = 50000;

  /** タイプ：デフォルトメール */
  public static final int TYPE_DEF_MAIL = -1;

  /** タイプ：新規メール */
  public static final int TYPE_NEW_MAIL = 0;

  /** タイプ：返信メール */
  public static final int TYPE_REPLY_MAIL = 1;

  /** タイプ：転送メール */
  public static final int TYPE_FORWARD_MAIL = 2;

  /** メール作成のタイプ */
  private ALNumberField mailType = null;

  /** 宛名 */
  private ALStringField to = null;

  /** CC */
  private ALStringField cc = null;

  /** BCC */
  private ALStringField bcc = null;

  /** 件名 */
  private ALStringField subject = null;

  /** 本文 */
  private ALStringField body = null;

  /** 添付ファイルリスト */
  private List fileuploadList = null;

  private String folderName = null;

  /**  */
  private int userId = -1;

  /**  */
  private int accountId = -1;

  private String org_id;

  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    super.init(action, rundata, context);

    userId = ALEipUtils.getUserId(rundata);
    try {
      accountId = Integer.parseInt(ALEipUtils.getTemp(rundata, context,
          WebMailUtils.ACCOUNT_ID));
    } catch (Exception e) {
      accountId = 0;
    }

    folderName = rundata.getParameters().getString("folderName");

    org_id = DatabaseOrmService.getInstance().getOrgId(rundata);
  }

  /**
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
    // メール作成のタイプ
    mailType = new ALNumberField();
    mailType.setFieldName("タイプ");

    // To
    to = new ALStringField();
    to.setFieldName("宛先");
    to.setTrim(true);

    // CC
    cc = new ALStringField();
    cc.setFieldName("CC");
    cc.setTrim(true);

    // BCC
    bcc = new ALStringField();
    bcc.setFieldName("BCC");
    bcc.setTrim(true);

    // Subject
    subject = new ALStringField();
    subject.setFieldName("件名");
    subject.setTrim(true);

    // Body
    body = new ALStringField();
    body.setFieldName("本文");
    body.setTrim(false);

    fileuploadList = new ArrayList();
  }

  /**
   * 各フィールドに対する制約条件を設定する抽象メソッドです。
   */
  protected void setValidator() {
    // 宛先を必須項目にする
    to.setNotNull(true);
    to.limitMaxLength(FIELD_RECIPIENT_MAX_LEN);

    // CC
    cc.limitMaxLength(FIELD_RECIPIENT_MAX_LEN);

    // BCC
    bcc.limitMaxLength(FIELD_RECIPIENT_MAX_LEN);

    // 件名の文字数制限
    subject.limitMaxLength(FIELD_SUBJECT_MAX_LEN);

    // 本文の文字数制限
    body.limitMaxLength(FIELD_BODY_MAX_LEN);

  }

  /**
   * フォームデータの妥当性を検証する．
   * 
   * @param msgList
   *            エラーメッセージのリスト
   */
  public boolean validate(ArrayList msgList) {
    String delim = ",";
    if (to.validate(msgList)
        && !WebMailUtils.checkAddress(to.getValue(), delim)) {
      msgList.add("『 <span class='em'>宛先</span> 』を正しく入力してください。");
    }
    if (cc.validate(msgList) && cc.getValue().trim().length() > 0
        && !WebMailUtils.checkAddress(cc.getValue(), delim)) {
      msgList.add("『 <span class='em'>CC</span> 』を正しく入力してください。");
    }
    if (bcc.validate(msgList) && bcc.getValue().trim().length() > 0
        && !WebMailUtils.checkAddress(bcc.getValue(), delim)) {
      msgList.add("『 <span class='em'>BCC</span> 』を正しく入力してください。");
    }
    subject.validate(msgList);
    body.validate(msgList);

    /*
     * StringBuffer sb = new StringBuffer(); String toErr =
     * checkUnusualChar(to.getValue()); if (toErr != null && !toErr.equals("")) {
     * sb.append( "『 <span class='em'>宛名 </span> 』に次の機種依存文字が含まれています ： " + toErr + "
     * <br> "); }
     * 
     * String ccErr = checkUnusualChar(cc.getValue()); if (ccErr != null &&
     * !ccErr.equals("")) { sb.append( "『 <span class='em'>CC </span>
     * 』に次の機種依存文字が含まれています ： " + ccErr + " <br> "); }
     * 
     * String bccErr = checkUnusualChar(bcc.getValue()); if (bccErr != null &&
     * !bccErr.equals("")) { sb.append( "『 <span class='em'>BCC </span>
     * 』に次の機種依存文字が含まれています ： " + bccErr + " <br> "); }
     * 
     * String subjectErr = checkUnusualChar(subject.getValue()); if (subjectErr !=
     * null && !subjectErr.equals("")) { sb.append( "『 <span class='em'>件名
     * </span> 』に次の機種依存文字が含まれています ： " + subjectErr + " <br> "); }
     * 
     * String bodyErr = checkUnusualChar(body.getValue()); if (bodyErr != null &&
     * !bodyErr.equals("")) { sb.append( "『 <span class='em'>本文 </span>
     * 』に次の機種依存文字が含まれています ： " + bodyErr + " <br> "); }
     * 
     * int length = attachmentFileNameList.size(); AttachmentFile attachmentFile =
     * null; String attachmentFileErr = ""; String tmpErr = null; for (int i =
     * 0; i < length; i++) { attachmentFile = (AttachmentFile)
     * attachmentFileNameList.get(i); if(i == 0){ tmpErr =
     * checkUnusualChar(attachmentFile.getFileName().getValue()); if(tmpErr !=
     * null && !tmpErr.equals("")){ attachmentFileErr += tmpErr; } }else{ tmpErr =
     * checkUnusualChar(attachmentFile.getFileName().getValue()); if(tmpErr !=
     * null && !tmpErr.equals("")){ if(attachmentFileErr.equals("")){
     * attachmentFileErr += tmpErr; }else{ attachmentFileErr = attachmentFileErr +
     * "," + tmpErr; } } } } if (attachmentFileErr != null &&
     * !attachmentFileErr.equals("")) { sb.append( "『 <span class='em'>添付ファイル
     * </span> 』に次の機種依存文字が含まれています ： " + attachmentFileErr + " <br> "); }
     * 
     * if (sb.length() > 0) {
     * sb.append("送信先では正しく表示されない可能性があるため、機種依存文字の入力を制限しています。 <br> "); sb.append( "
     * <a href=\"javascript:open_help()\"> <span>Aipo で入力できる機種依存文字はこちらを参照ください。
     * </span> </a>"); msgList.add(sb.toString()); }
     */
    return (msgList.size() == 0);
  }

  /**
   * @see com.aimluck.eip.common.ALAbstractFormData#deleteFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean deleteFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      int index;
      try {
        index = Integer.parseInt(ALEipUtils.getTemp(rundata, context,
            ALEipConstants.ENTITY_ID));
      } catch (Exception e) {
        return false;
      }

      String currentTab = ALEipUtils.getTemp(rundata, context, "tab");
      int type_mail = (WebMailUtils.TAB_RECEIVE.equals(currentTab)) ? ALFolder.TYPE_RECEIVE
          : ALFolder.TYPE_SEND;
      ALMailHandler handler = ALMailFactoryService.getInstance()
          .getMailHandler();
      ALFolder folder = handler.getALFolder(type_mail, org_id, userId, Integer
          .valueOf(accountId));
      folder.deleteMail(index);

    } catch (Exception e) {
      logger.error("Exception", e);
      return false;
    }
    return true;
  }

  /**
   * @see com.aimluck.eip.common.ALAbstractFormData#insertFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean insertFormData(RunData rundata, Context context,
      ArrayList msgList) {

    String[] attachmentFilepaths = null;
    boolean success = false;
    try {
      FileuploadLiteBean filebean = null;
      File file = null;
      boolean hasAttachments = (fileuploadList != null && fileuploadList.size() > 0);
      if (hasAttachments) {
        int size = fileuploadList.size();
        attachmentFilepaths = new String[size];
        for (int i = 0; i < size; i++) {
          filebean = (FileuploadLiteBean) fileuploadList.get(i);
          file = FileuploadUtils.getAbsolutePath(org_id, userId, folderName,
              filebean.getFileId());
          attachmentFilepaths[i] = file.getAbsolutePath();
        }
      }

      // 件名の値を検証
      if (subject.getValue() == null || subject.getValue().equals("")) {
        subject.setValue("無題");
      }

      // 返信メールの場合は，ヘッダを追加する．
      Map map = null;
      if (getMailType().getValue() == TYPE_REPLY_MAIL) {
        ALLocalMailMessage msg = null;
        try {
          msg = (ALLocalMailMessage) WebMailUtils.getSelectedLocalMailMessage(
              rundata, context, (int) getMailType().getValue());
          if (msg == null) {
            return false;
          }
        } catch (Exception e) {
          return false;
        }
        String in_reply_tos = msg.getMessageID();
        StringBuffer reference = new StringBuffer();
        String[] references = msg.getHeader("References");
        map = new LinkedHashMap();
        if (references != null && references.length > 0) {
          reference.append(ALMailUtils.getOneString(references, " "));
        }
        if (in_reply_tos != null && (!in_reply_tos.equals(""))) {
          map.put("In-Reply-To", in_reply_tos);
          reference.append(" ").append(in_reply_tos);
        }

        if (reference.toString() != null || (!reference.toString().equals(""))) {
          map.put("References", reference.toString());
        }
      }

      if (map != null && map.size() == 0)
        map = null;

      String delim = ",";

      // オブジェクトモデルを取得
      EipMMailAccount account = ALMailUtils.getMailAccount(null, userId,
          accountId);

      ALMailHandler handler = ALMailFactoryService.getInstance()
          .getMailHandler();
      // 送信サーバ情報
      ALMailSenderContext scontext = ALMailUtils.getALSmtpMailSenderContext(
          org_id, account);

      // 送信メッセージのコンテキスト
      ALSmtpMailContext mailcontext = ALMailUtils.getALSmtpMailContext(
          ALMailUtils
              .getTokens(ALStringUtil.unsanitizing(to.getValue()), delim),
          ALMailUtils
              .getTokens(ALStringUtil.unsanitizing(cc.getValue()), delim),
          ALMailUtils.getTokens(ALStringUtil.unsanitizing(bcc.getValue()),
              delim), account.getMailAddress(), ALStringUtil
              .unsanitizing(account.getMailUserName()), ALStringUtil
              .unsanitizing(subject.getValue()), ALStringUtil.unsanitizing(body
              .getValue()), attachmentFilepaths, map);

      int success_send = handler.send(scontext, mailcontext);

      if (success_send == ALSmtpMailSender.SEND_MSG_SUCCESS) {
        if (hasAttachments) {
          File folder = FileuploadUtils.getFolder(org_id, userId, folderName);
          // 添付ファイル保存先のフォルダを削除
          FileuploadUtils.deleteFolder(folder);
        }
      } else {
        if (success_send == ALSmtpMailSender.SEND_MSG_FAIL) {
          msgList.add("メールを送信できませんでした。アカウント設定が間違っている可能性があります。");
        } else if (success_send == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
          msgList.add("7MB を超えるサイズのメールは送信できません。");
        } else if (success_send == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
          msgList.add("メールを送信できませんでした。SMTP認証の認証に失敗しました。");
        }

        return false;
      }
    } catch (Exception e) {
      logger.error("Exception", e);
      msgList.add("メールを送信できませんでした。アカウント設定が間違っている可能性があります。");
      return false;
    }
    return true;
  }

  /**
   * @see com.aimluck.eip.common.ALAbstractFormData#loadFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean loadFormData(RunData rundata, Context context,
      ArrayList msgList) {

    try {
      ALLocalMailMessage msg = (ALLocalMailMessage) WebMailUtils
          .getSelectedLocalMailMessage(rundata, context, (int) getMailType()
              .getValue());
      if (msg == null)
        return false;

      mailType.setValue(rundata.getParameters().getInt(WebMailUtils.MAIL_TYPE,
          TYPE_NEW_MAIL));

      String tmpSubject = null;
      if (getMailType().getValue() == TYPE_NEW_MAIL) {
        // TO
        Address[] tos = msg.getRecipients(Message.RecipientType.TO);
        this.setTo(ALMailUtils.getAddressString(tos));

        // CC
        Address[] ccs = msg.getRecipients(Message.RecipientType.CC);
        this.setCc(ALMailUtils.getAddressString(ccs));
        // BCC
        Address[] bccs = msg.getRecipients(Message.RecipientType.BCC);
        this.setCc(ALMailUtils.getAddressString(bccs));

        tmpSubject = msg.getSubject();
      } else if (getMailType().getValue() == TYPE_REPLY_MAIL) {
        // TO
        Address[] tos = msg.getFrom();
        this.setTo(ALMailUtils.getAddressString(tos));

        tmpSubject = "Re: " + msg.getSubject();
      } else if (getMailType().getValue() == TYPE_FORWARD_MAIL) {
        tmpSubject = "Fwd: " + msg.getSubject();
      }

      // Subject
      this.setSubject(tmpSubject);

      // 返信の原文付与
      String[] tmp2 = msg.getBodyTextArray();

      StringBuffer replies = new StringBuffer();
      replies.append("\r\n\r\n\r\n" + "------Original Message-------\r\n");
      for (String factor : tmp2) {
        replies.append("> " + factor + "\r\n");
      }

      // Body
      try {
        // オブジェクトモデルを取得
        EipMMailAccount account = ALMailUtils.getMailAccount(null, userId,
            accountId);
        // 署名と返信とを本文に追加
        if (account.getSignature() != null
            && !"".equals(account.getSignature())) {
          body.setValue(replies + "\r\n\r\n\r\n" + account.getSignature());
        }else{
          body.setValue(replies.toString());
        }
      } catch (Exception ex) {
        logger.error("Exception", ex);
      }

      if (getMailType().getValue() == TYPE_FORWARD_MAIL) {
        // tmp フォルダの作成
        // setupFolder(rundata);

        String[] filenames = msg.getAttachmentFileNameArray();
        if (filenames != null && filenames.length > 0) {
          /*
           * File folder = new File(tmpfolderRootPath); if(! folder.exists()){
           * folder.mkdirs(); } String newAttachmentFolderName =
           * WebMailUtils.getNewAttachmentFolderName(folder); String folderpath =
           * tmpfolderRootPath + FILE_SEPARATOR + newAttachmentFolderName;
           * folder = new File(folderpath); if(! folder.exists()){
           * folder.mkdirs(); }
           * 
           * File tmpFile = new File(attachmentItem.getName()); String filepath =
           * folderpath + FILE_SEPARATOR + tmpFile.getName(); File file = new
           * File(filepath);
           * 
           * file.createNewFile(); attachmentItem.write(file.getAbsolutePath());
           * 
           * attachmentFile = new AttachmentFile();
           * attachmentFile.setFileName(file.getName());
           * attachmentFile.setNumber(newAttachmentFolderName);
           * attachmentFileNameList.add(attachmentFile);
           */

          /*
           * String tmpfolderRootPath = WebMailUtils.FOLDER_FOR_ATTACHMENT_FILES +
           * FILE_SEPARATOR + userId + FILE_SEPARATOR + folderName;
           * AttachmentFile attachmentFile = null; File attachmentFolder = null;
           * String tmpfolderpath = null; int length = filenames.length; for(int
           * i=0; i <length; i++){ String newAttachmentFolderName =
           * WebMailUtils.getNewAttachmentFolderName(new
           * File(tmpfolderRootPath)); String folderpath = tmpfolderRootPath +
           * FILE_SEPARATOR + newAttachmentFolderName; File folder = new
           * File(folderpath); if(! folder.exists()){ folder.mkdirs(); }
           * 
           * tmpfolderpath = folderpath + FILE_SEPARATOR + filenames[i];
           * FileItem attachmentItem = new FileItem(); attachmentFolder = new
           * File(tmpfolderpath); File[] files = attachmentFolder.listFiles();
           * if(files == null || files.length <= 0) continue; attachmentFile =
           * new AttachmentFile();
           * attachmentFile.setFileName(files[0].getName());
           * attachmentFile.setNumber(attachmentNumbers[i]);
           * attachmentFileNameList.add(attachmentFile); }
           */
        }

      }
      return true;
    } catch (Exception e) {
      logger.error("Exception", e);
      return false;
    }
  }

  protected boolean updateFormData(RunData rundata, Context context,
      ArrayList msgList) throws ALPageNotFoundException, ALDBErrorException {
    return false;
  }

  /**
   * 
   * @see com.aimluck.eip.common.ALAbstractFormData#setFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean setFormData(RunData rundata, Context context,
      ArrayList msgList) throws ALPageNotFoundException, ALDBErrorException {

    boolean res = super.setFormData(rundata, context, msgList);

    try {
      fileuploadList = FileuploadUtils.getFileuploadList(rundata);
      // Body
      // オブジェクトモデルを取得
      EipMMailAccount account = ALMailUtils.getMailAccount(null, userId,
          accountId);
      // 署名を本文に追加
      if (!ALEipConstants.MODE_INSERT.equals(rundata.getParameters().get(
          ALEipConstants.MODE))
          && account.getSignature() != null
          && !"".equals(account.getSignature())) {
        StringBuffer bodybuf = new StringBuffer();
        if (body.getValue() != null) {
          bodybuf.append(body.getValue());
        }
        bodybuf.append("\r\n\r\n\r\n");
        bodybuf.append(account.getSignature());
        body.setValue(bodybuf.toString());
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
    }

    return res;
  }

  /**
   * @return
   */
  public ALStringField getBcc() {
    return bcc;
  }

  /**
   * @return
   */
  public ALStringField getBody() {
    return body;
  }

  /**
   * @return
   */
  public ALStringField getCc() {
    return cc;
  }

  /**
   * @return
   */
  public ALStringField getSubject() {
    return subject;
  }

  /**
   * @return
   */
  public ALStringField getTo() {
    return to;
  }

  /**
   * @return
   */
  public ALNumberField getMailType() {
    return mailType;
  }

  /**
   * @param field
   */
  public void setMailType(int field) {
    mailType.setValue(field);
  }

  /**
   * @param field
   */
  public void setBcc(String string) {
    bcc.setValue(string);
  }

  /**
   * @param field
   */
  public void setBody(String string) {
    body.setValue(string);
  }

  /**
   * @param field
   */
  public void setCc(String string) {
    cc.setValue(string);
  }

  /**
   * @param field
   */
  public void setSubject(String string) {
    subject.setValue(string);
  }

  /**
   * @param field
   */
  public void setTo(String string) {
    to.setValue(string);
  }

  public String getAccountName() {
    return ALMailUtils.getAccountName(userId, accountId);
  }

  /**
   * 
   * @return
   */
  public Map getPostMap() {
    return ALEipManager.getInstance().getPostMap();
  }

  public List getAttachmentFileNameList() {
    return fileuploadList;
  }

  public String getFolderName() {
    return folderName;
  }

  public int getAccountId() {
    return accountId;
  }

  public String getAddrForCell(ALStringField addrs_filed) {
    if (addrs_filed == null)
      return "";

    String addrs = addrs_filed.getValue();

    if (addrs == null || addrs.length() == 0)
      return "";

    StringBuffer addrbuf = new StringBuffer();
    int count = 0;
    String token = null;
    StringTokenizer st = new StringTokenizer(addrs, ",");
    int size = st.countTokens();
    for (int i = 0; i < size; i++) {
      token = st.nextToken();
      if (token.indexOf("<") == -1) {
        addrbuf.append(token);
      } else {
        StringTokenizer tmp_st = new StringTokenizer(token, "<>");
        if (tmp_st.countTokens() == 2) {
          tmp_st.nextToken();
          addrbuf.append(tmp_st.nextToken());
        }
      }
      count = count + 1;
      if (count < size) {
        addrbuf.append(",");
      }
    }
    return addrbuf.toString();
  }

}
