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

package com.aimluck.eip.webmail;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.cayenne.CayenneException;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.access.ResultIterator;
import org.apache.cayenne.access.Transaction;
import org.apache.commons.io.FileUtils;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;

import com.aimluck.eip.cayenne.om.portlet.AvzTMailBatch;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailSend;
import com.aimluck.eip.cayenne.om.portlet.EipTMail;
import com.aimluck.eip.cayenne.om.security.TurbineUser;
import com.aimluck.eip.mail.ALAdminMailContext;
import com.aimluck.eip.mail.ALAdminMailMessage;
import com.aimluck.eip.mail.ALFolder;
import com.aimluck.eip.mail.ALMailService;
import com.aimluck.eip.mail.file.ALFileLocalFolder;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.webmail.util.WebMailUtils;

/**
 * 非同期にてメール一括退避処理を行うクラスです
 * 
 * @see java.lang.Runnable
 */
public class WebMailPackageProcessFolderDeleteThread implements Runnable {

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

  /** ログインユーザー名 * */
  private final String login_user_name;

  /** ログインユーザーID * */
  private final int user_id;

  /** ログインユーザーのアカウントID * */
  private int account_id;

  /** ログ出力用メッセージ(メール一括削除処理パラメータ取得) * */
  private final String ERROR_MESSAGE_GET_STATUS_PARAMETER =
    "メール一括削除処理パラメータ取得に失敗しました";

  /** ログ出力用メッセージ(一括削除処理対象メール取得) * */
  private final String ERROR_MESSAGE_GET_DELETE_MAIL = "一括削除処理対象メール取得に失敗しました";

  /** ログ出力用メッセージ(メール一括削除) * */
  private final String ERROR_MESSAGE_DELETE_MAIL = "メール一括削除に失敗しました";

  /** ログ出力用メッセージ(メール一括削除処理パラメータ更新) * */
  private final String ERROR_MESSAGE_UPDATE_MAIL_BATCH_STATUS =
    "メール一括削除処理パラメータ更新に失敗しました";

  /** ログ出力用メッセージ(メール一括削除処理完了メール送信) * */
  private final String ERROR_MESSAGE_COMPLETE_MAIL = "メール一括削除処理完了メール送信に失敗しました";

  /** データベース ID */
  private DataContext dataContext = null;

  /** ダウンロード後削除フラグ */
  private final boolean isDeleteAfterDownload;

  /**
   * コンストラクタ
   * 
   * @param orgId
   * @param userId
   * @param mailAccountId
   */
  public WebMailPackageProcessFolderDeleteThread(DataContext dataContext,
      int user_id, boolean isDeleteAfterDownloadFlg) {
    this.dataContext = dataContext;
    this.user_id = user_id;
    this.login_user_name = ALEipUtils.getUserFullName(user_id);
    this.isDeleteAfterDownload = isDeleteAfterDownloadFlg;

  }

