/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2011 Aimluck,Inc.
 * http://www.aipo.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.webmail.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.MessagingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.cayenne.CayenneException;
import org.apache.cayenne.DataRow;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.access.ResultIterator;
import org.apache.cayenne.access.Transaction;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.commons.io.FileUtils;
import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALDateTimeField;
import com.aimluck.commons.utils.ALStringUtil;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailBatch;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailSend;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailSendRecvAcl;
import com.aimluck.eip.cayenne.om.portlet.EipMAddressbook;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.cayenne.om.portlet.EipTMail;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFilter;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFolder;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALPageNotFoundException;
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.ALMailMessage;
import com.aimluck.eip.mail.ALMailReceiverContext;
import com.aimluck.eip.mail.ALMailSenderContext;
import com.aimluck.eip.mail.ALPop3MailReceiveThread;
import com.aimluck.eip.mail.ALSmtpMailContext;
import com.aimluck.eip.mail.ALSmtpMailSender;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.Operations;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.services.storage.ALStorageService;
import com.aimluck.eip.user.beans.UserGroupPositionLiteBean;
import com.aimluck.eip.user.util.UserUtils;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.webmail.ExtFolderInfo;
import com.aimluck.eip.webmail.WebMailConsts;
import com.aimluck.eip.webmail.WebMailFolderResultData;
import com.aimluck.eip.webmail.WebMailFormData;
import com.aimluck.eip.webmail.beans.WebMailFolderVolumeSummaryBean;
import com.aimluck.eip.webmail.beans.WebmailAccountLiteBean;

/**
 */
public class WebMailUtils {

  /** logger */
  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(WebMailUtils.class.getName());

  // add start
  /** 設定ファイルパス */
  private static final String SETTING_FILE_PATH = JetspeedResources.getString("aipo.conf", "") + File.separator + "WebMailAdminSettings.properties";

  // add end

  /** セッションの識別子 */
  public static final String FOLDER_ID = ALMailUtils.FOLDER_ID;

  public static final String FILTER_ID = "filterid";

  /** タブ「受信トレイ」 */
  public static final String TAB_RECEIVE = "receive";

  /** タブ「送信トレイ」 */
  public static final String TAB_SENT = "sent";

  public static final String DATE_TIME_FORMAT = ALDateTimeField.DEFAULT_DATE_TIME_FORMAT;

  public static final String CREATED_DATE_FORMAT = ALDateTimeField.DEFAULT_DATE_FORMAT;

  public final static String ACCOUNT_ID = "accountid";

  public final static String ACCOUNT_NAME = "accountname";

  public final static String MAIL_TYPE = "mailtype";

  public final static String CONFIRM_LAST_TIME = "confirmlasttime";

  /** フィルタタイプ */
  public final static String FILTER_TYPE_MAILADDRESS = ALMailUtils.FILTER_TYPE_MAILADDRESS;

  public final static String FILTER_TYPE_DOMAIN = ALMailUtils.FILTER_TYPE_DOMAIN;

  public final static String FILTER_TYPE_SUBJECT = ALMailUtils.FILTER_TYPE_SUBJECT;

  public final static String FILTER_TYPE_TO = ALMailUtils.FILTER_TYPE_TO;

  public static final List<EipMMailAccount> getMailAccountNameList(int userId) {
    SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);

