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

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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.field.ALCellDateTimeField;
import com.aimluck.commons.field.ALCellStringField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.cayenne.om.portlet.EipTSchedule;
import com.aimluck.eip.cayenne.om.portlet.EipTScheduleMap;
import com.aimluck.eip.common.ALAbstractFormWindow;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.mail.util.ALEipUserAddr;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.schedule.data.ScheduleMemberUser;
import com.aimluck.eip.schedule.util.ScheduleUtils;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.util.ALEipUtils;

/**
 * スケジュールの状態変更を行うクラスです。
 * 
 */
public class ScheduleChangeStatusFormData
// change start
    // 運用課題No.68
    // extends ALAbstractFormData {
    extends ALAbstractFormWindow {
  // change end
  /** <code>logger</code> logger */
  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(ScheduleChangeStatusFormData.class.getName());

  /** <code>status</code> 状態 */
  private ALCellStringField status;

  /** <code>tmpView</code> 表示する日 */
  private String tmpView;

  /** <code>end_date</code> 終了日時 */
  private ALCellDateTimeField view_date;

  // add start
  /** 更新対象 */
  private String updatingPlace = "";

  /** ステータス変更要求：返信せず削除 */
  public static final String CHANGE_STATUS_REQ_NONRESPONSE = "RN";

  /** 更新対象：重要フラグ */
  public static final String UPDATING_PLACE_PRIORITY = "change_priority";

  /** 重要フラグ更新成功メッセージ（JSONで正常メッセージとして返すため、Javascript側でも判定が必要） */
  public static final String PRIORITY_UPDATE_SUCCESS_MSG = "PriorityUpdate=";

  /** 正常系のメッセージを格納するリスト */
  private List<String> normalMsgList;

  /** ログインユーザー */
  private ALEipUser loginUser;

  /** 対象ユーザーID */
  private int userId;

  /** スケジュールID */
  private String scheduleId = "";

  // add end

  // add start 要件No.1 スケジュール案内受信
  /** <code>comment</code> 返信コメント */
  private ALStringField comment;

  // add end

  public void loadParametersViewDate(RunData rundata, Context context) {
    // add start
    normalMsgList = new ArrayList<String>();
    loginUser = ALEipUtils.getALEipUser(rundata);
    // add end
    if (ALEipUtils.isMatch(rundata, context)) {
      if (rundata.getParameters().containsKey("view_date")) {
        ALCellDateTimeField dummy = new ALCellDateTimeField("yyyy-MM-dd");
        tmpView = rundata.getParameters().getString("view_date");
        ALEipUtils.setTemp(rundata, context, "tmpView", tmpView);
        dummy.setValue(tmpView);
        if (!dummy.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, "tmpView");
          logger.debug("[ScheduleFormData] Parameter cannot validate");
          ALEipUtils.redirectPageNotFound(rundata);
          return;
        }
      }
      // add start
      // 対象ユーザーIDを取得
      if (rundata.getParameters().containsKey("userid")) {
        userId = rundata.getParameters().getInt("userid");
      } else {
        // 得られない場合はログインユーザーを対象ユーザーとする
        userId = (int) loginUser.getUserId().getValue();
      }
      // スケジュールIDを取得
      // change start 要件No.16 スケジュール画面（月単位／週単位／日単位）右クリックメニュー
      // scheduleId =
      // ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);
      // // エンティティIDがセッションから取得出来ない場合は、リクエストパラメータから取得する
      // if (null == scheduleId || "".equals(scheduleId)) {
      // if (rundata.getParameters().containsKey(ALEipConstants.ENTITY_ID)) {
      // scheduleId =
      // rundata.getParameters().getString(ALEipConstants.ENTITY_ID);
      // }
      // }
      if (rundata.getParameters().containsKey(ALEipConstants.ENTITY_ID)) {
        scheduleId = rundata.getParameters().getString(ALEipConstants.ENTITY_ID);
      } else {
        scheduleId = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);
      }
      // change end
      // add end
    }
    tmpView = ALEipUtils.getTemp(rundata, context, "tmpView");
  }

  /*
   * 
   */
  public void initField() {
    // フィールドの初期化
    // 状態
    status = new ALCellStringField();
    status.setTrim(true);

    Date now = new Date();
    // 指定日時
    view_date = new ALCellDateTimeField("yyyy-MM-dd");
    if (tmpView == null || tmpView.equals("")) {
      view_date.setValue(now);
    } else {
      view_date.setValue(tmpView);
    }
    view_date.setFieldName("指定日時");

    // add start 要件No.1 スケジュール案内受信
    comment = new ALStringField();
    comment.setFieldName("返信コメント");
    // add end
  }

  /*
   * 
   */
  @Override
  protected void setValidator() {
    // add start 要件No.1 スケジュール案内受信
    // 返信コメントの最大文字数
    comment.limitMaxLength(1000);
    // add end
  }

  /**
   * 
   * @param msgList
   * @return
   */
  @Override
  protected boolean validate(List<String> msgList) {
    // change start
    // 異常値が設定される恐れがほぼ無いため、チェックを削除
    // // T: 仮スケジュール
    // // C: 確認済みスケジュール
    // // R: 棄却されたスケジュール
    // // O: 通常スケジュール（オーナー）
    // // 以上の文字列以外は入力チェックNGとする。
    // return "T".equals(status.getValue())
    // || "C".equals(status.getValue())
    // || "R".equals(status.getValue())
    // || "O".equals(status.getValue());

    // add start 要件No.1 スケジュール案内受信
    if (ScheduleConst.SCHEDULEMAP_STATUS_CONSENT.equals(status.getValue())
      || ScheduleConst.SCHEDULEMAP_STATUS_PROVISIONAL.equals(status.getValue())
      || ScheduleConst.SCHEDULEMAP_STATUS_VETO.equals(status.getValue())
      || (ScheduleConst.SCHEDULEMAP_STATUS_REMOVE + ScheduleConst.SCHEDULEMAP_STATUS_VETO).equals(status.getValue())) {
      comment.validate(msgList);
    }
    // add end

    // change start 要件No.1 スケジュール案内受信
    // return true;
    return (msgList.size() == 0);
    // change end
    // change end
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   */
  @Override
  protected boolean loadFormData(RunData rundata, Context context, List<String> msgList) {
    // このメソッドは利用されません。
    return false;
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   */
  @Override
  protected boolean insertFormData(RunData rundata, Context context, List<String> msgList) {
    // このメソッドは利用されません。
    return false;
  }

  /*
   * @see com.aimluck.eip.common.ALAbstractFormData#updateFormData(RunData,
   *      context, List<String>)
   */
  @Override
  protected boolean updateFormData(RunData rundata, Context context, List<String> msgList) throws ALDBErrorException, ALPageNotFoundException {
    // add start
    // メール送信可
    boolean canSendMail = false;
    // エラーメッセージ用処理名
    String actionName = "不明";
    // リクエストされた更新後状態の要求
    String sValue = "";
    // 更新後の状態
    String resultStatus = "";
    // 更新対象スケジュールマップ
    EipTScheduleMap schedule = null;
    // add end
    try {

      // オブジェクトモデルを取得
      // change start
      // EipTScheduleMap schedule =
      // ScheduleUtils.getEipTScheduleMap(rundata, context);
      schedule = ScheduleUtils.getEipTScheduleMapByLogicKey(userId, new Integer(scheduleId));
      // change end
      if (schedule == null) {
        return false;
      }
      // change start
      // schedule.setStatus(status.getValue());
      // 更新先を判定する
      if (UPDATING_PLACE_PRIORITY.equals(updatingPlace)) {
        // -----------------
        // 重要フラグを更新する
        // -----------------
        actionName = "重要フラグ更新";
        schedule.setPriority(status.getValue());
        canSendMail = false;
      } else {
        // -----------------
        // 状態を更新する
        // -----------------
        actionName = "状態更新";
        sValue = status.getValue();
        // ステータス値を判定する
        if (sValue.startsWith(ScheduleConst.SCHEDULEMAP_STATUS_REMOVE)) {
          // 削除系の場合
          // 状態への設定値を[削除]とする
          resultStatus = ScheduleConst.SCHEDULEMAP_STATUS_REMOVE;
          // ステータス値の2文字目で処理を分岐する
          if (sValue.substring(1).startsWith(ScheduleConst.SCHEDULEMAP_STATUS_VETO)) {
            canSendMail = true;
          } else {
            // 返信せず削除
            // ダミー未回答を設定する
            schedule.setDummyNonResponse(ScheduleConst.SCHEDULEMAP_DUMMY_NON_RES_T);
            canSendMail = true;
          }
        } else {
          // 削除系でない場合、ステータス値を状態の設定値とする
          resultStatus = sValue;
          canSendMail = true;
        }
        schedule.setStatus(resultStatus);
      }
      // change end
      Database.commit();

      // add start
      if (UPDATING_PLACE_PRIORITY.equals(updatingPlace)) {
        // 更新先が「重要フラグ」でコミット成功時、成功メッセージを設定
        normalMsgList.add(PRIORITY_UPDATE_SUCCESS_MSG + status.getValue());
        logger.debug("prioryty update. success message set.");
      }
      // add end

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
        schedule.getScheduleId(),
        ALEventlogConstants.PORTLET_TYPE_SCHEDULE,
        schedule.getEipTSchedule().getName());

      // orm_map.doUpdate(schedule);
    } catch (Exception e) {
      Database.rollback();
      // change start
      // logger.error("[ScheduleChangeStatusFormData]", e);
      // throw new ALDBErrorException();
      // change start 要件No.16 スケジュール画面（月単位／週単位／日単位）右クリックメニュー
      // logger
      // .error("共有スケジュールの更新に失敗しました。ログインユーザー:" +
      // loginUser.getUserId().getValue() + "/スケジュールID:" + scheduleId +
      // "/対象ユーザー:" + userId + "/操作:" + actionName, e);
      // msgList.add("共有スケジュールの更新に失敗しました。");
      logger.error("スケジュールの更新に失敗しました。ログインユーザー:" + loginUser.getUserId().getValue() + "/スケジュールID:" + scheduleId + "/対象ユーザー:" + userId + "/操作:" + actionName, e);
      msgList.add("スケジュールの更新に失敗しました。");
      // change end
      return false;
      // change end
    }

    // add start
    if (!canSendMail) {
      // メールを送信しない場合、ここで処理を終了する
      return true;
    }

    // -----------------
    // メール送信処理
    // -----------------

    // スケジュール本体
    EipTSchedule eipTScheduleObj = null;
    // 参加メンバー
    List<ScheduleMemberUser> smList = null;

    // 送信メール用スケジュール情報取得
    try {
      eipTScheduleObj = schedule.getEipTSchedule();
      smList = ScheduleUtils.getScheduleMemberUsers(eipTScheduleObj.getScheduleId());
    } catch (ALDBErrorException e) {
      Database.rollback();
      logger.error("メール送信用のスケジュール情報取得に失敗しました。ログインユーザー:" + loginUser.getUserId().getValue() + "/スケジュールID:" + scheduleId + "/対象ユーザー:" + userId, e);
      msgList.add("メール送信用のスケジュール情報取得に失敗しました。");
      return false;
    }

    // メール送信先(ALEipUser)
    List<ALEipUser> sendToEipUserList = new ArrayList<ALEipUser>(0);
    // add start
    // メール送信先(ALEipUser)秘書設定元送信用
    List<ALEipUser> sendToEipClientUserList = new ArrayList<ALEipUser>(0);
    // add end
    // 参加メンバーを必須と任意で仕分けする
    List<ScheduleMemberUser> reqSmList = new ArrayList<ScheduleMemberUser>(0);
    List<ScheduleMemberUser> subSmList = new ArrayList<ScheduleMemberUser>(0);
    for (ScheduleMemberUser sm : smList) {
      if (ScheduleConst.SCHEDULEMAP_REQUIRED_T.equals(sm.getRequired())) {
        // 必須に追加
        reqSmList.add(sm);
      } else {
        // 任意に追加
        subSmList.add(sm);
      }
      // 返信せず削除以外は、主催者を送信先(ALEipUser)に追加する
      if (eipTScheduleObj.getOwnerId().longValue() == sm.getUserId().getValue() && !CHANGE_STATUS_REQ_NONRESPONSE.equals(sValue)) {
        sendToEipUserList.add(sm);
      }
      // 対象者を送信先(ALEipUser)に追加する
      if (schedule.getUserId().longValue() == sm.getUserId().getValue()) {
        // sendToEipUserList.add(sm);
        // add start
        if (userId != (int) loginUser.getUserId().getValue()) {
          // 秘書設定元へ代理回答したことを通知するため
          sendToEipClientUserList.add(sm);
        }
        // add end
      }
    }

    // メール送信先
    // 対象者と主催者（ログインユーザーを除く）を送信先にする
    List<ALEipUserAddr> sendToUserList = ALMailUtils.getALEipUserAddrs(sendToEipUserList, (int) loginUser.getUserId().getValue(), false);

    // add start
    List<ALEipUserAddr> sendToClientUserList = ALMailUtils.getALEipUserAddrs(sendToEipClientUserList, (int) loginUser.getUserId().getValue(), false);
    // add end

    // アクション文
    String actionText = "";
    // add start 要件No.1 スケジュール案内受信
    String subjectActionText = "";
    String commentText = "";
    String subjectActionTextForSubstitute = "";
    // add end
    if (CHANGE_STATUS_REQ_NONRESPONSE.equals(sValue)) {
      // 返信せず削除
      actionText = "返信せず削除しました。";
      // add start 要件No.1 スケジュール案内受信
      subjectActionText = "削除";
      subjectActionTextForSubstitute = "返信せず削除(代理)";
      // add end
    } else if (ScheduleConst.SCHEDULEMAP_STATUS_CONSENT.equals(resultStatus)) {
      // 承諾に更新
      actionText = "承諾しました。";
      // add start 要件No.1 スケジュール案内受信
      subjectActionText = "承諾";
      subjectActionTextForSubstitute = "代理承諾";
      commentText = comment.getValue();
      // add end
    } else if (ScheduleConst.SCHEDULEMAP_STATUS_PROVISIONAL.equals(resultStatus)) {
      // 仮承諾に更新
      actionText = "仮承諾しました。";
      // add start 要件No.1 スケジュール案内受信
      subjectActionText = "仮承諾";
      subjectActionTextForSubstitute = "代理仮承諾";
      commentText = comment.getValue();
      // add end
    } else if (ScheduleConst.SCHEDULEMAP_STATUS_REMOVE.equals(resultStatus) || ScheduleConst.SCHEDULEMAP_STATUS_VETO.equals(resultStatus)) {
      // 削除または辞退に更新
      actionText = "辞退しました。";
      // add start 要件No.1 スケジュール案内受信
      subjectActionText = "辞退";
      subjectActionTextForSubstitute = "代理辞退";
      commentText = comment.getValue();
      // add end
    } else if (ScheduleConst.SCHEDULEMAP_STATUS_NON_RES.equals(resultStatus)) {
      // 未回答に更新
      actionText = "未回答に戻しました。";
      // add start 要件No.1 スケジュール案内受信
      subjectActionText = "未回答";
      subjectActionTextForSubstitute = "未回答に戻す(代理)";
      // add end
    }
    // メール送信実行
    if (!ScheduleUtils.sendScheduleMail(sendToUserList, userId, eipTScheduleObj, reqSmList, subSmList,
    // change start 要件No.1 スケジュール案内受信
      // "予定回答",
      subjectActionText,
      // change end
      actionText,
      rundata,
      // add start 要件No.1 スケジュール案内受信
      commentText,
      ScheduleUtils.CREATE_MSG_MODE_RES
    // add end
      )) {
      msgList.add("メールを送信できませんでした。");
      return false;
    }

    if (sendToClientUserList.size() > 0) {
      // 秘書設定元へ代理操作したことを通知
      if (!ScheduleUtils.sendScheduleMail(sendToClientUserList, (int) loginUser.getUserId().getValue(), userId, eipTScheduleObj, reqSmList, subSmList,
      // change start 要件No.1 スケジュール案内受信
        // ScheduleUtils.SUBSTITUTE_RESPONSE,
        subjectActionTextForSubstitute,
        // change end
        actionText,
        rundata,
        // add start 要件No.1 スケジュール案内受信
        commentText,
        ScheduleUtils.CREATE_MSG_MODE_SUBRES
      // add end
        )) {
        msgList.add("メールを送信できませんでした。");
        return false;
      }
    }
    // add end
    return true;
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   */
  @Override
  protected boolean deleteFormData(RunData rundata, Context context, List<String> msgList) {
    // このメソッドは利用されません。
    return false;
  }

  public ALCellDateTimeField getViewDate() {
    return view_date;
  }

  // add start
  /**
   * 更新先設定
   * 
   * @param value
   *            更新先（状態の場合「change_status」、重要フラグの場合「change_priority」）
   */
  public void setUpdatingPlace(String value) {
    updatingPlace = value;
  }

  /**
   * 正常メッセージリスト取得
   * 
   * @return 正常メッセージリスト
   */
  public List<String> getNormalMsgList() {
    return normalMsgList;
  }
  // add end

}
