package aipo.webservice.soap.axis2;

/*
 * 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/>.
 *
 */

import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.om.security.UserNamePrincipal;
import org.apache.jetspeed.services.JetspeedUserManagement;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;

import aipo.batch.utils.BatchUtils;
import aipo.webservice.util.WsUtils;

import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.mail.ALPop3MailReceiveThread;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.util.ALEipUtils;

/**
 * <HR>
 * リマインダーWebサービスクラス
 * <p>
 * 
 * リマインダー、Outlookデータ移行からの要求に応じてDBアクセス、メールサーバーアクセスを伴う処理を行う。
 * <P>
 * <HR>
 * <P>
 * 
 */
public class MaintenanceService {

  /** ロガー */
  private static final JetspeedLogger logger =
    JetspeedLogFactoryService.getLogger(MaintenanceService.class.getName());

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

  /** SMTPサーバ名 */
  private static final String DEFAULT_SMTP_SERVER =
    (String) BatchUtils.getProperties(SETTING_FILE_PATH).get("smtpserver_name");

  /** POP3サーバ名 */
  private static final String DEFAULT_POP3_SERVER =
    (String) BatchUtils.getProperties(SETTING_FILE_PATH).get("pop3server_name");

  /** プロパティファイル */
  private static final String PROPERTY_FILE =
    JetspeedResources.getString("aipo.conf", "")
      + File.separator
      + "Batch.properties";

  /**
   * メールサーバー接続先の変更処理
   * 
   * @return 結果文字列
   */
  public String changeMailServer() {
    logger.info("メールサーバー接続先の変更処理開始");

    String rtn = "メールサーバー接続先の変更に成功しました。";
    try {
      // DB接続
      openDbConecction();

      // メールアカウントを抽出する
      SelectQuery<EipMMailAccount> query =
        Database.query(EipMMailAccount.class);
      query.orderAscending(EipMMailAccount.USER_ID_PROPERTY);
      List<EipMMailAccount> resultList = query.fetchList();

      // final String ACCOUNT_TYPE_DEFAULT = "1";
      for (EipMMailAccount entity : resultList) {

        String pop3userName = entity.getPop3userName();

        ALBaseUser base = ALEipUtils.getBaseUser(entity.getUserId().intValue());

        // if (ACCOUNT_TYPE_DEFAULT.equals(entity.getAccountType())) {
        // String[] tmpList = entity.getMailAddress().split("@");
        // pop3userName = tmpList[0];
        // logger.debug("プライマリアドレスの受信IDを書き換え：" + pop3userName);
        // }

        if (entity.getMailAddress().equals(base.getEmail())) {
          String[] tmpList = entity.getMailAddress().split("@");
          pop3userName = tmpList[0];
          logger.info("プライマリアドレスの受信IDを書き換え："
            + entity.getPop3userName()
            + "->"
            + pop3userName);
        }

        entity.setPop3userName(pop3userName);
        // entity.setPop3password(ALMailUtils
        // .getEncryptedMailAccountPasswd(pop3userName.getBytes()));
        String passwd = WsUtils.getMD5Digest(pop3userName);

        logger.debug("新パスワード:" + passwd);

        entity.setPop3password(ALMailUtils.getEncryptedMailAccountPasswd(passwd
          .getBytes()));
        entity.setDelAtPop3Flg("1");// サーバーに残さない
        entity.setPop3serverName(DEFAULT_POP3_SERVER);
        entity.setSmtpserverName(DEFAULT_SMTP_SERVER);
        entity.setUpdateDate(new Date());

        logger.info("メールサーバー接続先の変更処理実行：" + entity.getMailAddress());

      }
      Database.commit();

      logger.info("メールサーバー接続先の変更処理終了");

    } catch (Exception e) {
      Database.rollback();
      logger.error("メールサーバー接続先の変更処理でエラーが発生しました。", e);
      rtn = "メールサーバー接続先の変更処理でエラーが発生しました。 " + e.getMessage();
    } finally {
      // DBクローズ
      closeDbConecction();
    }
    return rtn;
  }