    query.select(EipMMailAccount.ACCOUNT_ID_PK_COLUMN);
    query.select(EipMMailAccount.ACCOUNT_NAME_COLUMN);
    // add start
    query.select(EipMMailAccount.USER_ID_COLUMN);
    // add end
    Expression exp = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));

    return query.setQualifier(exp).fetchList();
  }

  /**
   * 選択したメールをローカルファイルシステムから取得する．
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Throwable
   */
  // change start 2011.1203 受入テスト障害168
  // public static final ALMailMessage getSelectedLocalMailMessage(
  // RunData rundata, Context context, int mailType) throws Throwable {
  public static final ALMailMessage getSelectedLocalMailMessage(RunData rundata, Context context, int mailType, String currentTab
  // add start 2012.2.7 受入障害No.272
      , boolean isRepresent
      // add end
      // add start 運用フェーズ課題・障害台帳No.１５０
      , int accountId
  // add end
  ) throws Throwable {
    // change end
    try {
      String orgId = Database.getDomainName();
      int uid = ALEipUtils.getUserId(rundata);
      // remove start 運用フェーズ課題・障害台帳No.１５０
      // int accountId =
      // Integer.parseInt(ALEipUtils.getTemp(rundata, context, ACCOUNT_ID));
      // remove end

      // add start
      // 代理受信アカウントの場合、ユーザーIDを代理受信元のユーザーに再設定
      try {
        EipMMailAccount tmpAccount = ALMailUtils.getMailAccount(accountId);
        if (tmpAccount.getUserId() != uid) {
          // アカウントのログインユーザーに対する代理受信許可をチェック
          // ログインユーザーの代理受信アカウントであればユーザーIDを代理受信元ユーザーに再設定
          if (ALMailUtils.isRepresentReceiveAccount(tmpAccount, uid)) {
            uid = tmpAccount.getUserId();
          } else {
            throw new Exception();
          }
        }
      } catch (Exception e1) {
        logger.error("代理受信アカウント情報の取得に失敗しました。", e1);
        throw new ALPageNotFoundException();
      }
      // add end

      String mailid = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);
      if (mailid == null || Integer.valueOf(mailid) == null) {
        // Mail IDが空の場合
        logger.debug("[Mail] Empty ID...");
        return null;
      }

      // remove start 2011.1202 受入テスト障害168
      // String currentTab = ALEipUtils.getTemp(rundata, context, "tab");
      // remove end
      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, orgId, uid, accountId);
      // change start 2012.2.7 受入障害No.272
      // 代理受信の場合はステータスの変更は行わない
      // ALMailMessage msg = folder.getMail(Integer.valueOf(mailid));
      // change start 2012.2.24 受入障害No.294
      // ALMailMessage msg = folder.getMail(Integer.valueOf(mailid),
      // isRepresent);
      EipMMailAccount account = ALMailUtils.getMailAccount(accountId);
      ALMailMessage msg = folder.getMail(Integer.valueOf(mailid), isRepresent, account.getAccountUsage());
      // change end 2012.2.24
      // change end 2012.2.7
      if (WebMailFormData.TYPE_REPLY_MAIL == mailType) {
        return ALMailUtils.getReplyMessage(msg);
      } else if (WebMailFormData.TYPE_FORWARD_MAIL == mailType) {
        return ALMailUtils.getForwardMessage(msg);
      } else {
        return msg;
      }
    } catch (Throwable e) {
      throw e;
    }
  }

  /**
   * 複数のメールアドレスを含む文字列の中のメールアドレス形式をチェックします。 想定メール形式は address@aimluck.com xxxyyy
   * <address@aimluck.com>
   * 
   * @param argstr
   *            複数メールアドレス
   * @param delim
   * @return
   */
  public static boolean checkAddress(String argstr, String delim) {
    String[] addresses;
    if (argstr == null || argstr.trim().length() == 0) {
      return false;
    }
    addresses = ALMailUtils.getTokens(argstr, delim);
    for (int i = 0; i < addresses.length; i++) {
      String str = addresses[i].trim();
      if (str.length() == 0) {
        continue;
      }
      if (str.charAt(str.length() - 1) == '>') {
        // 氏名付きアドレス指定 sei mei <seimei@xxx.com>
        int idx = str.indexOf("<");
        // "<"がなければエラー
        if (idx == -1) {
          return false;
        }
        String address = str.substring(idx + 1, str.length() - 1);
        if (!ALStringUtil.isCellPhoneMailAddress(address)) {
          return false;
        }
      } else {
        // アドレス指定のみ
        if (!ALStringUtil.isCellPhoneMailAddress(str)) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * 複数のメールアドレスを含む文字列の中のメールアドレス形式をチェックします。 想定メール形式は address@aimluck.com xxxyyy
   * <address@aimluck.com>
   * 
   * @param argstr
   *            複数メールアドレス
   * @param delim
   * @return
   */
  public static boolean checkAddressForCellularSmartPhone(String argstr, String delim) {
    String[] addresses;
    if (argstr == null || argstr.trim().length() == 0) {
      return false;
    }
    try {
      addresses = ALMailUtils.getTokensExtForMobile(argstr, delim);
    } catch (IOException e) {
      return false;
    }
    for (int i = 0; i < addresses.length; i++) {
      String str = addresses[i].trim();
      if (str.length() == 0) {
        continue;
      }
      if (str.charAt(str.length() - 1) == '>') {
        // 氏名付きアドレス指定 sei mei <seimei@xxx.com>
        int idx = str.indexOf("<");
        // "<"がなければエラー
        if (idx == -1) {
          return false;
        }
        String address = str.substring(idx + 1, str.length() - 1);
        if (!ALStringUtil.isCellPhoneMailAddress(address)) {
          return true;
        }
      } else {
        // アドレス指定のみ
        if (!ALStringUtil.isCellPhoneMailAddress(str)) {
          return true;
        }
      }
    }
    return true;
  }

  public static String checkUnusualChar(String str) {
    List<Character> unusualChars = new ArrayList<Character>();

    /**
     * 文字化けを起こす特殊記号 【囲み英数字／ローマ数字】①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ
     * 【単位記号】㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍・㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡ 【省略文字／囲み文字／年号】㍻〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼∮∑∟⊿
     */
    char[] unusualchars =
      {
        '①',
        '②',
        '③',
        '④',
        '⑤',
        '⑥',
        '⑦',
        '⑧',
        '⑨',
        '⑩',
        '⑪',
        '⑫',
        '⑬',
        '⑭',
        '⑮',
        '⑯',
        '⑰',
        '⑱',
        '⑲',
        '⑳',
        'Ⅰ',
        'Ⅱ',
        'Ⅲ',
        'Ⅳ',
        'Ⅴ',
        'Ⅵ',
        'Ⅶ',
        'Ⅷ',
        'Ⅸ',
        'Ⅹ',
        '㍉',
        '㌔',
        '㌢',
        '㍍',
        '㌘',
        '㌧',
        '㌃',
        '㌶',
        '㍑',
        '㍗',
        '㌍',
        '・',
        '㌣',
        '㌫',
        '㍊',
        '㌻',
        '㎜',
        '㎝',
        '㎞',
        '㎎',
        '㎏',
        '㏄',
        '㎡',
        '㍻',
        '〝',
        '〟',
        '№',
        '㏍',
        '℡',
        '㊤',
        '㊥',
        '㊦',
        '㊧',
        '㊨',
        '㈱',
        '㈲',
        '㈹',
        '㍾',
        '㍽',
        '㍼',
        '∮',
        '∑',
        '∟',
        '⊿' };
    int unusuallen = unusualchars.length;
    int length = str.length();
    Character cha = null;
    for (int i = 0; i < length; i++) {
      for (int j = 0; j < unusuallen; j++) {
        if (str.charAt(i) == unusualchars[j]) {
          cha = Character.valueOf(unusualchars[j]);
          if (!unusualChars.contains(cha)) {
            unusualChars.add(cha);
          }
        }
      }
    }

    StringBuffer sb = new StringBuffer();
    if (unusualChars.size() < 1) {
      return null;
    }
    length = unusualChars.size() - 1;
    for (int i = 0; i < length; i++) {
      sb.append("\"").append(unusualChars.get(i)).append("\"").append(",");
    }
    sb.append("\"").append(unusualChars.get(length)).append("\"");
    return sb.toString();
  }

  /**
   * POP3 サーバからメールを受信する。
   * 
   * @param rundata
   * @param context
   *            /** add start
   * @param boolean
   *            携帯フラグ PC:false MB:true //*add end
   * @throws Exception
   */
  // change start
  // public static void receiveMailsThread(RunData rundata, Context context)
  // throws Exception {
  public static void receiveMailsThread(RunData rundata, Context context, boolean mobile) throws Exception {
    // change end

    // remove start 初期Aipoではメールファイル出力の競合を避けるためにシステム一意の排他を掛けていたが、
    // 現状では必要がなくなっているため削除
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {
    // remove end
    JetspeedRunData jdata = (JetspeedRunData) rundata;
    JetspeedUser user = (JetspeedUser) jdata.getUser();

    // 現在使用中のアカウントIDを取得
    int accountId = 0;
    try {
      accountId = Integer.parseInt(ALEipUtils.getTemp(rundata, context, ACCOUNT_ID));
    } catch (Exception ex) {
    }
    if (accountId <= 0) {
      return;
    }

    // アカウントがユーザーのものであるかどうかチェックする
    EipMMailAccount account = ALMailUtils.getMailAccount(Integer.parseInt(user.getUserId()), accountId);
    if (account == null) {
      return;
    }

    if (!ALPop3MailReceiveThread.isProcessing(user, accountId)) {
      // メールと接続してなければ新規にスレッドを生成
      Runnable receiver =
        new ALPop3MailReceiveThread(Database.createDataContext(Database.getDomainName()), user, accountId, ALPop3MailReceiveThread.PROCESS_TYPE_RECEIVEMAIL);
      Thread mailthread = new Thread(receiver);

      // ALStaticObject ob = ALStaticObject.getInstance();
      // ob.updateAccountStat(accountId, ALPop3MailReceiveThread.KEY_THREAD,
      // mailthread);
      mailthread.start();
      // add start
      if (mobile) {
        // 携帯の場合は処理が完了するまで待ち合わせを行う
        mailthread.join();
      }
      // add end
    }
    // remove start
    // }
    // remove end
  }

  // add start
  /**
   * POP3 サーバからメールを受信する。(PCクラスからの呼び出し用)
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static void receiveMailsThread(RunData rundata, Context context) {
    try {
      receiveMailsThread(rundata, context, false);
    } catch (Exception ex) {
      logger.error("(PC)POP3 サーバからメール受信に失敗しました。", ex);
    }
  }

  /**
   * POP3 サーバからメールを受信する。(携帯向け)
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static void receiveMailsForMobile(RunData rundata, Context context) throws Exception {
    try {
      receiveMailsThread(rundata, context, true);
    } catch (Exception ex) {
      logger.error("(携帯・スマートフォン)POP3 サーバからメール受信に失敗しました。", ex);
    }
  }

  // add end

  /**
   * ユーザーの全アカウントに対してPOP3 サーバからメールを受信する。<BR>
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static void receiveAllAccountMailsThread(RunData rundata, Context context) throws Exception {
    // remove start 初期Aipoではメールファイル出力の競合を避けるためにシステム一意の排他を掛けていたが、
    // 現状では必要がなくなっているため削除
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {
    // remove end
    JetspeedRunData jdata = (JetspeedRunData) rundata;
    JetspeedUser user = (JetspeedUser) jdata.getUser();

    // ログインユーザーの全アカウント取得
    List<EipMMailAccount> accountList = WebMailUtils.getMailAccountNameList(ALEipUtils.getUserId(rundata));

    // 代理受信アカウントの取得
    List<AvzTMailSendRecvAcl> deputyList = ALMailUtils.getRepresentReceiveAccount(ALEipUtils.getUserId(rundata));

    // アカウントIDリスト作成
    List<Integer> accountIdList = new ArrayList<Integer>();
    // ログインユーザーアカウント
    for (EipMMailAccount account : accountList) {
      accountIdList.add(account.getAccountId());
    }
    // 代理受信アカウント
    for (AvzTMailSendRecvAcl avzTMailSendRecvAcl : deputyList) {
      accountIdList.add(avzTMailSendRecvAcl.getAccountId());
    }

    // 取得した全アカウントでメール受信
    for (Integer accountId : accountIdList) {

      if (!ALPop3MailReceiveThread.isProcessing(user, accountId)) {
        // メールと接続してなければ新規にスレッドを生成
        Runnable receiver =
          new ALPop3MailReceiveThread(Database.createDataContext(Database.getDomainName()), user, accountId, ALPop3MailReceiveThread.PROCESS_TYPE_RECEIVEMAIL);
        Thread mailthread = new Thread(receiver);

        mailthread.start();

      }
    }
    // remove start
    // }
    // remove end
  }

  /**
   * POP3 サーバから新着メール数を取得する。
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static int getNewMailNumThread(String orgId, JetspeedUser user, int accountId) throws Exception {
    // remove start 初期Aipoではメールファイル出力の競合を避けるためにシステム一意の排他を掛けていたが、
    // 現状では必要がなくなっているため削除
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {
    // remove end
    if (!ALPop3MailReceiveThread.isProcessing(user, accountId)) {
      // メールと接続してなければ新規にスレッドを生成
      Thread mailthread =
        new Thread(new ALPop3MailReceiveThread(
          Database.createDataContext(Database.getDomainName()),
          user,
          accountId,
          ALPop3MailReceiveThread.PROCESS_TYPE_GET_NEWMAILNUM));
      mailthread.start();
    }

    return ALPop3MailReceiveThread.getNewMailNum(user, accountId);
    // remove start
    // }
    // remove end
  }

  // /**
  // * 指定されたアカウントのメール受信を中断する。
  // *
  // * @param account
  // */
  // public static void stopReceiveMailThread(int accountId) {
  //
  // Object objRS = ALStaticObject.getInstance().getAccountStat(accountId,
  // ALPop3MailReceiveThread.KEY_THREAD);
  // if (objRS == null){
  // return;
  // }
  //
  // return;
  // }

  /**
   * POP3 サーバと通信後の結果を取得する。
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static int getStatThread(String orgId, JetspeedUser user, int accountId) throws Exception {
    // remove start 初期Aipoではメールファイル出力の競合を避けるためにシステム一意の排他を掛けていたが、
    // 現状では必要がなくなっているため削除
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {
    // remove end
    if (ALPop3MailReceiveThread.isProcessing(user, accountId)) {
      return ALPop3MailReceiveThread.PROCESS_STAT_PROCESSING;
    } else {
      return ALPop3MailReceiveThread.getReceiveMailResult(user, accountId);
    }
    // remove start
    // }
    // remove end
  }

  /**
   * POP3 サーバと通信後の結果を取得する。
   * 
   * @param rundata
   * @param context
   * @throws Exception
   */
  public static String getStatStrThread(String orgId, JetspeedUser user, int accountId) throws Exception {
    // remove start 初期Aipoではメールファイル出力の競合を避けるためにシステム一意の排他を掛けていたが、
    // 現状では必要がなくなっているため削除
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {
    // remove end
    return ALPop3MailReceiveThread.getReceiveMailResultStr(user, accountId);
    // remove start
    // }
    // remove end
  }

  /**
   * 未読メール総数を取得する。
   * 
   * @param rundata
   * @param userId
   * @param accountId
   * @return
   */
  public static int getUnreadMailNumber(RunData rundata, int userId, int accountId) {
    String orgId = Database.getDomainName();
    EipMMailAccount account = ALMailUtils.getMailAccount(userId, accountId);
    ALMailHandler handler = ALMailFactoryService.getInstance().getMailHandler();
    ALMailReceiverContext rcontext = ALMailUtils.getALPop3MailReceiverContext(orgId, account);

    return handler.getUnReadMailSum(rcontext);
  }

  /**
   * フォルダ別未読メール数を取得する。
   * <p>
   * 受信トレイまたは送信トレイのフォルダ別未読メール数を返す。<BR>
   * 
   * @param rundata
   * @param userId
   *            ユーザーID
   * @param accountId
   *            アカウントID
   * @return Map<Integer, Integer> フォルダ別未読送信メール数<フォルダID, 未読数>
   * @throws Exception
   */
  public static Map<Integer, Integer> getUnreadMailNumberMap(RunData rundata, int userId, int accountId) throws Exception {
    String orgId = Database.getDomainName();
    EipMMailAccount account = ALMailUtils.getMailAccount(userId, accountId);
    ALMailHandler handler = ALMailFactoryService.getInstance().getMailHandler();
    ALMailReceiverContext rcontext = ALMailUtils.getALPop3MailReceiverContext(orgId, account);

    return handler.getUnReadMailSumMap(rcontext);
  }

  public static boolean isNewMessage(RunData rundata, Context context) {
    String accountId = rundata.getParameters().getString(WebMailUtils.ACCOUNT_ID);
    if (accountId == null || "".equals(accountId)) {
      return true;
    }
    EipMMailAccount account = ALMailUtils.getMailAccount(ALEipUtils.getUserId(rundata), Integer.parseInt(accountId));
    String orgId = Database.getDomainName();

    ALMailHandler handler = ALMailFactoryService.getInstance().getMailHandler();
    ALMailReceiverContext rcontext = ALMailUtils.getALPop3MailReceiverContext(orgId, account);
    int res = -1;
    try {
      res = handler.getNewMailSum(rcontext);
    } catch (Exception e) {
      res = -1;
      logger.error(e);
    }
    return (res > 0 ? true : false);
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTMailFolder getEipTMailFolder(RunData rundata, Context context) {
    try {
      int accountId, folderId;

      try {
        accountId = Integer.parseInt(ALEipUtils.getTemp(rundata, context, ACCOUNT_ID));
        folderId = Integer.parseInt(ALEipUtils.getTemp(rundata, context, FOLDER_ID));
      } catch (Exception e) {
        logger.debug("[Mail] Empty ID...");
        return null;
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.FOLDER_ID_PK_COLUMN, folderId);
      Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, accountId);

      EipTMailFolder folder = query.setQualifier(exp.andExp(exp2)).fetchSingle();
      if (folder == null) {
        logger.debug("[WebMail Folder] Not found ID...");
        return null;
      }
      return folder;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTMailFolder getEipTMailFolder(EipMMailAccount account, String folderId) {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        return null;
      }
      if (folderId == null || Integer.valueOf(folderId) == null) {
        // フォルダIDが空の場合、デフォルトのフォルダIDを使う
        folderId = account.getDefaultFolderId().toString();
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.FOLDER_ID_PK_COLUMN, folderId);
      Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      EipTMailFolder folder = query.setQualifier(exp.andExp(exp2)).fetchSingle();
      if (folder == null) {
        logger.debug("[WebMail Folder] Not found ID...");
        return null;
      }
      return folder;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * フィルタオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTMailFilter getEipTMailFilter(EipMMailAccount account, String filterId) {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Filter] Empty Account...");
        return null;
      }

      SelectQuery<EipTMailFilter> query = Database.query(EipTMailFilter.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFilter.FILTER_ID_PK_COLUMN, filterId);
      Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFilter.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      EipTMailFilter filter = query.setQualifier(exp.andExp(exp2)).fetchSingle();
      if (filter == null) {
        logger.debug("[WebMail Filter] Not found ID...");
        return null;
      }
      return filter;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * フィルタオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTMailFilter getEipTMailFilter(RunData rundata, Context context) {
    try {
      int accountId, filterId;

      try {
        accountId = Integer.parseInt(ALEipUtils.getTemp(rundata, context, ACCOUNT_ID));
        filterId = Integer.parseInt(ALEipUtils.getTemp(rundata, context, FILTER_ID));
      } catch (Exception e) {
        logger.debug("[WebMail Filter] Empty ID...");
        return null;
      }

      SelectQuery<EipTMailFilter> query = Database.query(EipTMailFilter.class);
      Expression exp = ExpressionFactory.matchDbExp(EipTMailFilter.FILTER_ID_PK_COLUMN, filterId);
      Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFilter.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, accountId);

      EipTMailFilter filter = query.setQualifier(exp.andExp(exp2)).fetchSingle();
      if (filter == null) {
        logger.debug("[WebMail Filter] Not found ID...");
        return null;
      }
      return filter;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * 指定されたアカウントのフィルタの最後のソート番号を取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static int getMailFilterLastSortOrder(EipMMailAccount account) {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Filter] Empty Account...");
        return 0;
      }

      SelectQuery<EipTMailFilter> query = Database.query(EipTMailFilter.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFilter.EIP_MMAIL_ACCOUNT_PROPERTY, account);
      query.setQualifier(exp).orderDesending(EipTMailFilter.SORT_ORDER_PROPERTY);

      EipTMailFilter filter = query.fetchSingle();
      if (filter == null) {
        logger.debug("[WebMail Filter] Not found ID...");
        return 0;
      }
      return filter.getSortOrder();
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return 0;
    }
  }

  /**
   * セッションに保存されたString値から メール未読数のHashMap を作りなおします。
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static HashMap<Integer, Integer> getUnreadMailSumMapFromString(String str) {

    HashMap<Integer, Integer> unreadSumMap = new HashMap<Integer, Integer>();
    try {
      String[] entries = str.split("\\{")[1].split("\\}")[0].split(",");
      for (String entry : entries) {
        entry = entry.trim();
        String[] keyValue = entry.split("=");
        unreadSumMap.put(Integer.valueOf(keyValue[0]).intValue(), Integer.valueOf(keyValue[1]).intValue());
      }
      return unreadSumMap;
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * メールアカウントのセッション情報を削除します。
   * 
   * @param rundata
   * @param context
   */
  public static void clearWebMailAccountSession(RunData rundata, Context context) {
    ALEipUtils.removeTemp(rundata, context, WebMailUtils.ACCOUNT_ID);
    ALEipUtils.removeTemp(rundata, context, WebMailUtils.FOLDER_ID);
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Exception
   */
  public static List<WebMailFolderResultData> getMailFolderAll(EipMMailAccount account) throws Exception {

    List<EipTMailFolder> folderList = ALMailUtils.getEipTMailFolderAll(account);

    // 受信トレイを先頭に配置する
    List<WebMailFolderResultData> list = new ArrayList<WebMailFolderResultData>();

    for (EipTMailFolder folder : folderList) {
      WebMailFolderResultData data = new WebMailFolderResultData(folder);
      list.add(data);
    }

    return list;
  }

  // add by motegi start サブフォルダ対応
  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Exception
   */
  public static List<WebMailFolderResultData> getMailFolderAll(EipMMailAccount account, String folder_kind) throws Exception {

    List<EipTMailFolder> folderList = ALMailUtils.getEipTMailFolderAll(account, folder_kind);

    // 受信トレイを先頭に配置する
    List<WebMailFolderResultData> list = new ArrayList<WebMailFolderResultData>();

    for (EipTMailFolder folder : folderList) {
      WebMailFolderResultData data = new WebMailFolderResultData(folder);
      list.add(data);
    }

    return list;
  }

  /**
   * フォルダオブジェクトモデル(携帯)を取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Exception
   */
  // change start 運用保守障害58
  // public static List<WebMailFolderResultData> getMailFolderAllForMobile(
  // EipMMailAccount account, String folder_kind) throws Exception {
  // // 携帯は「下書き」フォルダは含めない
  // List<EipTMailFolder> folderList =
  // ALMailUtils.getEipTMailFolderAllForMobile(account, folder_kind);
  //
  // // 受信トレイを先頭に配置する
  // List<WebMailFolderResultData> list =
  // new ArrayList<WebMailFolderResultData>();
  //
  // for (EipTMailFolder folder : folderList) {
  // WebMailFolderResultData data = new WebMailFolderResultData(folder);
  // list.add(data);
  // }
  //
  // return list;
  // }
  public static List<ExtFolderInfo> getMailFolderAllForMobile(EipMMailAccount account, String folder_kind) throws Exception {
    // 携帯は「下書き」フォルダは含めない
    List<EipTMailFolder> folderList = ALMailUtils.getEipTMailFolderAllForMobile(account, folder_kind);

    // 受信トレイを先頭に配置する
    List<ExtFolderInfo> list = new ArrayList<ExtFolderInfo>();

    for (EipTMailFolder folder : folderList) {
      ExtFolderInfo info = new ExtFolderInfo();
      info.setHierarchyIndex(0);
      info.setFolderId(folder.getFolderId().intValue());
      info.setParentFolderId(folder.getParentFolderId().intValue());
      info.setFolderName(folder.getFolderName());
      info.setFolderType(folder.getFolderType());
      info.setFolderKind(folder.getFolderKind());
      list.add(info);
    }

    return list;
  }

  // change end

  /** 『ルートフォルダ』の親フォルダ ID */
  /** フォルダ『ルートフォルダ』の予約 ID */
  public static final int ROOT_FODLER_ID = 0;

  /** 『ルートフォルダ』の親フォルダ ID */
  public static final int ROOT_PARENT_FODLER_ID = 0;

  /** セッションの識別子 */
  public static final String SESSION_KEY_FOLDER_ID = "ext_folder_id";

  /** リクエストの識別子 */
  public static final String REQUEST_KEY_FOLDER_ID = "folder_id";

  // public static List<EipTMailFolder> getRootFolderId(int account_id) {
  // try {
  // SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);
  // query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);
  //
  // Expression exp1 =
  // ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY
  // + "."
  // + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, account_id);
  // query.andQualifier(exp1);
  //
  // Expression exp2 =
  // ExpressionFactory.matchExp(
  // EipTMailFolder.PARENT_FOLDER_ID_PROPERTY,
  // ROOT_PARENT_FODLER_ID);
  // query.andQualifier(exp2);
  //
  // ResultList<EipTMailFolder> list = query.getResultList();
  // if (list == null || list.size() < 0) {
  // return null;
  // }
  // return list;
  // } catch (Exception e) {
  // e.printStackTrace();
  // return null;
  // }
  // }

  /**
   * @param folder_id
   * @param account_id
   * @param folder_kind
   * @return
   */
  public static List<ExtFolderInfo> getFolderList(int folder_id, int account_id, String folder_kind) {
    try {
      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);
      // query.orderAscending(EipTMailFolder.UPDATE_DATE_PROPERTY);
      query.orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY);
      query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);

      // Expression exp =
      // ExpressionFactory.matchDbExp(
      // EipTMailFolder.FOLDER_ID_PK_COLUMN,
      // folderId);
      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, account_id);
      query.andQualifier(exp);
      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);
      query.andQualifier(exp2);

      ResultList<EipTMailFolder> list = query.getResultList();
      if (list == null || list.size() < 0) {
        return null;
      }

      List<ExtFolderInfo> prerootlist = getExtFolderInfoList(list, folder_id, 0);

      List<ExtFolderInfo> result = getFolderList(prerootlist);

      return result;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  // public static List<ExtFolderInfo> getFolderList2(int parent_folder_id,
  // int target_folder_id, int account_id) {
  // try {
  // SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);
  // query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);
  //
  // // Expression exp =
  // // ExpressionFactory.matchDbExp(
  // // EipTMailFolder.FOLDER_ID_PK_COLUMN,
  // // folderId);
  // Expression exp =
  // ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY
  // + "."
  // + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, account_id);
  //
  // query.andQualifier(exp);
  //
  // ResultList<EipTMailFolder> list = query.getResultList();
  // if (list == null || list.size() < 0) {
  // return null;
  // }
  //
  // List<ExtFolderInfo> prerootlist =
  // getExtFolderInfoList2(list, parent_folder_id, target_folder_id, 0);
  //
  // List<ExtFolderInfo> result = getFolderList(prerootlist);
  //
  // return result;
  // } catch (Exception e) {
  // e.printStackTrace();
  // return null;
  // }
  // }

  // private static List<ExtFolderInfo> getExtFolderInfoList2(
  // List<EipTMailFolder> dblist, int parent_id, int target_id,
  // int hierarchy_index) {
  // List<ExtFolderInfo> list = new ArrayList<ExtFolderInfo>();
  // int size = dblist.size();
  // for (int i = 0; i < size; i++) {
  // EipTMailFolder folder = dblist.get(i);
  // if (folder.getParentFolderId().intValue() == parent_id
  // && folder.getFolderId().intValue() == target_id) {
  // ExtFolderInfo info = new ExtFolderInfo();
  // info.setHierarchyIndex(hierarchy_index);
  // info.setFolderId(folder.getFolderId().intValue());
  // info.setParentFolderId(folder.getParentFolderId().intValue());
  // info.setFolderName(folder.getFolderName());
  // list.add(info);
  // }
  // }
  //
  // if (list.size() <= 0) {
  // return null;
  // }
  //
  // int size2 = list.size();
  // for (int i = 0; i < size2; i++) {
  // ExtFolderInfo info = list.get(i);
  // List<ExtFolderInfo> colist =
  // getExtFolderInfoList(dblist, info.getFolderId(), info
  // .getHierarchyIndex() + 1);
  // if (colist != null && colist.size() > 0) {
  // info.setList(colist);
  // }
  // }
  // return list;
  // }

  /**
   * @param dblist
   * @param parent_id
   * @param hierarchy_index
   * @return
   */
  private static List<ExtFolderInfo> getExtFolderInfoList(List<EipTMailFolder> dblist, int parent_id, int hierarchy_index) {
    List<ExtFolderInfo> list = new ArrayList<ExtFolderInfo>();
    int size = dblist.size();
    for (int i = 0; i < size; i++) {
      EipTMailFolder folder = dblist.get(i);
      if (folder.getParentFolderId().intValue() == parent_id) {
        ExtFolderInfo info = new ExtFolderInfo();
        info.setHierarchyIndex(hierarchy_index);
        info.setFolderId(folder.getFolderId().intValue());
        info.setParentFolderId(folder.getParentFolderId().intValue());
        info.setFolderName(folder.getFolderName());
        info.setFolderType(folder.getFolderType());
        info.setFolderKind(folder.getFolderKind());
        list.add(info);
      }
    }

    if (list.size() <= 0) {
      return null;
    }

    int size2 = list.size();
    for (int i = 0; i < size2; i++) {
      ExtFolderInfo info = list.get(i);
      List<ExtFolderInfo> colist = getExtFolderInfoList(dblist, info.getFolderId(), info.getHierarchyIndex() + 1);
      if (colist != null && colist.size() > 0) {
        info.setList(colist);
      }
    }
    return list;
  }

  /**
   * @param list
   * @return
   */
  public static List<ExtFolderInfo> getFolderList(List<ExtFolderInfo> list) {
    try {
      if (list == null || list.size() <= 0) {
        return null;
      }

      List<ExtFolderInfo> res = new ArrayList<ExtFolderInfo>();
      int size = list.size();
      for (int i = 0; i < size; i++) {
        ExtFolderInfo info = list.get(i);
        res.add(info);
        List<ExtFolderInfo> infos = info.getList();
        List<ExtFolderInfo> a = getFolderList(infos);
        if (a != null && a.size() > 0) {
          res.addAll(a);
        }
      }
      return res;
    } catch (Exception e) {
      return null;
    }

  }

  /**
   * @param folder_list
   * @param selectedinfo
   */
  public static void setFolderVisible(List<ExtFolderInfo> folder_list, ExtFolderInfo selectedinfo) {
    if (folder_list == null || folder_list.size() <= 0) {
      return;
    }

    List<ExtFolderInfo> list = new ArrayList<ExtFolderInfo>();
    ExtFolderInfo info = null;
    int hierarchy_index = 0;
    int parent_id = 0;
    int size = folder_list.size() - 1;
    for (int i = size; i >= 0; i--) {
      if (hierarchy_index < 0) {
        break;
      }
      info = folder_list.get(i);
      if (null != selectedinfo && info.getFolderId() == selectedinfo.getFolderId()) {
        /** 新しく開かれたフォルダ */
        info.setOpened(true);
        list.add(0, info);
        parent_id = info.getParentFolderId();
        hierarchy_index = info.getHierarchyIndex() - 1;
      } else if (info.getFolderId() == parent_id) {
        // 親フォルダを捜す
        info.setOpened(true);
        list.add(0, info);
        parent_id = info.getParentFolderId();
        hierarchy_index = info.getHierarchyIndex() - 1;
      }
    }
    /*
     * size = folder_list.size(); for (int i = 0; i < size; i++) { ExtFolderInfo
     * info1 = folder_list.get(i); boolean containsId = false; for (int j = 0; j <
     * list.size(); j++) { ExtFolderInfo info2 = list.get(j); if
     * (info1.getFolderId() == info2.getFolderId()) { containsId = true; break; }
     * else if (info1.getParentFolderId() == info2.getFolderId()) { containsId =
     * true; break; } } if (containsId) { info1.setVisible(true); } else {
     * info1.setVisible(false); } }
     */
  }

  /**
   * メールフォルダ削除
   * <p>
   * 
   * @param mailAccount
   *            アカウント情報オブジェクト
   * @param folder
   *            フォルダ情報オブジェクト
   * @return boolean true;削除成功 false:削除失敗
   * @throws Throwable
   */
  public static boolean deleteFolder(EipMMailAccount mailAccount, EipTMailFolder folder) throws Throwable {

    try {

      if (mailAccount == null) {
        logger.debug("[WebMail Folder] Empty Account...");
        throw new Exception("アカウントが渡されていません。");
      }

      if (folder == null) {
        logger.debug("[WebMail Folder] Empty Folder...");
        throw new Exception("フォルダが渡されていません。");
      }

      // フォルダ内のメール
      List<EipTMail> folderMails = ALMailUtils.getEipTMails(folder);

      // 振り分け先として指定してあるフィルタは、振り分け先をデフォルトに変更
      SelectQuery<EipTMailFilter> query = Database.query(EipTMailFilter.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFilter.EIP_TMAIL_FOLDER_PROPERTY, folder);

      List<EipTMailFilter> filters = query.setQualifier(exp).fetchList();
      if (filters != null && filters.size() != 0) {
        EipTMailFolder defaultFolder = WebMailUtils.getEipTMailFolder(mailAccount, mailAccount.getDefaultFolderId().toString());
        for (EipTMailFilter filter : filters) {
          filter.setEipTMailFolder(defaultFolder);
        }
      }

      // ローカルファイルに保存されているメールのパスのリスト
      List<String> mailPaths = new ArrayList<String>();
      if (folderMails != null && folderMails.size() > 0) {
        for (EipTMail mail : folderMails) {
          mailPaths.add(mail.getFilePath());
        }
      }
      // フォルダ情報を削除
      Database.delete(folder);
      Database.commit();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
        folder.getFolderId(),
        ALEventlogConstants.PORTLET_TYPE_WEBMAIL_FOLDER,
        folder.getFolderName());

      // ローカルファイルに保存されているファイルを削除する．
      if (mailPaths.size() > 0) {
        int size = mailPaths.size();
        for (int k = 0; k < size; k++) {
          ALStorageService.deleteFile(ALMailUtils.getLocalurl() + mailPaths.get(k));
        }
      }
      return true;
    } catch (Throwable t) {
      Database.rollback();
      logger.error(t);
      throw t;
      // return false;
    }

  }

  // add start
  /**
   * ユーザーIDから一括処理情報取得
   * 
   * @return List AvzTMailBatch ログインユーザーの処理ステータス情報
   */
  public static AvzTMailBatch getAvzTMailBatchResultList(int user_id) {
    SelectQuery<AvzTMailBatch> query = Database.query(AvzTMailBatch.class);
    AvzTMailBatch mailBatchRecord = null;
    // 抽出条件
    // Webメール一括処理.ユーザーID = <ログインユーザーID>
    Expression exp = ExpressionFactory.matchExp(AvzTMailBatch.USER_ID_PROPERTY, user_id);
    query.setQualifier(exp);
    mailBatchRecord = query.fetchSingle();
    return mailBatchRecord;
  }

  /**
   * 指定アカウントID,指定フォルダIDからフォルダオブジェクト取得
   * 
   * @param int
   *            account_id
   * @param int
   *            folder_id
   * @return obj フォルダオブジェクト
   */
  public static EipTMailFolder getEipTMailFolder(int account_id, int folder_id) {
    EipTMailFolder res = new EipTMailFolder();

    SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

    Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, account_id);
    query.setQualifier(exp);

    Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFolder.FOLDER_ID_PK_COLUMN, folder_id);
    query.andQualifier(exp2);

    res = query.fetchSingle();
    return res;
  }

  /**
   * 指定アカウントIDのWebメールアドレスを取得する。
   * 
   * @param account_id
   *            アカウントID
   * @return Webメールアカウント
   */
  public static String getEipMMailAddress(int account_id) {

    SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);
    Expression exp = ExpressionFactory.matchDbExp(EipMMailAccount.ACCOUNT_ID_PK_COLUMN, Integer.valueOf(account_id));

    EipMMailAccount dbList = query.setQualifier(exp).fetchSingle();
    return dbList.getMailAddress();
  }

  /**
   * 指定されたパラメータでのEipTMailオブジェクトを取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return List<EipTMail>
   */
  public static List<EipTMail> getEipTMail(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch, boolean isDeleteAfterDownload) {

    List<EipTMail> eipTMailList = new ArrayList<EipTMail>();
    // SelectQuery<EipTMail> query = Database.query(EipTMail.class);
    // Expression exp1 =
    // ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, user_id);
    // query.setQualifier(exp1);
    // Expression exp2 =
    // ExpressionFactory.matchExp(EipTMail.ACCOUNT_ID_PROPERTY, account_id);
    // query.andQualifier(exp2);
    // Expression exp3 =
    // ExpressionFactory.matchExp(EipTMail.FOLDER_ID_PROPERTY, folder_id);
    // query.andQualifier(exp3);
    // if (null != mailBatch.getToDate() && null != mailBatch.getFromDate()) {
    // Expression exp4 =
    // ExpressionFactory.greaterOrEqualExp(
    // EipTMail.EVENT_DATE_PROPERTY,
    // mailBatch.getFromDate());
    // query.andQualifier(exp4);
    // Date src_date = mailBatch.getToDate();
    // Calendar cal = Calendar.getInstance();
    // cal.setTime(src_date);
    // cal.add(Calendar.DATE, 1);
    // Date dest_date = cal.getTime();
    // Expression exp5 =
    // ExpressionFactory.lessExp(EipTMail.EVENT_DATE_PROPERTY, dest_date);
    // query.andQualifier(exp5);
    // }
    SelectQuery<EipTMail> query = getEipTMailQeury(account_id, user_id, folder_id, mailBatch, isDeleteAfterDownload);
    eipTMailList = query.fetchList();
    return eipTMailList;
  }

  /**
   * 指定されたパラメータでのAvzTMailSendオブジェクトを取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return List<AvzTMailSend>
   */
  public static List<AvzTMailSend> getAvzTMailSend(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch, boolean isDeleteAfterDownload) {

    List<AvzTMailSend> avzTMailSend = new ArrayList<AvzTMailSend>();

    // SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);
    // Expression exp1 =
    // ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, user_id);
    // query.setQualifier(exp1);
    // Expression exp2 =
    // ExpressionFactory.matchExp(AvzTMailSend.ACCOUNT_ID_PROPERTY, account_id);
    // query.andQualifier(exp2);
    // Expression exp3 =
    // ExpressionFactory.matchExp(AvzTMailSend.FOLDER_ID_PROPERTY, folder_id);
    // query.andQualifier(exp3);
    // if (null != mailBatch.getToDate() && null != mailBatch.getFromDate()) {
    // Expression exp4 =
    // ExpressionFactory.greaterOrEqualExp(
    // AvzTMailSend.EVENT_DATE_PROPERTY,
    // mailBatch.getFromDate());
    // query.andQualifier(exp4);
    // Date src_date = mailBatch.getToDate();
    // Calendar cal = Calendar.getInstance();
    // cal.setTime(src_date);
    // cal.add(Calendar.DATE, 1);
    // Date dest_date = cal.getTime();
    // Expression exp5 =
    // ExpressionFactory.lessExp(AvzTMailSend.EVENT_DATE_PROPERTY, dest_date);
    // query.andQualifier(exp5);
    // }
    SelectQuery<AvzTMailSend> query = getAvzTMailSendQeury(account_id, user_id, folder_id, mailBatch, isDeleteAfterDownload);
    avzTMailSend = query.fetchList();
    return avzTMailSend;
  }

  /**
   * メールファイルパス生成
   * 
   * @param int
   *            user_id ユーザーID
   * @param int
   *            account_id アカウントID
   * @param int
   *            folder_type フォルダタイプ
   * @param int
   *            file_path ファイルパス
   * @return String メールファイルパス
   */
  public static String createMailFilePath(int user_id, int account_id, String folder_type, String file_path) {
    String homeFilePath = JetspeedResources.getString("aipo.home", "");
    String dest_file_path =
      homeFilePath
        + File.separator
        + "mail"
        + File.separator
        + Database.getDomainName()
        + File.separator
        + user_id
        + File.separator
        + account_id
        + File.separator
        + folder_type
        + File.separator
        + file_path;
    return dest_file_path;
  }

  /**
   * 引数の処理ステータスで更新します
   * 
   * @param AvzTMailBatch
   *            更新データオブジェクト
   * @param String
   *            ステータス
   */
  public static void updateMailBatchData(AvzTMailBatch mailBatch, String process_status) {
    Date now = Calendar.getInstance().getTime();
    // 処理ステータス
    mailBatch.setStatus(process_status);
    // 更新日は処理開始日時の格納用に使用する 2011.1122
    // mailBatch.setUpdateDate(now);
  }

  /**
   * フォルダ種別とフォルダIDからフォルダ内のメール容量を算出し、<フォルダ容量>を返却する。
   * 
   * @param String
   *            folder_type フォルダ種別
   * @param int
   *            folder_id フォルダID
   * @return int folder_volume <フォルダ容量>
   */
  // change start
  // 内部レビュー反映（SUM関数にて取得するように修正）
  // public static int getFolderVolume(int folder_volume, String folder_kind,
  // int folder_id) {
  //
  // if (WebMailConsts.RECEIVE_FOLDER.equals(folder_kind)) {
  // // フォルダ種別が受信トレイの場合
  //
  // // フォルダ内の全メール情報取得
  // SelectQuery<EipTMail> selectFileVolumeQuery =
  // Database.query(EipTMail.class);
  // List<EipTMail> eipTMailFileVolumeList = new ArrayList<EipTMail>();
  // Expression exp13 =
  // ExpressionFactory.matchExp(EipTMail.FOLDER_ID_PROPERTY, folder_id);
  // selectFileVolumeQuery.setQualifier(exp13);
  // eipTMailFileVolumeList = selectFileVolumeQuery.fetchList();
  // if (null == eipTMailFileVolumeList || eipTMailFileVolumeList.size() < 1) {
  // } else {
  // // フォルダ内のメールの容量を全て合算
  // for (int i = 0; i < eipTMailFileVolumeList.size(); i++) {
  // EipTMail fileVolume = eipTMailFileVolumeList.get(i);
  // folder_volume = folder_volume + fileVolume.getFileVolume();
  // }
  // }
  // } else {
  // // フォルダ種別が送信トレイの場合
  //
  // // フォルダ内の全メール情報取得
  // SelectQuery<AvzTMailSend> selectFileVolumeQuery =
  // Database.query(AvzTMailSend.class);
  // List<AvzTMailSend> avzTMailSendFileVolumeList =
  // new ArrayList<AvzTMailSend>();
  // Expression exp14 =
  // ExpressionFactory.matchExp(AvzTMailSend.FOLDER_ID_PROPERTY, folder_id);
  // selectFileVolumeQuery.setQualifier(exp14);
  // avzTMailSendFileVolumeList = selectFileVolumeQuery.fetchList();
  // if (null == avzTMailSendFileVolumeList
  // || avzTMailSendFileVolumeList.size() < 1) {
  // } else {
  // // フォルダ内のメールの容量を全て合算
  // for (int i = 0; i < avzTMailSendFileVolumeList.size(); i++) {
  // AvzTMailSend fileVolume = avzTMailSendFileVolumeList.get(i);
  // folder_volume = folder_volume + fileVolume.getFileVolume();
  // }
  // }
  // }
  // return folder_volume;
  // }
  public static long getFolderVolume(String folder_kind, int folder_id) {
    String volumeSumSql = "";
    List<DataRow> volumelist = null;
    DataRow dataRow;
    long volume = 0;
    if (WebMailConsts.RECEIVE_FOLDER.equals(folder_kind)) {
      // フォルダ種別が受信トレイの場合
      volumeSumSql =
        "SELECT " + " COALESCE(SUM(FILE_VOLUME),0) * 1024 AS FILE_VOLUME " + " FROM EIP_T_MAIL  " + " WHERE FOLDER_ID = #bind($folder_id 'INTEGER') ";
      volumelist = Database.sql(EipTMail.class, volumeSumSql).param("folder_id", folder_id).fetchListAsDataRow();
    } else {
      // フォルダ種別が送信トレイの場合
      volumeSumSql =
        "SELECT " + " COALESCE(SUM(FILE_VOLUME),0) * 1024 AS FILE_VOLUME " + " FROM AVZ_T_MAIL_SEND  " + " WHERE FOLDER_ID = #bind($folder_id 'INTEGER') ";
      volumelist = Database.sql(AvzTMailSend.class, volumeSumSql).param("folder_id", folder_id).fetchListAsDataRow();
    }
    if (null != volumelist && volumelist.size() > 0) {
      dataRow = volumelist.get(0);
      volume = Long.valueOf((Database.getFromDataRow(dataRow, "FILE_VOLUME")).toString());
    }
    return volume;
  }

  // change end
  // add end

  // add start
  /**
   * メールボックス容量情報を取得する。
   * <p>
   * 指定された全アカウントIDのメールフォルダの容量を合算して取得する。<BR>
   * 
   * @param accountIdList
   *            アカウントIDリスト
   * @return WebMailFolderVolumeSummaryBean メールボックス容量情報
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static WebMailFolderVolumeSummaryBean getFolderVolumeSummaryBean(List<Integer> accountIdList) throws Exception {
    try {
      // メールアカウントIDが設定されていない場合
      if ((null == accountIdList) || accountIdList.size() == 0) {
        return null;
      }

      // 全アカウントIDのフォルダ取得
      List<EipTMailFolder> folderList = new ArrayList<EipTMailFolder>();
      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);
      Expression exp = ExpressionFactory.inDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, accountIdList);

      folderList = query.setQualifier(exp).fetchList();

      // メールボックス容量算出（全アカウントのフォルダ容量合算）
      // Integer folderVolumeSummary = 0;
      long folderVolumeSummary = 0L;
      for (int i = 0; i < folderList.size(); i++) {
        folderVolumeSummary += folderList.get(i).getFolderVolume();
      }

      // メールボックス容量はMBで返す
      folderVolumeSummary = folderVolumeSummary / 1024 / 1024;

      // １ユーザーのメール容量上限(MB)の取得
      BigDecimal folderVolumeMax = new BigDecimal(Integer.parseInt(getMailVolumeMax()));

      // フォルダ使用率の算出
      // フォルダ容量計(MB) / フォルダ最大容量(MB) × 100
      BigDecimal percentage = new BigDecimal(folderVolumeSummary).divide(folderVolumeMax, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));

      // メールフォルダ容量合計情報設定
      WebMailFolderVolumeSummaryBean folderVolumeSummaryBean = new WebMailFolderVolumeSummaryBean();
      folderVolumeSummaryBean.initField();
      // メールボックス使用率
      folderVolumeSummaryBean.setMailBoxVolumePct(percentage.intValue());
      // メールボックス未使用率
      if (percentage.intValue() > 100) {
        folderVolumeSummaryBean.setMailBoxVolumeEmptyPct(0);
      } else {
        folderVolumeSummaryBean.setMailBoxVolumeEmptyPct(100 - percentage.intValue());
      }
      // メールボックス容量計(MB)
      folderVolumeSummaryBean.setFolderVolumeSummary(folderVolumeSummary);

      return folderVolumeSummaryBean;

    } catch (Exception ex) {
      logger.error("フォルダ容量合計の取得に失敗しました。　", ex);
      throw ex;
    }
  }

  /**
   * １ユーザーあたりのメールボックスの容量上限を取得する。
   * <p>
   * 設定ファイルより取得する。<BR>
   * 
   * @return フォルダ最大容量(MB)
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static String getMailVolumeMax() throws Exception {
    try {

      // プロパティファイルから設定読み込み
      Properties prop = new Properties();
      prop.load(new FileInputStream(SETTING_FILE_PATH));

      return prop.getProperty("mailbox_volume_max");

    } catch (Exception ex) {
      logger.error("メールボックス容量上限取得に失敗しました。 ", ex);
      throw ex;
    }
  }

  /**
   * ファイル名を指定してメールファイルを取得します。<BR>
   * 
   * @param userId
   *            ユーザーID
   * @param accountId
   *            アカウントID
   * @param type
   *            メール種別
   * @param fileName
   *            メールファイル名
   * @return メールファイル
   * @throws Exception
   */
  public static File getMailFile(int userId, int accountId, String type, String fileName) throws Exception {

    try {
      // メール種別よりディレクトリ名を判別
      String dirName = null;
      // 受信の場合
      if (type.equals(ALMailUtils.FOLDER_KIND_RECEIVE)
        || type.equals(TAB_RECEIVE)
        || type.equals(WebMailConsts.RECEIVE_FOLDER)
        || type.equals(WebMailConsts.STR_RECEIVE_FOLDER_NAME)) {
        dirName = WebMailConsts.STR_RECEIVE_FOLDER_NAME;
      }
      // 送信の場合
      if (type.equals(ALMailUtils.FOLDER_KIND_SEND)
        || type.equals(TAB_SENT)
        || type.equals(WebMailConsts.SEND_FOLDER)
        || type.equals(WebMailConsts.STR_SEND_FOLDER_NAME)) {
        dirName = WebMailConsts.STR_SEND_FOLDER_NAME;
      }
      // 対象となるメールファイルを取得
      File src_file = new File(WebMailUtils.createMailFilePath(userId, accountId, dirName, fileName));
      return src_file;

    } catch (Exception e) {
      throw e;
    }

  }

  /**
   * メールのファイル名を変更して返す。
   * <p>
   * 件名 + 送信日時(yyyyMMddHHMMSS) + 拡張子(.eml) <BR>
   * 
   * @param subject
   *            件名
   * @param eventDate
   *            送信日時
   * @return 変更後ファイル名
   */
  public static String getRenameMailFile(String subject, Date eventDate, int sequenceNumber) {

    // フォルダ名に使用する日付フォーマット
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    // ファイル拡張子名
    String EML_EXTENSION = ".eml";

    // 件名のデコード
    String decode_subject = ALMailUtils.decodeSubject(subject);
    decode_subject = decode_subject.replaceAll("[\t:\"|/*<>?\\\\]", "");

    // ファイル名を拡張子まで含め255バイト以内とする必要があるため、件名を先頭の60文字までとする
    // if (decode_subject.length() > 182) {
    // decode_subject = decode_subject.substring(0, 182);
    // }
    if (decode_subject.length() > 60) {
      decode_subject = decode_subject.substring(0, 60);
    }
    // リネームファイル名(ファイル名を変更し、emlファイルとする。)
    // change start 2012.1.20 受入障害No.223 同一ファイル名対応
    // return decode_subject + sdf.format(eventDate) + EML_EXTENSION;
    return decode_subject + sdf.format(eventDate) + "_" + sequenceNumber + EML_EXTENSION;
    // change end
  }

  /**
   * ダウンロードしたメールファイルの格納ディレクトリを生成します
   * <p>
   * ディレクトリ名は<パラメータ.ディレクトリパス>/フォルダ名_現在日時/ <BR>
   * 
   * @param accountId
   *            アカウントID
   * @param folderId
   *            フォルダID
   * @param directoryPath
   *            ディレクトリパス
   * @return 格納ディレクトリ
   * @throws UnsupportedEncodingException
   */
  public static File makeFileDownloadDirectory(int accountId, int folderId, String directoryPath) throws UnsupportedEncodingException {

    // 作業ディレクトリを一旦削除する
    File tmp = new File(directoryPath);
    if (tmp.exists()) {
      deleteFolder(tmp);
    }

    // ディレクトリ名に使用するシステム日付
    Date now = Calendar.getInstance().getTime();
    // ディレクトリ名に使用する日付フォーマット
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    // フォルダ情報取得
    EipTMailFolder folder = getEipTMailFolder(accountId, folderId);

    // 出力先ディレクトリ生成
    File downloadDirectory =
    // new File(directoryPath
      // + userId
      // + "_"
      // + accountId
      // + "_"
      // + sdf.format(now)
      // + File.separator);
      new File(directoryPath + folder.getFolderName() + "_" + sdf.format(now) + File.separator);
    if (!downloadDirectory.exists()) {
      downloadDirectory.mkdirs();
    }
    return downloadDirectory;
  }

  /**
   * メールファイルをダウンロードディレクトリにコピーする。<BR>
   * 
   * @param userId
   *            ユーザーID
   * @param accountId
   *            アカウントID
   * @param type
   *            メール種別（受信or送信）
   * @param mailFileName
   *            コピー元メールファイル名
   * @param subject
   *            コピー元メール件名
   * @param eventDate
   *            コピー元メール送信日時
   * @param downloadDirectory
   *            コピー先ディレクトリ
   * @return boolean true:処理成功
   * @throws Exception
   */
  public static File copyMailFileToDownloadDirectory(int userId, int accountId, String type, String mailFileName, String subject, Date eventDate,
      File downloadDirectory, int sequenceNumber) throws Exception {

    File destFile = null;

    try {
      // 退避対象となるメールファイルを取得
      File mailFile = getMailFile(userId, accountId, type, mailFileName);

      if (mailFile.exists()) {
        // ファイル名を件名＋送信日時に変更し、emlファイルとする。)
        String renameFileName = getRenameMailFile(subject, eventDate, sequenceNumber);
        // 出力先ディレクトリ+リネームファイル
        destFile = new File(downloadDirectory + File.separator + renameFileName);
        // 読み込んだメールファイルを出力先ディレクトリに出力する。
        FileUtils.copyFile(mailFile, destFile);

      } else {
        logger.warn("退避対象のメールファイルがありません。ユーザーID=" + userId + "アカウントID=" + accountId + "メール種別=" + type + "メールファイル名" + mailFileName);
      }

      return destFile;
    } catch (Exception e) {
      throw e;
    }
  }

  /**
   * 退避ファイルダウンロード処理
   * <p>
   * ファイルをダウンロードするダイアログを表示する<BR>
   * 
   * @param rundata
   * @param downloadDirectory
   *            ダウンロードファイル格納ディレクトリ
   * @param downloadFileName
   *            ダウンロードファイル名
   * @param deleteFile
   *            ダウンロード後ファイルを削除する場合true
   * @return boolean true:ダウンロード成功
   * @throws Exception
   * @throws IOException
   */
  public static boolean downloadFile(RunData rundata, String downloadDirectory, String downloadFileName, boolean deleteFile) throws Exception {

    HttpServletResponse response = rundata.getResponse();
    // change start
    // 内部レビュー反映
    // // ダウンロードファイル
    // File download_file = new File(downloadDirectory + downloadFileName);
    //
    // // 処理
    // FileInputStream fin = new
    // FileInputStream(download_file.getAbsolutePath());
    // // ファイル読み込み用バッファ
    // byte buffer[] = new byte[fin.available()];
    // // contentTypeを出力
    // response.setContentType("application/octet-stream");
    // // ファイル名の送信
    // response.setHeader("Content-disposition", "attachment; filename=\""
    // + downloadFileName
    // + "\"");
    // // ファイル内容の出力
    // ServletOutputStream out = response.getOutputStream();
    // int size;
    // // ファイルの読み込みが成功した場合、ファイルをレスポンスに出力する。
    // while ((size = fin.read(buffer)) != -1) {
    // out.write(buffer, 0, size);
    // }
    // fin.close();
    // out.flush();
    // out.close();

    // ダウンロードファイル
    File download_file = new File(downloadDirectory + downloadFileName);
    FileInputStream fin = null;
    ServletOutputStream out = null;
    try {
      // 処理
      fin = new FileInputStream(download_file.getAbsolutePath());
      // ファイル読み込み用バッファ
      byte buffer[] = new byte[4096];
      // contentTypeを出力
      response.setContentType("application/octet-stream");
      // ファイル名の送信
      response.setHeader("Content-disposition", "attachment; filename=\"" + URLEncoder.encode(downloadFileName, "UTF-8") + "\"");
      // ファイル内容の出力
      out = response.getOutputStream();
      int size;
      // ファイルの読み込みが成功した場合、ファイルをレスポンスに出力する。
      while ((size = fin.read(buffer)) != -1) {
        out.write(buffer, 0, size);
      }
      // add start
    } catch (Exception ex) {
      logger.error("退避ファイルダウンロード処理に失敗", ex);
      throw ex;
      // add end
    } finally {
      try {
        fin.close();
      } catch (IOException ioe) {
        logger.error(ioe);
      }
      try {
        out.flush();
      } catch (IOException ioe) {
        logger.error(ioe);
      }
      try {
        out.close();
      } catch (IOException ioe) {
        logger.error(ioe);
      }
      // ダウンロード完了後削除
      if (deleteFile) {
        if (!FileUtils.deleteQuietly(download_file)) {
          logger.error("退避ファイルダウンロード完了後のファイル削除に失敗。対象ファイルパス：" + download_file.getAbsolutePath());
        }
      }
    }
    return true;
  }

  /**
   * アカウントIDよりメールアカウント情報を取得する。
   * <p>
   * 
   * @param accountId
   *            アカウントID
   * @return メールアカウント情報
   * @throws Exception
   */
  public static EipMMailAccount getMailAccount(int accountId) throws Exception {
    if (accountId < 0) {
      return null;
    }

    try {

      SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);
      Expression exp1 = ExpressionFactory.matchDbExp(EipMMailAccount.ACCOUNT_ID_PK_COLUMN, Integer.valueOf(accountId));

      EipMMailAccount account = query.andQualifier(exp1).fetchSingle();
      if (account == null) {
        logger.debug("[WebMail] Not found AccountID...");
        return null;
      }
      return account;
    } catch (Exception ex) {
      throw ex;
    }
  }

  /**
   * WebメールアカウントのBeanを返します。
   * <p>
   * 
   * @param account
   *            メールアカウント情報
   * @return WebメールアカウントBean
   */
  public static WebmailAccountLiteBean getWebmailAccountLiteBean(EipMMailAccount account, boolean attachPosition) {

    WebmailAccountLiteBean bean = new WebmailAccountLiteBean();
    bean.initField();
    bean.setAccountId(account.getAccountId());
    String name = account.getAccountName();

    if (attachPosition) {
      // 代理送信元アカウントの部署・役職情報取得
      List<UserGroupPositionLiteBean> userPostPositionList = UserUtils.getPostPositionBeanList(account.getUserId());

      if (userPostPositionList != null && userPostPositionList.size() > 0) {
        UserGroupPositionLiteBean userPostPosition = userPostPositionList.get(0);
        if (!(null == userPostPosition.getPositionName()) && userPostPosition.getPositionName().length() > 0) {
          name = name + " (" + userPostPosition.getPositionName() + ")";
        }
      }
    }

    bean.setAccountName(name);
    // add start 2012.2.24 受入障害No.294
    String countUnRead;
    countUnRead = getCountUnRead(account.getAccountId());
    bean.setCountUnRead(countUnRead);
    // add end 2012.2.24
    return bean;

  }

  /**
   * ユーザーのよりデフォルトメールアカウント情報を取得する。
   * <p>
   * ユーザーIDのメールアカウントを全て取得し、その1件目を返す。<br>
   * 
   * @param userId
   *            ユーザーID
   * @return メールアカウント情報
   * @throws Exception
   */
  // public static EipMMailAccount getDefaultMailAccount(int userId)
  // throws Exception {
  // if (userId < 0) {
  // return null;
  // }
  //
  // try {
  // Expression exp =
  // ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, userId);
  // SelectQuery<EipMMailAccount> query =
  // Database.query(EipMMailAccount.class, exp);
  //
  // List<EipMMailAccount> accounts = query.fetchList();
  // if (accounts != null && accounts.size() > 0) {
  // return accounts.get(0);
  // } else {
  // return null;
  // }
  // } catch (Exception ex) {
  // throw ex;
  // }
  // }
  public static EipMMailAccount getDefaultMailAccount(int userId) throws Exception {
    if (userId < 0) {
      return null;
    }

    // プライマリアドレスを取得
    ALBaseUser user = ALEipUtils.getBaseUser(userId);
    String email = user.getEmail();

    // プライマリアドレスに紐づくメールアカウントを取得
    SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);
    // query.select(EipMMailAccount.ACCOUNT_ID_PK_COLUMN);
    // query.select(EipMMailAccount.ACCOUNT_NAME_COLUMN);
    // query.select(EipMMailAccount.USER_ID_COLUMN);
    Expression exp1 = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
    Expression exp2 = ExpressionFactory.matchExp(EipMMailAccount.MAIL_ADDRESS_PROPERTY, email);
    List<EipMMailAccount> list = query.setQualifier(exp1).andQualifier(exp2).fetchList();

    if (list == null || list.size() == 0) {

      // プライマリに紐づくメールアカウントが無い場合は、他のアカウントを取得する。
      SelectQuery<EipMMailAccount> query2 = Database.query(EipMMailAccount.class);

      // query2.select(EipMMailAccount.ACCOUNT_ID_PK_COLUMN);
      // query2.select(EipMMailAccount.ACCOUNT_NAME_COLUMN);
      // query2.select(EipMMailAccount.USER_ID_COLUMN);

      Expression exp = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));

      list = query2.setQualifier(exp).fetchList();
    }

    if (list == null || list.size() == 0) {
      return null;
    }

    return list.get(0);
  }

  /**
   * 退避ファイルＺＩＰの配置ディレクトリ取得
   * 
   * @param user_id
   * @return
   * @author motegi 2011.11.09
   */
  public static String getDownloadFileDir(int user_id) {

    // ダウンロードディレクトリパス
    String tmpFilePath = JetspeedResources.getString("aipo.ziptmp.directory", "");
    String downloadDirectory = tmpFilePath + File.separator + "download" + File.separator + user_id + File.separator;

    return downloadDirectory;

  }

  /**
   * 退避ファイルＺＩＰパス名取得
   * 
   * @param user_id
   * @return
   * @author motegi 2011.11.09
   */
  public static String getDownloadFilePath(int user_id) {

    // ダウンロードファイル名
    AvzTMailBatch mailBatch = WebMailUtils.getAvzTMailBatchResultList(user_id);
    String download_file_name = mailBatch.getFileName();

    return getDownloadFileDir(user_id) + File.separator + download_file_name;

  }

  /**
   * 一括処理対象の指定されたパラメータでのEipTMailオブジェクト数を取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return レコード件数
   */
  public static int getEipTMailCount(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch) {
    SelectQuery<EipTMail> query = getEipTMailQeury(account_id, user_id, folder_id, mailBatch, false);
    return query.getCount();
  }

  /**
   * 一括処理対象の指定されたパラメータでのEipTMailオブジェクト数を取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return レコード件数
   */
  public static int getAvzTMailSendCount(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch) {
    SelectQuery<AvzTMailSend> query = getAvzTMailSendQeury(account_id, user_id, folder_id, mailBatch, false);
    return query.getCount();
  }

  /**
   * 一括処理対象受信メール取得用ＳＱＬオブジェクトを構築
   * 
   * @param account_id
   * @param user_id
   * @param folder_id
   * @param mailBatch
   * @return
   */
  private static SelectQuery<EipTMail> getEipTMailQeury(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch, boolean isDeleteAfterDownload) {

    SelectQuery<EipTMail> query = Database.query(EipTMail.class);
    Expression exp1 = ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, user_id);
    query.setQualifier(exp1);
    Expression exp2 = ExpressionFactory.matchExp(EipTMail.ACCOUNT_ID_PROPERTY, account_id);
    query.andQualifier(exp2);
    if (!isRootFolder(folder_id)) {
      Expression exp3 = ExpressionFactory.matchExp(EipTMail.FOLDER_ID_PROPERTY, folder_id);
      query.andQualifier(exp3);
    }
    if (null != mailBatch.getToDate() && null != mailBatch.getFromDate()) {
      Expression exp4 = ExpressionFactory.greaterOrEqualExp(EipTMail.EVENT_DATE_PROPERTY, mailBatch.getFromDate());
      query.andQualifier(exp4);
      Date src_date = mailBatch.getToDate();
      Calendar cal = Calendar.getInstance();
      cal.setTime(src_date);
      cal.add(Calendar.DATE, 1);
      Date dest_date = cal.getTime();
      Expression exp5 = ExpressionFactory.lessExp(EipTMail.EVENT_DATE_PROPERTY, dest_date);
      query.andQualifier(exp5);
    }

    if (isDeleteAfterDownload) {
      Expression exp6 =
      // change start 2012.2.15 受入障害対応No.287
        // 削除対象メールの判定基準を「eventDate」から「createDate」に変更
        // 未来日付対応
        // ExpressionFactory.lessExp(EipTMail.EVENT_DATE_PROPERTY, mailBatch
        ExpressionFactory.lessExp(EipTMail.CREATE_DATE_PROPERTY, mailBatch
        // change end
          .getUpdateDate());
      query.andQualifier(exp6);
    }
    query.select(EipTMail.EVENT_DATE_COLUMN);
    query.select(EipTMail.FILE_PATH_COLUMN);
    query.select(EipTMail.SUBJECT_COLUMN);
    query.select(EipTMail.FILE_VOLUME_COLUMN);
    query.select(EipTMail.MAIL_ID_PK_COLUMN);
    return query;
  }

  /**
   * 一括処理対象送信メール取得用ＳＱＬオブジェクトを構築
   * 
   * @param account_id
   * @param user_id
   * @param folder_id
   * @param mailBatch
   * @return
   */
  private static SelectQuery<AvzTMailSend> getAvzTMailSendQeury(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch,
      boolean isDeleteAfterDownload) {
    SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);
    Expression exp1 = ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, user_id);
    query.setQualifier(exp1);
    Expression exp2 = ExpressionFactory.matchExp(AvzTMailSend.ACCOUNT_ID_PROPERTY, account_id);
    query.andQualifier(exp2);
    if (!isRootFolder(folder_id)) {
      Expression exp3 = ExpressionFactory.matchExp(AvzTMailSend.FOLDER_ID_PROPERTY, folder_id);
      query.andQualifier(exp3);
    }
    if (null != mailBatch.getToDate() && null != mailBatch.getFromDate()) {
      Expression exp4 = ExpressionFactory.greaterOrEqualExp(AvzTMailSend.EVENT_DATE_PROPERTY, mailBatch.getFromDate());
      query.andQualifier(exp4);
      Date src_date = mailBatch.getToDate();
      Calendar cal = Calendar.getInstance();
      cal.setTime(src_date);
      cal.add(Calendar.DATE, 1);
      Date dest_date = cal.getTime();
      Expression exp5 = ExpressionFactory.lessExp(AvzTMailSend.EVENT_DATE_PROPERTY, dest_date);
      query.andQualifier(exp5);
    }

    if (isDeleteAfterDownload) {
      Expression exp6 =
      // change start 2012.2.15 受入障害対応No.287
        // 削除対象メールの判定基準を「eventDate」から「createDate」に変更
        // 未来日付対応
        // ExpressionFactory.lessExp(AvzTMailSend.EVENT_DATE_PROPERTY, mailBatch
        ExpressionFactory.lessExp(AvzTMailSend.CREATE_DATE_PROPERTY, mailBatch
        // change end
          .getUpdateDate());
      query.andQualifier(exp6);
    }

    query.select(AvzTMailSend.EVENT_DATE_COLUMN);
    query.select(AvzTMailSend.FILE_PATH_COLUMN);
    query.select(AvzTMailSend.SUBJECT_COLUMN);
    query.select(AvzTMailSend.FILE_VOLUME_COLUMN);
    query.select(AvzTMailSend.MAIL_ID_PK_COLUMN);
    return query;
  }

  /**
   * フォルダ削除
   * 
   * @param File
   *            削除フォルダ
   */
  public static void deleteFolder(File f) {
    if (f.exists() == false) {
      return;
    }

    if (f.isFile()) {
      f.delete();
    }

    if (f.isDirectory()) {
      File[] files = f.listFiles();
      for (int i = 0; i < files.length; i++) {
        deleteFolder(files[i]);
      }
      f.delete();
    }
  }

  // add end

  // add start
  /**
   * 開封確認
   * <p>
   * 受信メールが開封確認要求付きメッセージであれば返信する。<BR>
   * 
   * @param to
   *            開封通知送信先アドレス
   * @param msg
   *            受信メール情報
   * @param userId
   *            受信ユーザーID（=ログインユーザーID）
   * @param accountId
   *            実際に受信したユーザーのアカウントID
   * @param representAccountId
   *            代理受信した場合の対象アカウントID（代理受信でない場合は０）
   * @throws MessagingException
   *             受信メール情報の取得に失敗した場合スローします。
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static void sendReplyForDispositionNotification(String to, ALLocalMailMessage msg, int userId, int accountId, int representAccountId, String orgId)
      throws MessagingException, Exception {

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

      // オブジェクトモデルを取得
      String opener = null;
      if (representAccountId != 0) {
        EipMMailAccount representAccount = ALMailUtils.getMailAccount(representAccountId);
        opener = representAccount.getMailUserName() + "<" + representAccount.getMailAddress() + ">";
      } else {
        opener = account.getMailUserName() + "<" + account.getMailAddress() + ">";
      }

      String subject = "開封済み_" + msg.getSubject();
      String body = "次のユーザーに送信されたメッセージの開封確認です :" + opener + "\r\n\r\n" + "メッセージが、次の時間に開封されました : " + ALMailUtils.translateDate(new Date());
      String delim = ",";

      String messageID = msg.getMessageID();
      Map<String, String> map = new LinkedHashMap<String, String>();
      map.put("References", messageID);

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

      ALSmtpMailContext mailcontext =
        ALMailUtils.getALSmtpMailContext(ALMailUtils.getTokens(ALStringUtil.unsanitizing(to), delim), null, null, account.getMailAddress(), ALStringUtil
          .unsanitizing(account.getMailUserName()), ALStringUtil.unsanitizing(subject), ALStringUtil.unsanitizing(body), null, map, false, true, false);

      int success_send = handler.send(scontext, mailcontext);
      if (success_send == ALSmtpMailSender.SEND_MSG_SUCCESS) {

      } else {
        if (success_send == ALSmtpMailSender.SEND_MSG_FAIL) {
          logger.error("メールを送信できませんでした。アカウント設定が間違っている可能性があります。");
        } else if (success_send == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
          logger.error("7MB を超えるサイズのメールは送信できません。");
        } else if (success_send == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
          logger.error("メールを送信できませんでした。SMTP認証の認証に失敗しました。");
        }
      }
    } catch (MessagingException e) {
      String Errmsg = "開封確認メールを送信できませんでした。[" + ALEipUtils.getBaseUser(userId).getUserName() + "]";
      logger.error(Errmsg, e);
      throw e;
    } catch (Exception e) {
      String Errmsg = "開封確認メールを送信できませんでした。[" + ALEipUtils.getBaseUser(userId).getUserName() + "]";
      logger.error(Errmsg, e);
      throw e;
    }
  }

  /**
   * 「全員へ返信」フォーム表示用 myAddressと一致するアドレスをaddressesから除いて返却する。
   * 
   * @param addresses
   *            アドレスリスト
   * @param myAddress
   *            現アカウントのアドレス
   * @return myAddressと一致するアドレスをaddressesから除いて返却する。
   * 
   */
  public static javax.mail.Address[] removeMyAddress(javax.mail.Address[] addresses, String myAddress) {

    if (addresses == null || addresses.length <= 0) {
      return new javax.mail.Address[0];
    }

    List<javax.mail.Address> tmpList = new ArrayList<javax.mail.Address>();

    for (javax.mail.Address addr : addresses) {

      String tmp = getMailAddressFromAddressString(addr);
      if (myAddress.equals(tmp)) {
        // 自分のアドレスはスキップ
        // System.out.println("自分のアドレスはスキップ" + tmp);
        continue;
      }
      tmpList.add(addr);
    }

    return tmpList.toArray(new javax.mail.Address[tmpList.size()]);

  }

  /**
   * メールアドレスのみを取得する。
   * 
   * @param address
   *            xxx@yyy.zzzz もしくは ＡＡＡ<xxx@yyy.zzzz>
   * @return メールアドレス（xxx@yyy.zzzz）
   */
  public static String getMailAddressFromAddressString(javax.mail.Address address) {
    // アドレスを"<"で分割
    String[] tmp = address.toString().split("<");
    // アドレスに"<"が含まれていない場合、そのまま送信先アドレスを返す
    int addressSplitLength = tmp.length;
    if (addressSplitLength == 1) {
      return address.toString();
    }
    // 送信先アドレスに"<"が含まれている場合
    // String tmpAddress = address.toString();
    String tmpAddress = tmp[1];
    // さらに">"で分割し、その１個目を返す
    tmp = tmpAddress.split(">");
    return tmp[0];
  }

  /**
   * フォルダがルートフォルダかどうか判別
   * 
   * @param int
   *            folder_id
   * @return ルートフォルダである:true ルートフォルダでない:false
   */
  public static boolean isRootFolder(int folder_id) {
    SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

    Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.FOLDER_ID_PK_COLUMN, folder_id);
    query.setQualifier(exp);
    EipTMailFolder res = query.fetchSingle();
    if (res.getParentFolderId().intValue() == 0) {
      return true;
    }
    return false;
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static List<EipTMailFolder> getEipTMailFolderAll(int accountid, String folder_kind) throws Exception {
    try {

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, accountid);

      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);

      List<EipTMailFolder> folder_list = query.andQualifier(exp).andQualifier(exp2).fetchList();

      if (folder_list == null || folder_list.size() == 0) {
        logger.debug("[WebMail Folder] Not found ID...");
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + accountid + " フォルダ種別=" + folder_kind);
      }
      return folder_list;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
      // return null;
    }
  }

  // add end

  // add start 2012.2.24 受入障害No.294
  // 2012.3.3 getCountメソッドに変更
  private static String getCountUnRead(int accountId) {
    String countUnRead = "";
    try {
      SelectQuery<EipMMailAccount> acountQuery = Database.query(EipMMailAccount.class);
      Expression accountExp1 = ExpressionFactory.matchDbExp(EipMMailAccount.ACCOUNT_ID_PK_COLUMN, accountId);
      acountQuery.select("account_usage");
      EipMMailAccount eipMMailAccount = acountQuery.andQualifier(accountExp1).fetchSingle();
      // 会議室ユーザー「"1"」のみ未読数を取得する。
      if ("1".equals(eipMMailAccount.getAccountUsage())) {
        SelectQuery<EipTMail> query = Database.query(EipTMail.class);
        Expression exp1 = ExpressionFactory.matchDbExp("ACCOUNT_ID", accountId);
        Expression exp2 = ExpressionFactory.matchDbExp(EipTMail.READ_FLG_COLUMN, "F");
        query.select(EipTMail.MAIL_ID_PK_COLUMN);
        int count = query.andQualifier(exp1).andQualifier(exp2).getCount();
        countUnRead = "(" + count + ")";
      }
    } catch (Exception e) {
      logger.error("メールアカウントプルダウン表示用の未読数取得に失敗しました。", e);
      return countUnRead;
    }
    return countUnRead;
  }

  // add end 2012.2.24

  // add start カーソル処理へ変更
  /**
   * 指定されたパラメータでのEipTMailオブジェクトを取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return List<EipTMail>
   * @throws Exception
   */
  public static ResultIterator getEipTMailResultIterator(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch, boolean isDeleteAfterDownload)
      throws Exception {

    SelectQuery<EipTMail> query = getEipTMailQeury(account_id, user_id, folder_id, mailBatch, isDeleteAfterDownload);

    DataContext dataContext = DataContext.getThreadDataContext();
    return dataContext.performIteratedQuery(query.getQuery());
  }

  /**
   * 指定されたパラメータでのAvzTMailSendオブジェクトを取得する。
   * 
   * @param int
   *            account_id アカウントID
   * @param int
   *            user_id ユーザーID
   * @param int
   *            folder_id フォルダID
   * @param AvzTMailBatch
   *            mailBatch mailBatchオブジェクト
   * @return List<AvzTMailSend>
   * @throws CayenneException
   */
  public static ResultIterator getAvzTMailSendResultIterator(int account_id, int user_id, int folder_id, AvzTMailBatch mailBatch, boolean isDeleteAfterDownload)
      throws CayenneException {

    SelectQuery<AvzTMailSend> query = getAvzTMailSendQeury(account_id, user_id, folder_id, mailBatch, isDeleteAfterDownload);

    DataContext dataContext = DataContext.getThreadDataContext();
    return dataContext.performIteratedQuery(query.getQuery());
  }

  /**
   * ユーザーIDから一括処理情報取得
   * 
   * @return List AvzTMailBatch ログインユーザーの処理ステータス情報
   * @throws Exception
   */
  public static AvzTMailBatch getAvzTMailBatchResultListOnOtherTran(int user_id) {

    SelectQuery<AvzTMailBatch> query = Database.query(AvzTMailBatch.class);
    Expression exp = ExpressionFactory.matchExp(AvzTMailBatch.USER_ID_PROPERTY, user_id);
    query.setQualifier(exp);

    DataContext dataContext = DataContext.getThreadDataContext();

    // 標準のトランザクション（オートコミット）
    Transaction baseTx = Transaction.getThreadTransaction();

    // 自己管理トランザクション
    Transaction tx = Transaction.internalTransaction(DataContext.getThreadDataContext().getParentDataDomain().getTransactionDelegate());

    // 標準のトランザクションを自己管理トランザクションに置き換えます。
    Transaction.bindThreadTransaction(tx);

    AvzTMailBatch mailBatch = null;
    boolean error = false;
    try {
      // トランザクション開始
      tx.begin();

      List<AvzTMailBatch> list = dataContext.performQuery(query.getQuery());
      if (list == null || list.size() == 0) {
        throw new Exception("一括処理状態レコードの取得に失敗しました。ユーザー名[" + ALEipUtils.getUserFullName(user_id) + "] ユーザーID[" + user_id + "]");
      }
      mailBatch = list.get(0);

    } catch (Exception e) {
      error = true;
      logger.error("一括処理状態の取得で例外が発生しました。", e);
      try {
        tx.rollback();
      } catch (IllegalStateException e1) {
        logger.error("一括処理状態の取得で例外が発生しました。", e1);
      } catch (SQLException e1) {
        logger.error("一括処理状態の取得で例外が発生しました。", e1);
      } catch (CayenneException e1) {
        logger.error("一括処理状態の取得で例外が発生しました。", e1);
      }
    } finally {
      if (!error) {
        try {
          tx.commit();
        } catch (IllegalStateException e) {
          logger.error("一括処理状態の取得で例外が発生しました。", e);
        } catch (SQLException e) {
          logger.error("一括処理状態の取得で例外が発生しました。", e);
        } catch (CayenneException e) {
          logger.error("一括処理状態の取得で例外が発生しました。", e);
        }
      }
      Transaction.bindThreadTransaction(baseTx);
    }
    return mailBatch;
  }

  // add start 受入テスト障害331
  /**
   * 表示名取得
   * 
   * @param address
   *            メールアドレス
   * @param loginUserId
   *            ログインユーザーID
   * 
   * @return 表示名（表示名が取得できない場合は、メールアドレス）
   */
  public static String getDisplayName(String address, int loginUserId) {

    String name = address;
    try {
      // 個人アドレス帳を検索する。
      EipMAddressbook ext =
        Database.query(EipMAddressbook.class).where(
          Operations.eq(EipMAddressbook.OWNER_ID_PROPERTY, loginUserId),
          Operations.eq(EipMAddressbook.EMAIL_PROPERTY, address)).fetchSingle();
      if (ext == null) {
        return null;
      }
      name = ext.getLastName();
      if (ext.getFirstName() != null && !"".equals(ext.getFirstName())) {
        name = name + " " + ext.getFirstName();
      }
    } catch (Exception e) {
      logger.error("個人アドレス帳からの差出人表示名取得に失敗しました。" + ALEipUtils.getUserFullName(loginUserId), e);
    }

    return name;
  }
  // add end
}
