/*
 * 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.mail.file;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.jar.Attributes;

import javax.mail.Header;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;

import com.aimluck.eip.cayenne.om.portlet.AvzTMailSend;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.cayenne.om.portlet.EipTMail;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFolder;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.mail.ALAbstractFolder;
import com.aimluck.eip.mail.ALFolder;
import com.aimluck.eip.mail.ALLocalMailMessage;
import com.aimluck.eip.mail.ALMailMessage;
import com.aimluck.eip.mail.beans.ALMailSearchCondition;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.services.storage.ALStorageService;

/**
 * ローカルのファイルシステムを利用し、送受信したメールを保持するローカルフォルダのクラスです。 <br />
 * 
 */
public class ALFileLocalFolder extends ALAbstractFolder {

  private static final JetspeedLogger logger =
    JetspeedLogFactoryService.getLogger(ALFileLocalFolder.class.getName());

  /** メールのファイル名規則 */
  public static final String DEFAULT_MAIL_FILENAME_DATE_FORMAT =
    "yyyyMMddHHmmssSSS";

  /**
   * コンストラクタ
   * 
   * @param parentFolder
   *            親フォルダ
   * @param folderName
   *            自身のフォルダ名
   */
  public ALFileLocalFolder(int type_mail, String org_id, int user_id,
      int account_id) {
    super(type_mail, org_id, user_id, account_id);
  }

  // add start
  // 全文検索
  public ALFileLocalFolder(int type_mail, String org_id, int user_id,
      int account_id, ALMailSearchCondition cond) {
    super(type_mail, org_id, user_id, account_id, cond);
  }

  // add end

  /**
   * メールを取得します。<BR>
   * 
   * @param mailid
   *            メールID
   * @return ALLocalMailMessage メール情報
   * @throws Throwable
   */
  @Override
  // public ALLocalMailMessage getMail(int mailid) throws Throwable {
  // change start 2012.2.24 受入障害No.294
  // 引数にアカウント用途を追加(通常ユーザー:"0" 会議室ユーザー:"1")
  // public ALLocalMailMessage getMail(int mailid, boolean isRepresent)
  public ALLocalMailMessage getMail(int mailid, boolean isRepresent,
      String accountUsage)
  // change end 2012.2.24 受入障害No.294
      throws Throwable {
    try {
      // change start

      // SelectQuery<EipTMail> query = Database.query(EipTMail.class);
      //
      // Expression exp1 =
      // ExpressionFactory.matchDbExp(EipTMail.MAIL_ID_PK_COLUMN, Integer
      // .valueOf(mailid));
      // Expression exp2 =
      // ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, user_id);
      //
      // EipTMail email = query.setQualifier(exp1.andExp(exp2)).fetchSingle();

      // if (email == null) {
      // logger.debug("[Mail] Not found ID...");
      // return null;
      // }

      // ALLocalMailMessage msg =
      // readMail(getFullName()
      // + ALStorageService.separator()
      // + email.getFilePath());
      //
      // add by motegi start for 開封確認
      // msg.setReadFlg("T".equals(email.getReadFlg()));
      // add end

      // 未読→既読に変更
      // email.setReadFlg("T");

      String filePath = null;
      // String readFlg = null;
      String notificationFlg = null;

      // 受信メールの場合
      if (ALFolder.TYPE_RECEIVE == type_mail) {
        // 受信メール情報をDBより取得
        // change start 2012.2.7 受入障害No.272
        // 代理受信の場合はステータスの変更は行わない
        // EipTMail email = getRecieveMail(mailid);
        // change start 2012.2.24 受入障害No.294
        // EipTMail email = getRecieveMail(mailid, isRepresent);
        EipTMail email = getRecieveMail(mailid, isRepresent, accountUsage);
        // change end 2012.2.24
        // change end 2012.2.7
        if (email == null) {
          logger.debug("[Mail] Not found ID...");
          return null;
        }
        // メールファイル名
        filePath = email.getFilePath();
        // 既読フラグ
        // readFlg = email.getReadFlg();
        // 開封確認送信済みフラグ
        notificationFlg = email.getNotificationFlg();
        // remove start
        // if (!readFlg.equals("T")) { // 未読の場合はここで更新する
        // email.setReadFlg("T");
        // }
        // remove end

        // 送信メールの場合
      } else {
        // 送信メール情報をDBより取得
        AvzTMailSend email = getSendMail(mailid);
        if (email == null) {
          logger.debug("[Mail] Not found ID...");
          return null;
        }
        // メールファイル名
        filePath = email.getFilePath();
        // 既読フラグ
        // readFlg = email.getReadFlg();

      }

      // メールファイルの内容を取得
      ALLocalMailMessage msg =
      // change start
        // readMail(getFullName()
        ALMailUtils.readMail(getFullName()
        // change end
          + ALStorageService.separator()
          + filePath);

      // 開封確認送信フラグを設定
      msg.setNotificationFlg("T".equals(notificationFlg));
      // メールIDを設定
      msg.setMailId(mailid);

      // change end

      // Database.commit();

      return msg;
    } catch (Throwable t) {
      // Database.rollback();
      // change start
      // logger.error(t);
      // return null;
      throw t;
      // change end
    }
  }