  /**
   * メール取得サービス
   * <p>
   * 未受信の新着メール情報を取得して返す。<br>
   * 
   * @param demandDateTime
   *            前回受信日時 [年4桁/月2桁/日2桁 時2桁:分2桁:秒2桁]
   * @param userName
   *            ユーザー名
   * @param password
   *            パスワード
   * @return ReceiveMailViewBean[] メール一覧（配列）
   */
  public String recieveMail(String userNameList) {

    logger.info("【開始】全メール受信処理 :" + userNameList);

    JetspeedUser user = null;
    StringBuffer rtn = new StringBuffer();
    String userName = "";
    try {

      // DB接続
      openDbConecction();

      StringTokenizer userToken = new StringTokenizer(userNameList, ",");
      while (userToken.hasMoreTokens()) {

        userName = userToken.nextToken();
        if (userName == null || userName.length() == 0) {
          continue;
        }

        // ユーザー情報を取得
        user = JetspeedUserManagement.getUser(new UserNamePrincipal(userName));
        if (user == null) {
          return "ユーザー[" + userName + "]は存在しないのでスキップします。\n";
        }

        // --------------------------------
        // DBよりメールアカウント情報取得
        // --------------------------------

        SelectQuery<EipMMailAccount> mailAccountQuery =
          Database.query(EipMMailAccount.class);
        Expression exp =
          ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer
            .valueOf(user.getUserId()));
        mailAccountQuery.setQualifier(exp);

        // logger.debug("search mail account start.");

        List<EipMMailAccount> mailAccountList = mailAccountQuery.fetchList();

        // logger.debug("search mail account end.");

        // --------------------------------
        // メールアカウント毎に未受信メールを取得する
        // --------------------------------
        // logger.debug("get mail start.");

        for (EipMMailAccount mailAccount : mailAccountList) {

          if (logger.isDebugEnabled()) {
            logger.debug("【受信開始】:ユーザー="
              + userName
              + " アカウントID="
              + mailAccount.getAccountId()
              + " メールアドレス="
              + mailAccount.getMailAddress());
          }

          // --------------------------------
          // メールを受信する
          // --------------------------------
          String tmp;
          try {
            boolean executeThread = receiveMailsThread(user, mailAccount);
            if (executeThread) {
              // 受信スレッドを起動した場合
              // tmp =
              // ALPop3MailReceiveThread.getReceiveMailResultStr(
              // user,
              // mailAccount.getAccountId());
              // if (tmp == null || tmp.length() == 0 ||
              // "メールを受信しました。".equals(tmp)) {
              // // 受信成功
              // tmp = "メールアカウント[" + mailAccount.getMailAddress() + "]の受信成功\n";
              // } else {
              // tmp =
              // "メールアカウント["
              // + mailAccount.getMailAddress()
              // + "]の受信失敗 ["
              // + tmp
              // + "]\n";
              // }
              tmp =
                "メールアカウント[" + mailAccount.getMailAddress() + "]の受信処理を行いました。\n";
            } else {
              // 画面側で受信スレッドを起動中で、スキップした場合
              tmp =
                "メールアカウント["
                  + mailAccount.getMailAddress()
                  + "]は受信中のため処理をスキップします。\n";
            }
            rtn.append(tmp);
          } catch (Exception e) {
            // １メールアカウントでエラーが発生しても処理を継続する。
            logger.error("受信失敗です。メール取得で予期せぬ例外が発生しました。ユーザー名：["
              + userName
              + "] メールアドレス:["
              + mailAccount.getMailAddress()
              + "]", e);
            rtn.append("受信失敗です。メール取得で予期せぬ例外が発生しました。ユーザー名：["
              + userName
              + "]　メールアドレス:["
              + mailAccount.getMailAddress()
              + "] 例外:["
              + e.getMessage()
              + "]\n");
          }

          if (logger.isDebugEnabled()) {
            logger.debug("【受信終了】:ユーザー="
              + userName
              + " アカウントID="
              + mailAccount.getAccountId()
              + " メールアドレス="
              + mailAccount.getMailAddress());
          }
          // sleep();
        }
      }
    } catch (Exception e) {
      // 予期せぬエラーの場合、0件のメールリストを返す
      logger
        .error("受信失敗です。メール取得で予期せぬ例外が発生しました。ユーザー名：[" + userNameList + "]", e);
      return "受信失敗です。メール取得で予期せぬ例外が発生しました。ユーザー名：["
        + userNameList
        + "]"
        + e.getMessage();
    } finally {
      closeDbConecction();
    }
    logger.info("【終了】全メール受信処理 :" + userNameList);
    return rtn.toString();
  }

  /**
   * 同期受信用メソッド
   * <p>
   * 未受信の新着メール情報を受信する。<br>
   * 
   * @param user
   *            受信対象ユーザー
   * @param account
   *            受信対象アカウント
   * @throws Exception
   *             すべての例外
   */
  private boolean receiveMailsThread(JetspeedUser user, EipMMailAccount account)
      throws Exception {
    // synchronized (ALPop3MailReceiveThread.KEY_SYNCHRONIZED_LOCK) {

    int accountId = account.getAccountId();
    boolean executeThread = false;
    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();
      // 待ち合わせを行う
      mailthread.join();

      executeThread = true;
    }
    // }

    return executeThread;
  }

  /**
   * DB接続
   * 
   * @return int 接続に成功した場合0、失敗した場合-1
   */
  private int openDbConecction() {
    logger.debug("openDbConecction() start.");
    int result = 0;
    DataContext dataContext = null;
    try {
      dataContext = Database.createDataContext(Database.DEFAULT_ORG);
      DataContext.bindThreadDataContext(dataContext);
    } catch (Exception e) {
      logger.error("DB接続に失敗しました。", e);
      result = -1;
    }
    logger.debug("openDbConecction() end.");
    return result;
  }

  /**
   * DB切断
   * 
   * @return int 切断に成功した場合0、失敗した場合-1
   */
  private int closeDbConecction() {
    logger.debug("closeDbConecction() start.");
    int result = 0;
    try {
      Database.tearDown();
    } catch (Exception e) {
      logger.error("DB切断で予期せぬ例外が発生しました。", e);
      result = -1;
    }
    logger.debug("closeDbConecction() end.");
    return result;
  }

  /**
   * 
   */
  private void sleep() {

    /** 受信処理にインターバル（ミリ秒） */
    try {
      long interval_millis = 100;

      String interval_millis_str =
        (String) BatchUtils.getProperties(PROPERTY_FILE).get("interval_millis");
      if (interval_millis_str != null && interval_millis_str.length() > 0) {
        try {
          interval_millis = Long.parseLong(interval_millis_str);
        } catch (NumberFormatException e) {
        }
      }

      Thread.sleep(interval_millis); // millis ミリ秒Sleepする
    } catch (Exception e) {
      logger.error("受信間隔タイマ処理で例外が発生しました。", e);
    }
  }
}
