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

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.Attributes;

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 org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.utils.ALDateUtil;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFolder;
import com.aimluck.eip.common.ALAbstractSelectData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.webmail.beans.WebmailAccountLiteBean;
import com.aimluck.eip.webmail.util.WebMailUtils;

/**
 * ウェブメールのフォルダを管理するためのクラスです。 <br />
 */
public class WebMailFolderSelectData extends
    ALAbstractSelectData<EipTMailFolder, EipTMailFolder> {

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

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

  /** フォルダID */
  String folder_id = null;

  /** メールアカウント */
  private EipMMailAccount mail_account;

  /** メールアカウント一覧 */
  private List<WebmailAccountLiteBean> mailAccountList;

  // add start
  /** 代理受信アカウントフラグ */
  private boolean isRepresent;

  /** フォルダ情報結果セット */
  private ResultList<EipTMailFolder> entityList;

  // add end

  /**
   * 初期処理
   * 
   * @param action
   *            アクションクラス
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @see com.aimluck.eip.common.ALAbstractSelectData#init(com.aimluck.eip.modules.actions.common.ALAction,
   *      org.apache.turbine.util.RunData, org.apache.velocity.context.Context)
   */
  @Override
  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    int mailAccountId = 0;

    // ソート列が指定されていない場合はフォルダ名の昇順にする
    String sort = ALEipUtils.getTemp(rundata, context, LIST_SORT_STR);
    if (sort == null || sort.equals("")) {
      ALEipUtils.setTemp(rundata, context, LIST_SORT_STR, "folder_name");
    }
    // 自ポートレットからのリクエストであれば、パラメータを展開しセッションに保存する。
    if (ALEipUtils.isMatch(rundata, context)) {
      // change start
      // ENTITY ID
      // if (rundata.getParameters().containsKey(WebMailUtils.FOLDER_ID)) {
      // folder_id = rundata.getParameters().get(WebMailUtils.FOLDER_ID);
      // }
      if (rundata.getParameters().containsKey(ALEipConstants.ENTITY_ID)) {
        folder_id = rundata.getParameters().get(ALEipConstants.ENTITY_ID);
      }
      // change end

      // メールアカウントID
      // add start
      try {
        // リクエストパラメータを優先する
        if (rundata.getParameters().containsKey(WebMailUtils.ACCOUNT_ID)) {
          mailAccountId =
            Integer.parseInt(rundata.getParameters().get(
              WebMailUtils.ACCOUNT_ID));
          // セッションにセットし直す
          ALEipUtils.setTemp(rundata, context, WebMailUtils.ACCOUNT_ID, rundata
            .getParameters()
            .getString(WebMailUtils.ACCOUNT_ID));
        } else {
          // add end
          mailAccountId =
            Integer.parseInt(ALEipUtils.getTemp(
              rundata,
              context,
              WebMailUtils.ACCOUNT_ID));
        }
      } catch (Exception e) {
        mailAccountId = 0;
      }
    }
    // アカウントが取得できなかった場合は、設定されている初期選択アカウントIDを取得
    try {
      if (mailAccountId == 0) {
        mailAccountId =
          Integer.parseInt(ALEipUtils
            .getPortlet(rundata, context)
            .getPortletConfig()
            .getInitParameter("p3a-accounts"));
      }
    } catch (Exception e) {
    }

    // ALEipUser login_user = ALEipUtils.getALEipUser(rundata);

    // 現在操作中のメールアカウントを取得する
    // change start
    // mail_account =
    // ALMailUtils.getMailAccount(
    // (int) login_user.getUserId().getValue(),
    // mailAccountId);
    // if (mail_account == null) {
    // return;
    // }
    try {
      mail_account = WebMailUtils.getMailAccount(mailAccountId);
    } catch (Exception e) {
      logger.error("フォルダ詳細 メールアカウントの取得に失敗しました。アカウントID=" + mailAccountId, e);
      throw new ALDBErrorException();
    }
    if (mail_account == null) {
      try {
        mail_account =
          WebMailUtils.getDefaultMailAccount(ALEipUtils.getUserId(rundata));
        mailAccountId = mail_account.getAccountId();
        ALEipUtils.setTemp(rundata, context, WebMailUtils.ACCOUNT_ID, Integer
          .toString(mailAccountId));
      } catch (Exception e) {
        logger.error("フォルダ詳細 メールアカウントの取得に失敗しました。アカウントID=" + mailAccountId, e);
        throw new ALDBErrorException();
      }
    }
    // change end

    // ログインユーザーID取得
    user_id = ALEipUtils.getUserId(rundata);

    // add start
    isRepresent = false; // 代理受信フラグ初期化
    // 代理受信アカウントの場合
    if (mail_account.getUserId() != user_id) {
      try {
        // アカウントのログインユーザーに対する代理受信許可をチェック
        isRepresent =
          ALMailUtils.isRepresentReceiveAccount(mail_account, user_id);
        if (!isRepresent) {
          // ログインユーザーの代理受信元アカウントではない場合
          throw new ALPageNotFoundException();
        }
      } catch (Exception e) {
        throw new ALPageNotFoundException();
      }
    }
    // add end

    // フォルダIDが設定されていない場合や、対象のフォルダが見つからない場合はエラーにする
    EipTMailFolder folder =
      WebMailUtils.getEipTMailFolder(mail_account, folder_id);
    if (folder == null) {
      logger.error("[WebMail Folder] mail folder was not found.");
      return;
    }

    // ログインユーザーID取得
    user_id = ALEipUtils.getUserId(rundata);

    super.init(action, rundata, context);
  }

  /**
   * メールアカウント一覧を取得します。
   * 
   * @param action
   *            アクションクラス
   * @param rundata
   *            JetSpeedランデータ
   * @throws Exception
   */
  public void loadMailAccountList(RunData rundata, Context context)
      throws Exception {
    try {
      // メールアカウント一覧
      mailAccountList = new ArrayList<WebmailAccountLiteBean>();

      List<EipMMailAccount> aList =
        WebMailUtils.getMailAccountNameList(ALEipUtils.getUserId(rundata));

      if (aList == null) {
        return;
      }

      WebmailAccountLiteBean bean = null;
      Iterator<EipMMailAccount> iter = aList.iterator();
      while (iter.hasNext()) {
        EipMMailAccount account = iter.next();
        bean = new WebmailAccountLiteBean();
        bean.initField();
        bean.setAccountId(account.getAccountId());
        bean.setAccountName(account.getAccountName());
        mailAccountList.add(bean);
      }
    } catch (Exception ex) {
      logger.error("フォルダ一覧　メールアカウント一覧の取得に失敗しました。　"
        + ALEipUtils.getUserFullName(user_id), ex);
      throw ex;
    }
  }

  /**
   * 一覧データを取得します。<BR>
   * 
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return フォルダ一覧
   * 
   */
  @Override
  protected ResultList<EipTMailFolder> selectList(RunData rundata,
      Context context) throws ALPageNotFoundException, ALDBErrorException {
    try {
      SelectQuery<EipTMailFolder> query = getSelectQuery(rundata, context);
      buildSelectQueryForListView(query);
      // remove by motegi start ソート制御はgetSelectQueryだけで行なう
      // buildSelectQueryForListViewSort(query, rundata, context);
      // remove end

      // add start
      // 親フォルダを辿るための結果セット（アカウントの全フォルダ）を取得します。
      SelectQuery<EipTMailFolder> queryAll = getSelectQuery(rundata, context);
      entityList = queryAll.getResultList();
      // add end

      return query.getResultList();
    } catch (Exception ex) {
      logger.error(
        "フォルダ一覧取得に失敗しました。　" + ALEipUtils.getUserFullName(user_id),
        ex);
      return null;
    }
  }

  /**
   * 検索条件を設定した SelectQuery を返します。 <BR>
   * 
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return SQLオブジェクト
   */
  private SelectQuery<EipTMailFolder> getSelectQuery(RunData rundata,
      Context context) {
    SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

    Expression exp =
      ExpressionFactory.matchDbExp(
        EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY,
        mail_account);
    query.setQualifier(exp);

    // ソート項目が「フォルダ名」の場合、ソート条件を先に付加する
    String sort = ALEipUtils.getTemp(rundata, context, LIST_SORT_STR);
    String sort_type = null;
    if (EipTMailFolder.FOLDER_NAME_PROPERTY.equals(getColumnMap()
      .getValue(sort))) {

      sort_type = ALEipUtils.getTemp(rundata, context, LIST_SORT_TYPE_STR);

      if (sort_type != null
        && ALEipConstants.LIST_SORT_TYPE_DESC.equals(sort_type)) {
        // 降順指定の場合、フォルダ種別、フォルダタイプの降順を設定
        query.orderDesending(EipTMailFolder.FOLDER_KIND_PROPERTY);
        query.orderDesending(EipTMailFolder.FOLDER_TYPE_PROPERTY);
        query.orderDesending(EipTMailFolder.FOLDER_NAME_PROPERTY);
      } else {
        // 昇順指定の場合、フォルダ種別、フォルダタイプの昇順を設定
        query.orderAscending(EipTMailFolder.FOLDER_KIND_PROPERTY);
        query.orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY);
        query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);
      }
    } else {

      sort_type = ALEipUtils.getTemp(rundata, context, LIST_SORT_TYPE_STR);
      if (sort_type != null
        && ALEipConstants.LIST_SORT_TYPE_DESC.equals(sort_type)) { //
        // 降順指定の場合、フォルダ名の降順を設定
        query.orderDesending(EipTMailFolder.FOLDER_VOLUME_PROPERTY);
        query.orderDesending(EipTMailFolder.FOLDER_NAME_PROPERTY);
      } else { //
        // 昇順指定の場合、フォルダ名の昇順を設定
        query.orderAscending(EipTMailFolder.FOLDER_VOLUME_PROPERTY);
        query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);
      }
    }
    current_sort_type = sort_type;
    current_sort = sort;

    return query;
  }

  /**
   * 詳細データを取得します。 <BR>
   * 
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return DBから取得したフォルダ情報
   */
  @Override
  protected EipTMailFolder selectDetail(RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    // change start
    // オブジェクトモデルを取得
    // EipTMailFolder folder = WebMailUtils.getEipTMailFolder(rundata, context);

    try {
      EipTMailFolder folder =
        WebMailUtils.getEipTMailFolder(mail_account, folder_id);
      // change end

      return folder;
    } catch (Exception e) {
      logger.error(
        "フォルダ情報の詳細取得に失敗しました。　" + ALEipUtils.getUserFullName(user_id),
        e);
      throw new ALPageNotFoundException();
    }
  }

  /**
   * ResultData に値を格納して返します。（一覧データ） <BR>
   * 
   * @param obj
   *            DBから取得したフォルダ情報
   * @return 画面表示用データ
   */
  @Override
  protected Object getResultData(EipTMailFolder obj)
      throws ALPageNotFoundException, ALDBErrorException {
    try {
      folder_id = obj.getFolderId().toString();

      WebMailFolderResultData rd = new WebMailFolderResultData();

      rd.initField();
      rd.setFolderId(obj.getFolderId());
      rd.setFolderName(obj.getFolderName());

      // add start
      rd.setParentFolderPath(getParentFolderPath(obj));
      // add end

      rd.setFolderVolume(obj.getFolderVolume() / 1024);

      // add start
      // ルートフォルダ、受信トレイ、送信トレイ、下書き、ごみ箱は編集・削除不可
      if (mail_account.getDefaultFolderId().equals(obj.getFolderId())
        || mail_account.getDefaultSendFolderId().equals(obj.getFolderId())
        || obj.getFolderType().equals(ALMailUtils.FOLDER_TYPE_DRAFT)
        || obj.getFolderType().equals(ALMailUtils.FOLDER_TYPE_TRASH)
        || obj.getFolderType().equals(ALMailUtils.FOLDER_TYPE_SPAM)
        || obj.getFolderType().equals(ALMailUtils.FOLDER_TYPE_RETURN)
        || obj.getParentFolderId() == (WebMailUtils.ROOT_PARENT_FODLER_ID)) {
        rd.setCanUpdate(false);
      } else {
        rd.setCanUpdate(true);
      }

      return rd;
    } catch (Exception ex) {
      logger.error(
        "フォルダ情報の詳細取得に失敗しました。　" + ALEipUtils.getUserFullName(user_id),
        ex);
      return null;
    }
  }

  /**
   * ResultData に値を格納して返します。（詳細データ） <BR>
   * 
   * @param obj
   *            DBから取得したフォルダ情報
   * @return 画面表示用フォルダ情報
   */
  @Override
  protected Object getResultDataDetail(EipTMailFolder record)
      throws ALPageNotFoundException, ALDBErrorException {

    try {
      folder_id = record.getFolderId().toString();

      WebMailFolderResultData rd = new WebMailFolderResultData();
      rd.initField();
      rd.setFolderId(record.getFolderId());
      rd.setFolderName(record.getFolderName());

      // add start
      rd.setParentFolderId(record.getParentFolderId());

      if (record.getParentFolderId() != WebMailUtils.ROOT_PARENT_FODLER_ID) {
        EipTMailFolder parent_folder =
          WebMailUtils.getEipTMailFolder(mail_account, record
            .getParentFolderId()
            .toString());
        rd.setParentFolderName(parent_folder.getFolderName());
      }

      rd.setFolderVolume(record.getFolderVolume() / 1000);
      // add end

      rd.setCreateDate(ALDateUtil.format(record.getCreateDate(), "yyyy年M月d日"));

      // デフォルトのフォルダは編集・削除不可
      if (mail_account.getDefaultFolderId().equals(record.getFolderId())
      // add start
        // ルートフォルダ、受信トレイ、送信トレイ、下書き、ごみ箱は編集・削除不可
        || mail_account.getDefaultSendFolderId().equals(record.getFolderId())
        || record.getFolderType().equals(ALMailUtils.FOLDER_TYPE_DRAFT)
        || record.getFolderType().equals(ALMailUtils.FOLDER_TYPE_TRASH)
        || record.getFolderType().equals(ALMailUtils.FOLDER_TYPE_SPAM)
        || record.getFolderType().equals(ALMailUtils.FOLDER_TYPE_RETURN)
        || record.getParentFolderId() == (WebMailUtils.ROOT_PARENT_FODLER_ID)
      // add end
      ) {
        rd.setCanUpdate(false);
      } else {
        rd.setCanUpdate(true);
      }

      // add start
      // 代理受信アカウントのフォルダは編集・削除不可
      if (isRepresent) {
        rd.setCanUpdate(false);
      }
      // add end

      return rd;
    } catch (Exception ex) {
      logger.error(
        "フォルダ情報の詳細取得に失敗しました。　" + ALEipUtils.getUserFullName(user_id),
        ex);
      return null;
    }
  }

  /**
   * ソート項目マップ作成
   * 
   * @return ソート項目マップ
   */
  @Override
  protected Attributes getColumnMap() {
    Attributes map = new Attributes();
    // add start
    map.putValue("folder_name", EipTMailFolder.FOLDER_NAME_PROPERTY);
    map.putValue("folder_volume", EipTMailFolder.FOLDER_VOLUME_PROPERTY);
    // add end
    return map;
  }

  /**
   * フォルダIDを取得します。<BR>
   * 
   * @return フォルダID
   */
  public String getFolderId() {
    return folder_id;
  }

  // add start
  /**
   * メールアカウントの一覧を取得します。<BR>
   * 
   * @return メールアカウント一覧
   */
  public List<WebmailAccountLiteBean> getMailAccountList() {
    return mailAccountList;
  }

  /**
   * 現在選択中のアカウントIDを取得します。<BR>
   * 
   * @return アカウントID
   */
  public int getAccountId() {
    return mail_account.getAccountId();
  }

  /**
   * 2つのIDの比較結果を取得します。<BR>
   * 
   * @param id1
   *            ID1
   * @param id2
   *            ID2
   * @return true:同一 false:相違
   */
  public boolean isMatch(int id1, long id2) {
    return id1 == (int) id2;
  }

  // add end

  /**
   * アクセス権限チェック用メソッド。<br />
   * アクセス権限の機能名を返します。
   * 
   * @return
   */
  @Override
  public String getAclPortletFeature() {
    // return ALAccessControlConstants.POERTLET_FEATURE_CABINET_FOLDER;
    return null;
  }

  // add by motegi start
  /**
   * 親フォルダパスを取得
   * 
   * @param entity
   *            対象フォルダ
   */
  private String getParentFolderPath(EipTMailFolder entity) {

    List<String> nameList = new ArrayList<String>();
    // nameList.add(entity.getFolderName());

    // 親フォルダを辿ってフォルダ名リストを取得する。
    setParentFolderName(entity, nameList);

    int size = nameList.size();
    StringBuffer buf = new StringBuffer();
    for (int i = size - 1; i >= 0; i--) {
      String str = nameList.get(i);
      if (i == size - 1) {
        buf.append(str);
      } else {
        buf.append("->" + str);
      }
    }

    return buf.toString();
  }

  /**
   * 親フォルダパスを取得
   * 
   * @param entity
   *            対象フォルダ
   * @param nameList
   *            フォルダ名リスト
   */
  private void setParentFolderName(EipTMailFolder folder, List<String> nameList) {

    for (EipTMailFolder f : entityList) {
      if (folder.getParentFolderId().intValue() == f.getFolderId().intValue()) {
        nameList.add(f.getFolderName());
        if (f.getParentFolderId().intValue() != 0) {
          setParentFolderName(f, nameList);
        }
        break;
      }
    }
  }
  // add end
}