  // add start

  /**
   * 受信メールを取得します。
   * 
   * @param mailid
   *            メールID
   * @return EipTMail 受信メール情報
   * @throws Throwable
   */
  // private EipTMail getRecieveMail(int mailid) throws Throwable {
  // change start 2012.2.24 受入障害No.294
  // 引数にアカウント用途を追加(通常ユーザー:"0" 会議室ユーザー:"1")
  // private EipTMail getRecieveMail(int mailid, boolean isRepresent)
  private EipTMail getRecieveMail(int mailid, boolean isRepresent,
      String accountUsage)
  // change end 2012.2.24
      throws Throwable {
    try {
      SelectQuery<EipTMail> query = Database.query(EipTMail.class);

      Expression exp1 =
        ExpressionFactory.matchDbExp(EipTMail.MAIL_ID_PK_COLUMN, Integer
          .valueOf(mailid));
      Expression exp2 =
        ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, user_id);

      EipTMail email = query.setQualifier(exp1.andExp(exp2)).fetchSingle();
      if (email == null) {
        logger.debug("[Mail] Not found ID...");
        return null;
      }

      // 未読→既読に変更
      // change start
      // 既読に変更済みの場合は更新しない
      // change start 2012.2.7 受入障害No.272
      // 代理受信の場合はステータスの変更は行わない
      // if (!email.getReadFlg().equals("T")) {
      // email.setReadFlg("T");
      // Database.commit();
      // }
      // // change end
      // change start 2012.2.24 受入障害No.294
      // if (!isRepresent) {
      if (!(isRepresent && ALMailUtils.USER_ACCOUNT.equals(accountUsage))) {
        // change end 2012.2.24
        if (!email.getReadFlg().equals("T")) {
          email.setReadFlg("T");
          Database.commit();
        }
      }
      // change end 2012.2.7
      return email;
    } catch (Throwable t) {
      Database.rollback();
      throw t;
    }
  }

  /**
   * 送信メールを取得します。
   * 
   * @param mailid
   *            メールID
   * @return AvzTMailSend 送信メール情報
   * @throws Throwable
   */
  private AvzTMailSend getSendMail(int mailid) throws Throwable {
    try {
      SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);

      Expression exp1 =
        ExpressionFactory.matchDbExp(AvzTMailSend.MAIL_ID_PK_COLUMN, Integer
          .valueOf(mailid));
      Expression exp2 =
        ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, user_id);

      AvzTMailSend email = query.setQualifier(exp1.andExp(exp2)).fetchSingle();
      if (email == null) {
        logger.debug("[Mail] Not found ID...");
        return null;
      }

      // 未読→既読に変更
      if (!email.getReadFlg().equals("T")) {
        email.setReadFlg("T");
        Database.commit();
      }

      return email;
    } catch (Throwable t) {
      Database.rollback();
      throw t;
    }
  }

  // add end

  /**
   * 指定されたファイルを読み込み，mail メッセージを取得する．
   * 
   * @param fileName
   * @return
   * @throws Exception
   */
  // remove start
  // ALMailUtilsに移動
  // private ALLocalMailMessage readMail(String filepath) {
  // System.setProperty("mail.mime.charset", "ISO-2022-JP");
  // System.setProperty("mail.mime.decodetext.strict", "false");
  // Properties prop = new Properties();
  // prop.setProperty("mail.mime.address.strict", "false");
  // ALLocalMailMessage localmsg = null;
  // BufferedInputStream input = null;
  // try {
  // input = new BufferedInputStream(ALStorageService.getFile(filepath));
  // localmsg =
  // new ALLocalMailMessage(Session.getDefaultInstance(prop), input);
  // input.close();
  // } catch (Exception ex) {
  // logger.error("Exception", ex);
  // }
  // return localmsg;
  // }
  // remove end
  /**
   * メールを保存する。
   * 
   * @param messages
   * @return
   * @throws Throwable
   */
  @Override
  // change start
  // public boolean saveMail(ALMailMessage mail, String orgId) {
  // boolean res = false;
  // try {
  // String tmpFileName = getNewFileName();
  // res = saveMailToFile(mail, tmpFileName, true);
  // if (res) {
  // res = insertMailToDB((MimeMessage) mail, tmpFileName, false, false);
  // }
  // } catch (Exception ex) {
  // logger.error("Exception", ex);
  // res = false;
  // }
  // return res;
  // }
  public boolean saveMail(ALMailMessage mail, String orgId) throws Throwable {
    boolean res = false;
    // add start 2012.2.22 受入障害対応No.293
    String deleteTmpFileName = null;
    // add end
    try {
      String tmpFileName = getNewFileName();
      // add start 2012.2.22 受入障害対応No.293
      deleteTmpFileName = tmpFileName;
      // add end
      res = saveMailToFile(mail, tmpFileName, true);

      if (res) {
        // change start 運用フェーズ障害128
        // res = insertMailToDB((MimeMessage) mail, tmpFileName, false, false);
        res =
          insertMailToDB((MimeMessage) mail, tmpFileName, false, false, false);
        if (!res) {
          // PostgreSQLのNULLコードエラーが発生した場合は、NULLコード置換モードでリトライする。
          res =
            insertMailToDB((MimeMessage) mail, tmpFileName, false, false, true);
        }
        // change end 運用フェーズ障害128
      }
    } catch (Exception ex) {
      // add start 2012.2.22 受入障害対応No.293
      if (res) {
        ALStorageService.deleteFile(getFullName()
          + ALStorageService.separator()
          + deleteTmpFileName);
      }
      // add end
      throw ex;
    }
    return res;
  }

  // change end

  // add start

  /**
   * フォルダを指定してメールを保存する。
   * <p>
   * 
   * @param mail
   *            メール情報
   * @param folderId
   *            フォルダID
   * @return
   * @throws Throwable
   */
  public boolean saveMailByFolder(ALMailMessage mail, String folderId)
      throws Throwable {
    boolean res = false;

    try {

      // メールをファイルに保存
      String tmpFileName = getNewFileName();
      res = saveMailToFile(mail, tmpFileName, true);

      if (res) {
        // メールをDBに登録
        // change start 運用フェーズ障害128
        // res = insertMailToDBByFolder((MimeMessage) mail, tmpFileName,
        // folderId,
        // false, false);
        res =
          insertMailToDBByFolder(
            (MimeMessage) mail,
            tmpFileName,
            folderId,
            false,
            false,
            false);
        if (!res) {
          // PostgreSQLのNULLコードエラーが発生した場合は、NULLコード置換モードでリトライする。
          res =
            insertMailToDBByFolder(
              (MimeMessage) mail,
              tmpFileName,
              folderId,
              false,
              false,
              true);
        }
        // change end 運用フェーズ障害128
      }
    } catch (Exception ex) {
      // change start
      throw ex;
      // logger.error("Exception", ex);
      // res = false;
      // change end
    }
    return res;
  }

  // add end

  /**
   * 受信サーバから受信した受信可能サイズを超えたメールを保存する。<br />
   * このメールはヘッダ情報のみ、受信サーバから取得し、他の情報は取得しない。
   * 
   * @param localMailMessage
   * @return
   * @throws Throwable
   */
  @Override
  // chabge start
  // public boolean saveDefectiveMail(ALMailMessage mail, String orgId) {
  // boolean res = false;
  // try {
  // String tmpFileName = getNewFileName();
  // res = saveMailToFile(mail, tmpFileName, false);
  // if (res) {
  // res = insertMailToDB((MimeMessage) mail, tmpFileName, false, false);
  // }
  // } catch (Exception ex) {
  // logger.error("Exception", ex);
  // res = false;
  // }
  // return res;
  // }
  public boolean saveDefectiveMail(ALMailMessage mail, String orgId)
      throws Throwable {
    boolean res = false;
    try {
      String tmpFileName = getNewFileName();
      res = saveMailToFile(mail, tmpFileName, false);

      if (res) {
        // change start 運用フェーズ障害128
        // res = insertMailToDB((MimeMessage) mail, tmpFileName, false, false);
        res =
          insertMailToDB((MimeMessage) mail, tmpFileName, false, false, false);
        if (!res) {
          // PostgreSQLのNULLコードエラーが発生した場合は、NULLコード置換モードでリトライする。
          res =
            insertMailToDB((MimeMessage) mail, tmpFileName, false, false, true);
        }
        // change end 運用フェーズ障害128
      }
    } catch (Exception ex) {
      throw ex;
    }
    return res;
  }

  // chabge end

  /**
   * メールをファイルに保存します。
   * 
   * @param mail
   * @return
   * @throws Exception
   */
  private boolean saveMailToFile(ALMailMessage mail, String fileName,
      boolean savecontents) throws Exception {
    boolean res = false;
    ByteArrayOutputStream output = null;
    try {
      // String pop3MailPath = getFullName() + File.separator + fileName;

      // add start 2012.1.11 Content-Transfer-Encoding:が正しくない場合の対応
      MimeMessage mimeMessage = (MimeMessage) mail;
      // Content-Transfer-Encoding:が「sevenbit」の場合に「7bit」に変換
      String[] str_list_encoding =
        mimeMessage.getHeader(ALLocalMailMessage.CONTENT_TRANSFER_ENCORDING);
      if (!(null == str_list_encoding || "".equals(str_list_encoding))) {
        String str_encoding = str_list_encoding[0];
        if ("sevenbit".equals(str_encoding)) {
          mimeMessage = new MimeMessage((MimeMessage) mail);
          mimeMessage.setHeader(
            ALLocalMailMessage.CONTENT_TRANSFER_ENCORDING,
            ALMailUtils.STR_7BIT);
        }
      }
      // add end

      // メールの保存
      output = new ByteArrayOutputStream();
      if (savecontents) {
        // add start 2012.1.11 Content-Transfer-Encoding:が正しくない場合の対応
        // mail.writeTo(output);
        mimeMessage.writeTo(output);
        // add end
      } else {
        // remove start 2012.1.11
        // スコープを上位に持っていくためtry文の下に移動
        // MimeMessage mimeMessage = (MimeMessage) mail;
        // remove end
        Session session = Session.getDefaultInstance(new Properties());
        Message newMsg = new MimeMessage(session);
        Enumeration<?> headers = mimeMessage.getAllHeaders();
        while (headers.hasMoreElements()) {
          Header h = (Header) headers.nextElement();
          newMsg.addHeader(h.getName(), h.getValue());
        }
        newMsg
          .setText("メールのサイズが7MBを超えていたため、このメールを受信できませんでした。\r\n 誠に恐れ入りますが、別のメーラーで受信してください。");
        newMsg.writeTo(output);
      }
      ALStorageService.createNewFile(new ByteArrayInputStream(output
        .toByteArray()), getFullName(), fileName);

      output.flush();
      output.close();

      mail.clearContents();

      res = true;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      try {
        if (output != null) {
          output.close();
        }
      } catch (IOException ie) {
        // logger.error("Exception", ie);
        throw ie;
      }
      // res = false;
      throw ex;
    } finally {
      try {
        if (output != null) {
          output.close();
        }
      } catch (IOException ie) {
        // logger.error("Exception", ie);
        // res = false;
        throw ie;
      }
    }
    return res;
  }

  /**
   * 指定されたインデックスのメールを削除する．
   * 
   * @return
   * @throws Throwable
   */
  @Override
  public boolean deleteMail(int mailid) throws Throwable {
    try {
      // add start
      String filePath = null;
      String folderId = null;
      Integer fileVolume = 0;

      if (ALFolder.TYPE_RECEIVE == type_mail) {
        // 受信メールの場合
        SelectQuery<EipTMail> query = Database.query(EipTMail.class);
        Expression exp1 =
          ExpressionFactory.matchDbExp(EipTMail.MAIL_ID_PK_COLUMN, Integer
            .valueOf(mailid));
        Expression exp2 =
          ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, user_id);
        Expression exp3 =
          ExpressionFactory.matchExp(EipTMail.ACCOUNT_ID_PROPERTY, account_id);

        List<EipTMail> mail_list =
          query
            .andQualifier(exp1)
            .andQualifier(exp2)
            .andQualifier(exp3)
            .fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALDbLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }

        EipTMail record = mail_list.get(0);
        // change start
        // String filePath = record.getFilePath();
        filePath = record.getFilePath();
        folderId = record.getFolderId().toString();
        fileVolume = record.getFileVolume();

        // メールを削除する
        Database.delete(record);
        // change end

      } else {
        // 送信メールの場合
        SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);
        Expression exp1 =
          ExpressionFactory.matchDbExp(AvzTMailSend.MAIL_ID_PK_COLUMN, Integer
            .valueOf(mailid));
        Expression exp2 =
          ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, user_id);
        Expression exp3 =
          ExpressionFactory.matchExp(
            AvzTMailSend.ACCOUNT_ID_PROPERTY,
            account_id);

        List<AvzTMailSend> mail_list =
          query
            .andQualifier(exp1)
            .andQualifier(exp2)
            .andQualifier(exp3)
            .fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALDbLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }

        AvzTMailSend record = mail_list.get(0);
        filePath = record.getFilePath();
        folderId = record.getFolderId().toString();
        fileVolume = record.getFileVolume();

        // メールを削除する
        Database.delete(record);
      }

      // ファイル削除
      ALStorageService.deleteFile(getFullName()
        + ALStorageService.separator()
        + filePath);

      // フォルダ容量更新
      EipTMailFolder folder = getEipTMailFolder(account_id, folderId);
      // 削除したメールの容量を差し引く
      folder.setFolderVolume(folder.getFolderVolume() - fileVolume * 1024); // メールの容量をByteに換算してから引く

      // remove start
      // メールを削除する
      // Database.delete(record);
      // remove end
      Database.commit();
    } catch (Throwable t) {
      Database.rollback();
      // change start
      throw t;
      // logger.error(t);
      // return false;
      // change end
    }
    return true;
  }

  /**
   * 指定されたインデックスのメールを削除する．
   * 
   * @param msgIndexes
   * @return
   * @throws Throwable
   */
  @Override
  public boolean deleteMails(List<String> msgIndexes) throws Throwable {
    try {
      // change start
      // 受信トレイ
      if (type_mail == ALFolder.TYPE_RECEIVE) {
        SelectQuery<EipTMail> query = Database.query(EipTMail.class);
        Expression exp1 =
          ExpressionFactory.inDbExp(EipTMail.MAIL_ID_PK_COLUMN, msgIndexes);
        Expression exp2 =
          ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, Integer
            .valueOf(user_id));

        List<EipTMail> mail_list =
          query.andQualifier(exp1).andQualifier(exp2).fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALFileLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }
        // ファイル削除
        for (EipTMail record : mail_list) {
          String filePath = record.getFilePath();
          ALStorageService.deleteFile(getFullName()
            + ALStorageService.separator()
            + filePath);

          // フォルダ容量更新
          EipTMailFolder folder =
            getEipTMailFolder(account_id, record.getFolderId().toString());
          if (folder == null) {
            return false;
          }
          // 削除したメールの容量を差し引く
          folder.setFolderVolume(folder.getFolderVolume()
            - record.getFileVolume()
            * 1024); // メールの容量をByteに換算してから引く
        }
        Database.deleteAll(mail_list);

        // change end

        // add start
        // 送信トレイ
      } else {
        SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);
        Expression exp1 =
          ExpressionFactory.inDbExp(AvzTMailSend.MAIL_ID_PK_COLUMN, msgIndexes);
        Expression exp2 =
          ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, Integer
            .valueOf(user_id));

        List<AvzTMailSend> mail_list =
          query.andQualifier(exp1).andQualifier(exp2).fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALFileLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }
        // ファイル削除
        for (AvzTMailSend record : mail_list) {
          String filePath = record.getFilePath();
          ALStorageService.deleteFile(getFullName()
            + ALStorageService.separator()
            + filePath);
          // フォルダ容量更新
          EipTMailFolder folder =
            getEipTMailFolder(account_id, record.getFolderId().toString());
          if (folder == null) {
            return false;
          }
          // 削除したメールの容量を差し引く
          folder.setFolderVolume(folder.getFolderVolume()
            - record.getFileVolume()
            * 1024);
        }
        Database.deleteAll(mail_list);
      }
      // add end

      Database.commit();
    } catch (Throwable t) {
      Database.rollback();
      // change start
      throw t;
      // logger.error(t);
      // return false;
      // change end
    }
    return true;
  }

  // add start 2012.2.22 受入障害対応No.297
  /**
   * 指定されたインデックスのメールを削除する．
   * 
   * @param msgIndexes
   * @return
   * @throws Throwable
   */
  public boolean deleteSeparateMails(List<String> msgIndexes) throws Throwable {

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

    final int separateIndex = 30000;
    if (msgIndexes.size() < separateIndex) {
      return deleteSeparateIndexMails(msgIndexes);
    } else {
      final int maxIndex = msgIndexes.size();
      int toIndex = maxIndex;
      for (int fromIndex = 0; fromIndex < msgIndexes.size();) {
        if (maxIndex - fromIndex > separateIndex) {
          toIndex = fromIndex + separateIndex;
        } else {
          toIndex = maxIndex;
        }
        if (!deleteSeparateIndexMails(msgIndexes.subList(fromIndex, toIndex))) {
          return false;
        }
        fromIndex += separateIndex;
      }
      return true;
    }
  }

  /**
   * 指定されたインデックスのメールを削除する．
   * 
   * @param msgIndexes
   * @return
   * @throws Throwable
   */
  private boolean deleteSeparateIndexMails(List<String> msgIndexes)
      throws Throwable {
    try {
      // 受信トレイ
      if (type_mail == ALFolder.TYPE_RECEIVE) {
        SelectQuery<EipTMail> query = Database.query(EipTMail.class);
        Expression exp1 =
          ExpressionFactory.inDbExp(EipTMail.MAIL_ID_PK_COLUMN, msgIndexes);
        Expression exp2 =
          ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, Integer
            .valueOf(user_id));
        query.select(EipTMail.MAIL_ID_PK_COLUMN);
        query.select("folder_id");
        query.select(EipTMail.FILE_PATH_COLUMN);
        query.select(EipTMail.FILE_VOLUME_COLUMN);
        List<EipTMail> mail_list =
          query.andQualifier(exp1).andQualifier(exp2).fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALFileLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }
        // ファイル削除
        for (EipTMail record : mail_list) {
          String filePath = record.getFilePath();
          ALStorageService.deleteFile(getFullName()
            + ALStorageService.separator()
            + filePath);

          // フォルダ容量更新
          EipTMailFolder folder =
            getEipTMailFolder(account_id, record.getFolderId().toString());
          if (folder == null) {
            return false;
          }
          // 削除したメールの容量を差し引く
          folder.setFolderVolume(folder.getFolderVolume()
            - record.getFileVolume()
            * 1024); // メールの容量をByteに換算してから引く
        }
        String sql =
          "DELETE FROM eip_t_mail WHERE MAIL_ID IN ("
            + implode(",", msgIndexes)
            + ")";
        Database.sql(EipTMail.class, sql).execute();

        // add start
        // 送信トレイ
      } else {
        SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);
        Expression exp1 =
          ExpressionFactory.inDbExp(AvzTMailSend.MAIL_ID_PK_COLUMN, msgIndexes);
        Expression exp2 =
          ExpressionFactory.matchExp(AvzTMailSend.USER_ID_PROPERTY, Integer
            .valueOf(user_id));

        query.select(AvzTMailSend.MAIL_ID_PK_COLUMN);
        query.select("folder_id");
        query.select(AvzTMailSend.FILE_PATH_COLUMN);
        query.select(AvzTMailSend.FILE_VOLUME_COLUMN);
        List<AvzTMailSend> mail_list =
          query.andQualifier(exp1).andQualifier(exp2).fetchList();
        if (mail_list == null || mail_list.size() == 0) {
          logger.debug("[ALFileLocalFolder] Not found ID...");
          throw new ALPageNotFoundException();
        }
        // ファイル削除
        for (AvzTMailSend record : mail_list) {
          String filePath = record.getFilePath();
          ALStorageService.deleteFile(getFullName()
            + ALStorageService.separator()
            + filePath);
          // フォルダ容量更新
          EipTMailFolder folder =
            getEipTMailFolder(account_id, record.getFolderId().toString());
          if (folder == null) {
            return false;
          }
          // 削除したメールの容量を差し引く
          folder.setFolderVolume(folder.getFolderVolume()
            - record.getFileVolume()
            * 1024);
        }
        String sql =
          "DELETE FROM avz_t_mail_send WHERE MAIL_ID IN ("
            + implode(",", msgIndexes)
            + ")";
        Database.sql(EipTMail.class, sql).execute();
      }
    } catch (Throwable t) {
      Database.rollback();
      throw t;
    }
    return true;
  }

  private static String implode(String glue, List<String> pieces) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0;; i++) {
      buf.append(pieces.get(i));
      if (i == pieces.size() - 1) {
        break;
      }
      buf.append(glue);
    }
    return buf.toString();
  }

  // add end 2012.2.22
  /**
   * フォルダ情報取得
   * <p>
   * 指定されたアカウントID、フォルダIDでフォルダ情報を取得する。<BR>
   * 
   * @param account_id
   *            アカウントID
   * @param folderId
   *            フォルダID
   * @return EipTMailFolder フォルダ情報
   * @throws Throwable
   */
  private EipTMailFolder getEipTMailFolder(int account_id, String folderId)
      throws Throwable {
    try {
      if (Integer.valueOf(account_id) == null) {
        // アカウントIDが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        return null;
      }
      if (folderId == null || Integer.valueOf(folderId) == null) {
        // フォルダIDが空の場合
        logger.debug("[WebMail Folder] Empty Folder...");
        return null;
      }
      // アカウント情報取得
      EipMMailAccount account = ALMailUtils.getMailAccount(user_id, account_id);

      // フォルダ情報取得
      return ALMailUtils.getEipTMailFolder(account, folderId);

    } catch (Throwable t) {
      throw t;
    }
  }

  /**
   * 
   * @return
   */
  @Override
  protected Attributes getColumnMap() {
    Attributes map = new Attributes();
    map.putValue("read_flg", EipTMail.READ_FLG_PROPERTY);
    map.putValue("subject", EipTMail.SUBJECT_PROPERTY);
    map.putValue("person", EipTMail.PERSON_PROPERTY);
    map.putValue("date", EipTMail.EVENT_DATE_PROPERTY);
    map.putValue("volume", EipTMail.FILE_VOLUME_PROPERTY);

    map.putValue("has_files", EipTMail.HAS_FILES_PROPERTY);

    return map;
  }

  /**
   * 新着メール数を取得する。
   * 
   * @return
   */
  @Override
  public int getNewMailNum() {
    return 0;
  }

  /**
   * 新着メール数を更新する．
   * 
   * @param num
   */
  @Override
  public void setNewMailNum(int num) {

  }

  /**
   * 指定したフォルダ内のメールの総数を取得する。
   * 
   * @param type
   *            送受信フラグ
   * @return
   */
  public int getMailSum() {
    return 0;
  }

  /**
   * 指定したフォルダ内の未読メール数を取得する．
   * 
   * @return
   */
  @Override
  public int getUnreadMailNum() {
    return 0;
  }

  /**
   * ローカルフォルダを閉じる．
   */
  @Override
  public void close() {
  }

  /**
   * 新しいファイル名を生成する．
   * 
   * @return
   */
  public String getNewFileName() {
    return String.valueOf(System.nanoTime());
  }
}