  @Override
  public void run() {

    // add by motegi start 2012.4.12
    DataContext.bindThreadDataContext(dataContext);

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

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

    // add end

    // 処理パラメータオブジェクト
    AvzTMailBatch mailBatch = null;
    // 処理パラメータから取得するフォルダ種別
    String folder_kind = null;
    // 処理パラメータから取得するフォルダID
    int folder_id = -1;
    // 削除対象メールID格納リスト
    List<String> deleteMailIdList = new ArrayList();
    // 非同期にて処理を行う場合はdataContextオブジェクトを再生成？
    DataContext.bindThreadDataContext(dataContext);
    // change start カーソル処理へ変更
    // 一度にDELETEする件数
    final int DELETE_SIZE = 500;
    // キャンセルフラグ
    boolean cancel = false;
    // change end

    try {
      Database.sql(
        TurbineUser.class,
        "SET TRANSACTION ISOLATION LEVEL READ COMMITTED;").execute();
      logger.info("トランザクションモードを切替しました。");

      // 処理パラメータ取得
      mailBatch = WebMailUtils.getAvzTMailBatchResultList(user_id);
      // アカウントID、フォルダID取得
      account_id = mailBatch.getAccountId();
      folder_id = mailBatch.getFolderId();
      // フォルダ種別取得
      folder_kind =
        WebMailUtils.getEipTMailFolder(account_id, folder_id).getFolderKind();
    } catch (Exception ex) {
      logger.error(ERROR_MESSAGE_GET_STATUS_PARAMETER + login_user_name, ex);
      return;
    }

    // add start カーソル処理へ変更
    ResultIterator it = null;
    // add end
    try {
      // 削除対象となるメールを取得（フォルダ種別で参照テーブルが異なる）
      if (WebMailConsts.RECEIVE_FOLDER.equals(folder_kind)) {

        // フォルダ種別 = R:受信トレイの場合
        // 削除対象メール一覧
        // remove start カーソル処理へ変更
        // List<EipTMail> eipTMailList = new ArrayList<EipTMail>();
        // remove end
        try {
          // add start カーソル処理へ変更
          // eipTMailList =
          // WebMailUtils.getEipTMail(
          // account_id,
          // user_id,
          // folder_id,
          // mailBatch,
          // isDeleteAfterDownload);
          it =
            WebMailUtils.getEipTMailResultIterator(
              account_id,
              user_id,
              folder_id,
              mailBatch,
              isDeleteAfterDownload);
          // add end
        } catch (Exception ex) {
          logger.error(ERROR_MESSAGE_GET_DELETE_MAIL + login_user_name, ex);
          return;
        }

        // 受入障害対応No.157
        // add start
        if (isDeleteAfterDownload) {
          // ダウンロードファイル名
          String download_file_name = mailBatch.getFileName();
          // ダウンロードディレクトリパス
          String downloadDirectory = WebMailUtils.getDownloadFileDir(user_id);
          // ダウンロードファイル
          File download_file = new File(downloadDirectory + download_file_name);
          if (!FileUtils.deleteQuietly(download_file)) {
            logger.error("退避ファイルダウンロード完了後のファイル削除に失敗。対象ファイルパス："
              + download_file.getAbsolutePath());
          }
        }
        // 受入障害対応No.157
        // add end

        // change start カーソル処理へ変更
        // if (null == eipTMailList || eipTMailList.size() < 1) {
        if (null == it) {
          // <結果レコード>が0件の場合、処理ステータスを「一括処理キャンセル」に更新
          WebMailUtils.updateMailBatchData(
            mailBatch,
            WebMailConsts.BATCH_PROCESSING_CANCEL);
        } else {
          // 削除対象となるメールIDリスト作成
          // change start カーソル処理へ変更
          // for (EipTMail eipTMail : eipTMailList) {
          // deleteMailIdList.add(eipTMail.getMailId().toString());
          // }
          // change end
          ALFileLocalFolder aLFileLocalFolder = null;
          // 削除
          aLFileLocalFolder =
            new ALFileLocalFolder(ALFolder.TYPE_RECEIVE, Database
              .getDomainName(), user_id, account_id);
          try {

            // add start カーソル処理
            int i = 0;
            while (it.hasNextRow()) {
              Map<String, Object> row = it.nextDataRow();
              deleteMailIdList.add(((Integer) row
                .get(EipTMail.MAIL_ID_PK_COLUMN)).toString());
              i++;
              if (deleteMailIdList.size() >= DELETE_SIZE) {

                Runtime runtime = Runtime.getRuntime();
                long max = runtime.maxMemory();
                long free = runtime.freeMemory();
                long used = max - free;
                logger.info("メール削除処理モニター["
                  + login_user_name
                  + "　メモリMAX:"
                  + max
                  / 1024
                  / 1024
                  + "M メモリFREE:"
                  + free
                  / 1024
                  / 1024
                  + "M メモリUSED:"
                  + used
                  / 1024
                  / 1024
                  + "M 現在処理件数:"
                  + i
                  + "件");

                String status =
                  WebMailUtils
                    .getAvzTMailBatchResultListOnOtherTran(user_id)
                    .getStatus();
                if (WebMailConsts.BATCH_PROCESSING_CANCEL.equals(status)) {
                  // finally節で後処理を行わせるためのフラグをON
                  logger.info(login_user_name + " 一括削除処理がキャンセルされました");
                  cancel = true;
                  return;
                }

                aLFileLocalFolder.deleteSeparateMails(deleteMailIdList);
                deleteMailIdList.clear();
              }
            }
            // add end カーソル処理

            // change start 2012.2.22 受入障害対応No.297
            // aLFileLocalFolder.deleteMails(deleteMailIdList);
            aLFileLocalFolder.deleteSeparateMails(deleteMailIdList);
            // change end
          } catch (Exception ex) {
            Database.rollback();
            logger.error(ERROR_MESSAGE_DELETE_MAIL + login_user_name, ex);
            return;
          } catch (Throwable e) {
            Database.rollback();
            logger.error(ERROR_MESSAGE_DELETE_MAIL + login_user_name, e);
            return;
          } finally {
            if (it != null) {
              try {
                it.close();
                it = null;
              } catch (CayenneException e) {
                logger.error("カーソルの解放で予期せぬ例外が発生しました。", e);
              }
            }
          }
          // 処理ステータスを「一括処理完了」に更新する。
          WebMailUtils.updateMailBatchData(
            mailBatch,
            WebMailConsts.BATCH_PROCESSING_COMPLETE);
        }

      } else if (WebMailConsts.SEND_FOLDER.equals(folder_kind)) {
        // フォルダ種別 = S:送信トレイの場合
        // 削除対象メール一覧
        // remove start カーソル処理へ変更
        // List<AvzTMailSend> avzTMailSendList = new ArrayList<AvzTMailSend>();
        // remove end
        try {
          // change start カーソル処理へ変更
          // avzTMailSendList =
          // WebMailUtils.getAvzTMailSend(
          // account_id,
          // user_id,
          // folder_id,
          // mailBatch,
          // isDeleteAfterDownload);
          it =
            WebMailUtils.getAvzTMailSendResultIterator(
              account_id,
              user_id,
              folder_id,
              mailBatch,
              isDeleteAfterDownload);
          // change end
        } catch (Exception ex) {
          logger.error(ERROR_MESSAGE_GET_DELETE_MAIL + login_user_name, ex);
          return;
        }

        // 受入障害対応No.157
        // add start
        if (isDeleteAfterDownload) {
          // ダウンロードファイル名
          String download_file_name = mailBatch.getFileName();
          // ダウンロードディレクトリパス
          String downloadDirectory = WebMailUtils.getDownloadFileDir(user_id);
          // ダウンロードファイル
          File download_file = new File(downloadDirectory + download_file_name);
          if (!FileUtils.deleteQuietly(download_file)) {
            logger.error("退避ファイルダウンロード完了後のファイル削除に失敗。対象ファイルパス："
              + download_file.getAbsolutePath());
          }
        }
        // 受入障害対応No.157
        // add end
        // change start カーソル処理へ変更
        // if (null == avzTMailSendList || avzTMailSendList.size() < 1) {
        if (null == it) {
          // <結果レコード>が0件の場合、処理ステータスを「一括処理キャンセル」に更新
          WebMailUtils.updateMailBatchData(
            mailBatch,
            WebMailConsts.BATCH_PROCESSING_CANCEL);
        } else {
          // 削除対象となるメールIDリスト作成
          // change start カーソル処理へ変更
          // for (AvzTMailSend avzTMail : avzTMailSendList) {
          // deleteMailIdList.add(avzTMail.getMailId().toString());
          // }
          // change end
          ALFileLocalFolder aLFileLocalFolder = null;
          try {
            // 削除
            aLFileLocalFolder =
              new ALFileLocalFolder(ALFolder.TYPE_SEND, Database
                .getDomainName(), user_id, account_id);

            // add start カーソル処理
            int i = 0;
            while (it.hasNextRow()) {
              Map<String, Object> row = it.nextDataRow();
              deleteMailIdList.add(((Integer) row
                .get(AvzTMailSend.MAIL_ID_PK_COLUMN)).toString());
              i++;
              if (deleteMailIdList.size() >= DELETE_SIZE) {

                Runtime runtime = Runtime.getRuntime();
                long max = runtime.maxMemory();
                long free = runtime.freeMemory();
                long used = max - free;
                logger.info("メール削除処理モニター["
                  + login_user_name
                  + "　メモリMAX:"
                  + max
                  / 1024
                  / 1024
                  + "M メモリFREE:"
                  + free
                  / 1024
                  / 1024
                  + "M メモリUSED:"
                  + used
                  / 1024
                  / 1024
                  + "M 現在処理件数:"
                  + i
                  + "件");

                String status =
                  WebMailUtils
                    .getAvzTMailBatchResultListOnOtherTran(user_id)
                    .getStatus();
                if (WebMailConsts.BATCH_PROCESSING_CANCEL.equals(status)) {
                  // finally節で後処理を行わせるためのフラグをON
                  logger.info(login_user_name + " 一括削除処理がキャンセルされました");
                  cancel = true;
                  return;
                }

                aLFileLocalFolder.deleteSeparateMails(deleteMailIdList);
                deleteMailIdList.clear();
              }
            }
            // add end カーソル処理

            // change start 2012.2.22 受入障害対応No.297
            // aLFileLocalFolder.deleteMails(deleteMailIdList);
            aLFileLocalFolder.deleteSeparateMails(deleteMailIdList);
            // change end
          } catch (Exception ex) {
            Database.rollback();
            logger.error(ERROR_MESSAGE_DELETE_MAIL + login_user_name, ex);
            return;
          } catch (Throwable e) {
            Database.rollback();
            logger.error(ERROR_MESSAGE_DELETE_MAIL + login_user_name, e);
            return;
          } finally {
            if (it != null) {
              try {
                it.close();
                it = null;
              } catch (CayenneException e) {
                logger.error("カーソルの解放で予期せぬ例外が発生しました。", e);
              }
            }
          }
          // 処理ステータスを「一括処理完了」に更新する。
          WebMailUtils.updateMailBatchData(
            mailBatch,
            WebMailConsts.BATCH_PROCESSING_COMPLETE);
        }

      }

      // change start
      // 内部レビュー反映No.6
      // コミットする。
      Database.commit();

      // 処理完了メールを送信する。
      sendBatchCompleteMail(account_id);
    } catch (Exception ex) {
      if (it != null) {
        try {
          it.close();
          it = null;
        } catch (CayenneException e) {
          logger.error("カーソルの解放で予期せぬ例外が発生しました。", e);
        }
      }

      Database.rollback();
      logger
        .error(ERROR_MESSAGE_UPDATE_MAIL_BATCH_STATUS + login_user_name, ex);
      return;
    } finally {
      if (it != null) {
        try {
          it.close();
          it = null;
        } catch (CayenneException e) {
          logger.error("カーソルの解放で予期せぬ例外が発生しました。", e);
        }
      }

      // add start カーソル処理へ変更
      if (cancel) {
        // メールファイルの削除があるためロールバックが不可 0413
        // Database.rollback();
        Database.commit();
      }
      // end start カーソル処理へ変更

      try {
        Database.tearDown();
      } catch (Exception e) {
        logger.error("DB切断で予期せぬ例外が発生しました。", e);
      }
    }
    // コミットする。
    // Database.commit();
    // change end
  }

  /**
   * 完了メールを送信します
   * 
   * @see com.aimluck.eip.mail.ALMailService.sendAdminMail
   * @param int
   *            account_id アカウントID
   */
  public void sendBatchCompleteMail(int account_id) {
    String subject = "メール一括削除完了のお知らせ";
    String orgId = Database.getDomainName();
    List<ALAdminMailMessage> messageList = new ArrayList<ALAdminMailMessage>();
    ALAdminMailMessage message = new ALAdminMailMessage();
    try {
      message.setPcSubject(subject);
      message.setPcBody(createMsgForPc());
      message.setUserId(user_id);
      message.setPcMailAddr(WebMailUtils.getEipMMailAddress(account_id));
      messageList.add(message);
      ALMailService.sendAdminMail(new ALAdminMailContext(
        orgId,
        user_id,
        messageList,
        ALMailUtils.getSendDestType(ALMailUtils.VALUE_MSGTYPE_DEST_PC)));
    } catch (Exception ex) {
      logger.error(ERROR_MESSAGE_COMPLETE_MAIL + login_user_name, ex);
      return;
    }
    return;
  }

  /**
   * メール本文作成
   * 
   * @return String メール本文
   */
  public static String createMsgForPc() {
    String CR = System.getProperty("line.separator");
    StringBuffer body = new StringBuffer("");
    body.append("メールの一括削除が完了しました").append(CR).append(CR);
    return body.toString();
  }
}
