/*
 * 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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALDateTimeField;
import com.aimluck.eip.category.util.CommonCategoryUtils;
import com.aimluck.eip.cayenne.om.portlet.EipTCommonCategory;
import com.aimluck.eip.cayenne.om.portlet.EipTSchedule;
import com.aimluck.eip.cayenne.om.portlet.EipTScheduleMap;
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.common.ALPermissionException;
import com.aimluck.eip.mail.util.ALEipUserAddr;
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.schedule.beans.ScheduleBean;
import com.aimluck.eip.schedule.util.ScheduleUtils;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.services.accessctl.ALAccessControlFactoryService;
import com.aimluck.eip.services.accessctl.ALAccessControlHandler;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.userfacility.beans.UserFacilityLiteBean;
import com.aimluck.eip.util.ALEipUtils;

/**
 * カレンダーに表示する予定のフォームデータを管理するクラスです。
 */
public class ScheduleWeeklyJSONFormData {

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

  // update

  /** 開始日時 */
  private ALDateTimeField startDate;

  /** 終了日時 */
  private ALDateTimeField endDate;

  /** 基準日 */
  private ALDateTimeField viewDate;

  /** リクエストパラメータ：開始日時 */
  private String start_date;

  /** リクエストパラメータ：終了日時 */
  private String end_date;

  /** リクエストパラメータ：基準日 */
  private String view_date;

  /** エンティティID（スケジュールID） */
  private int entityId;

  // remove start
  // 使用しないため削除
  // /** アクセス権限 */
  // private String aclPortletFeature;
  // remove end

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

  /** 更新対象・コピー元スケジュール */
  private EipTSchedule schedule;

  // remove start
  // 使用しないため削除
  // private boolean isEdit;
  //
  // private String orgId;
  // remove end

  // private boolean is_span; // 期間スケジュールかどうか
  //
  // private boolean isMember; // 自分はメンバーに含まれるかどうか

  private int edit_repeat_flag;

  /** 参加メンバー */
  private List<ALEipUser> memberList;

  /** 必須参加メンバー */
  private List<ALEipUser> reqMemberList;

  /** 任意参加メンバー */
  private List<ALEipUser> subMemberList;

  private List<EipTScheduleMap> scheduleMaps;

  private int ownerId;

  /** エラーメッセージ一覧 */
  private ArrayList<String> msgList;

  private boolean isViewList;

  // remove start
  // 使用しないため削除
  // private boolean ignore_duplicate_facility;
  // remove end

  // add start
  /** <code>loginUserName</code> ログインユーザー名 */
  private String loginUserName;

  /** 日またぎ更新モード */
  private String straddle_mode = null;

  /** 日またぎ更新：変更日数 */
  private int straddle_change_days = 0;

  /** 日またぎ更新：開始時刻 */
  private String straddle_start_time = null;

  /** 日またぎ更新：終了時刻 */
  private String straddle_end_time = null;

  /** 日またぎ更新モード：日付変更 */
  private static final String STRADDLE_MODE_CHANGE_DAY = "changeDay";

  /** 日またぎ更新モード：開始時刻変更 */
  private static final String STRADDLE_MODE_CHANGE_START_TIME = "changeStartTime";

  /** 日またぎ更新モード：終了時刻変更 */
  private static final String STRADDLE_MODE_CHANGE_END_TIME = "changeEndTime";

  /** スケジュールマップ登録用共有カテゴリ */
  private EipTCommonCategory commonCategory = null;

  // add end

  /**
   * 入力/表示フィールド・権限初期化
   */
  public void initField() {
    // remove start
    // 使用しないため削除
    // clPortletFeature =
    // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF;
    // remove end
  }

  /**
   * 初期化処理
   * 
   * @param action
   *            呼び出し元アクション
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   */
  public void init(ALAction action, RunData rundata, Context context) throws ALPageNotFoundException, ALDBErrorException {
    // add start
    ALEipUser loginuser = ALEipUtils.getALEipUser(rundata);
    loginUserName = loginuser.getName().getValue();
    // add end
    start_date = null;
    end_date = null;
    view_date = null;
    entityId = 0;
    userId = 0;
    // is_span = false;
    // isMember = false;
    // remove start
    // 使用しないため削除
    // isEdit = false;
    // remove end
    memberList = new ArrayList<ALEipUser>();
    // add start
    reqMemberList = new ArrayList<ALEipUser>(0);
    subMemberList = new ArrayList<ALEipUser>(0);
    // add end
    scheduleMaps = null;
    ownerId = 0;
    edit_repeat_flag = 0;
    startDate = new ALDateTimeField("yyyy-MM-dd-HH-mm");
    endDate = new ALDateTimeField("yyyy-MM-dd-HH-mm");
    viewDate = new ALDateTimeField("yyyy-MM-dd");
    msgList = new ArrayList<String>();
    isViewList = false;
    // remove start
    // 使用しないため削除
    // orgId = Database.getDomainName();
    //
    // aclPortletFeature =
    // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF;
    //
    // ignore_duplicate_facility = false;
    // remove end

  }

  /**
   * 画面表示処理
   * 
   * @param action
   *            呼び出し元アクション
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @param msgList
   *            エラーメッセージ一覧
   * @return JSON用出力文字列
   */
  public String doViewList(ALAction action, RunData rundata, Context context, List<String> msgList) {
    try {
      doCheckAclPermission(rundata, context, ALAccessControlConstants.VALUE_ACL_LIST);

      // remove start
      // 変数スコープが不正であるため、削除
      // AjaxScheduleResultData rd;
      // ScheduleBean bean;
      // remove end
      List<List<ScheduleBean>> termScheduleList = new ArrayList<List<ScheduleBean>>();
      List<AjaxScheduleResultData> _scheduleList = new ArrayList<AjaxScheduleResultData>();
      List<ScheduleBean> scheduleList = new ArrayList<ScheduleBean>();
      List<String> holidayList = new ArrayList<String>();
      List<String> dateList = new ArrayList<String>();
      List<String> dayOfWeekList = new ArrayList<String>();

      AjaxScheduleWeeklyGroupSelectData listData = new AjaxScheduleWeeklyGroupSelectData();
      // ScheduleWeeklySelectData listData = new
      // ScheduleWeeklySelectData();
      listData.doSelectList(null, rundata, context);
      JSONObject json = new JSONObject();
      json.put("hasAcl", hasAcl(rundata));
      json.put("today", listData.getToday().toString());
      json.put("prevDate", listData.getPrevDate().toString());
      json.put("nextDate", listData.getNextDate().toString());
      json.put("prevWeek", listData.getPrevWeek().toString());
      json.put("nextWeek", listData.getNextWeek().toString());
      json.put("prevMonth", listData.getPrevMonth().toString());
      json.put("nextMonth", listData.getNextMonth().toString());

      List<AjaxScheduleDayContainer> dayList = listData.getContainer().getDayList();
      List<AjaxTermScheduleWeekContainer> termList = listData.getWeekTermContainerList();
      List<AjaxTermScheduleDayContainer> termDayList;

      int dayListSize = dayList.size();

      Date containerDate = null;

      // 期間単位
      for (AjaxTermScheduleWeekContainer termContainer : termList) {
        if (!termContainer.hasVisibleTerm()) {
          continue;
        }
        termDayList = termContainer.getDayList();
        List<ScheduleBean> _termScheduleList = new ArrayList<ScheduleBean>(); // termSchedule
        int termDayListSize = termDayList.size();
        for (int k = 0; k < termDayListSize; k++) {
          AjaxTermScheduleDayContainer termDayContainer = termDayList.get(k);
          if (k == 0) {
            containerDate = termDayContainer.getDate().getValue();
          }
          // change start
          // 変数スコープを正常化
          // rd = termDayContainer.getTermResultData();
          AjaxScheduleResultData rd = termDayContainer.getTermResultData();
          // change end
          if (rd != null && containerDate != null) {
            int stime = (int) (rd.getStartDate().getValue().getTime() / 86400000);
            int etime = (int) (rd.getEndDate().getValue().getTime() / 86400000);
            int ctime = (int) (containerDate.getTime() / 86400000);
            int col = etime - stime + 1;
            int rindex = stime - ctime;
            // change start
            // 変数スコープを正常化
            // bean = new ScheduleBean();
            ScheduleBean bean = new ScheduleBean();
            // change end
            bean.initField();
            bean.setResultData(rd);

            // change start
            // if (!rd.isPublic() && !rd.isMember()) {
            // bean.setName("非公開");
            // }
            setNondisclosureMask(rd, bean, listData);
            // change end
            bean.setColspanReal(col);
            bean.setIndex(k);
            bean.setIndexReal(rindex);
            // change start
            // ログインユーザーが[秘書]である主催者・参加メンバーの予定も表示対象とする
            // if (!rd.isHidden() || rd.isMember()) {
            if (!rd.isHidden() || rd.isMember() || rd.isLoginuser()) {
              // change end
              _termScheduleList.add(bean);
            }
          }
        }
        termScheduleList.add(_termScheduleList);
      }

      // 日単位
      for (int i = 0; i < dayListSize; i++) {
        AjaxScheduleDayContainer container = dayList.get(i);
        if (i == 0) {
          containerDate = container.getDate().getValue();
        }
        dateList.add(container.getDate().toString());
        dayOfWeekList.add(container.getDate().getDayOfWeek());
        _scheduleList = container.getScheduleList();
        if (container.isHoliday()) {
          holidayList.add(container.getHoliday().getName().getValue());
        } else {
          holidayList.add("");
        }
        if (i == 0) {
          json.put("startDate", container.getDate().toString());
        } else if (i == dayListSize - 1) {
          json.put("endDate", container.getDate().toString());
        }
        int scheSize = _scheduleList.size();

        for (int j = 0; j < scheSize; j++) {
          // change start
          // 変数スコープを正常化
          // rd = _scheduleList.get(j);
          AjaxScheduleResultData rd = _scheduleList.get(j);
          // change end
          if (rd.isDummy()) {
            continue;
          }
          // 変数スコープを正常化
          // bean = new ScheduleBean();
          ScheduleBean bean = new ScheduleBean();
          // change end
          bean.initField();
          bean.setResultData(rd);
          // change start
          // if (!rd.isPublic() && !rd.isMember()) {
          // bean.setName("非公開");
          // }
          setNondisclosureMask(rd, bean, listData);
          // change end

          bean.setIndex(i);
          // change start
          // ログインユーザーが[秘書]である主催者・参加メンバーの予定も表示対象とする
          // if (!rd.isHidden() || rd.isMember()) {
          if (!rd.isHidden() || rd.isMember() || rd.isLoginuser()) {
            // change end
            scheduleList.add(bean);
          }
        }
      }
      // change end

      json.put("termSchedule", termScheduleList);
      json.put("schedule", scheduleList);
      json.put("holiday", holidayList);
      json.put("date", dateList);
      json.put("dayOfWeek", dayOfWeekList);

      // add start
      // <閲覧不可メンバー一覧>が1件以上存在する場合、エラーメッセージ表示領域へ設定する。
      String referenceErrMessage = listData.getReferenceErrMessage();
      if (!"".equals(referenceErrMessage)) {
        json.put("referenceErr", referenceErrMessage);
      }
      // add end
      // add start 要件No.7 スケジュール画面（週単位）
      // 閲覧可メンバーを設定する。
      List<Number> approvalMemberList = new ArrayList<Number>();
      List<UserFacilityLiteBean> approvalUserList = new ArrayList<UserFacilityLiteBean>();
      approvalMemberList = listData.getApprovalMemberList();
      for (Number approvalMember : approvalMemberList) {
        ALEipUser user = ALEipUtils.getALEipUser(approvalMember.intValue());
        UserFacilityLiteBean member = new UserFacilityLiteBean();
        member.initField();
        member.setUserFacilityId(approvalMember.intValue());
        member.setName(user.getName().getValue());
        member.setAliasName(user.getAliasName().getValue());
        approvalUserList.add(member);
      }
      json.put("approvalMemberList", approvalUserList);
      // add end

      if ((msgList != null) && (msgList.size() > 0)) {
        json.put("errList", msgList);
      }

      return json.toString();
    } catch (ALPermissionException e) {
      ALEipUtils.redirectPermissionError(rundata);
      return null;
    } catch (Exception e) {
      // change start
      // logger.error(e);
      logger.error("予定一覧画面の表示に失敗しました。ログインユーザー:" + loginUserName, e);
      // change end
      // change start 要件No.18 会議案内ファイル添付 DBエラー等の発生時に画面側にエラーを通知
      // return null;
      JSONObject json = new JSONObject();
      msgList.add(0, "FatalError");
      msgList.add("表示内容の更新が異常終了しました。再度更新ボタンを押下して下さい。");
      json.put("errList", msgList);
      return json.toString();
      // change end
    }
  }

  // add start
  /**
   * 非公開のマスク表示を設定します。
   * 
   * @param rd
   *            スケジュール検索結果
   * @param bean
   *            設定先のスケジュールBean
   * @param listData
   *            カレンダー用週間予定検索処理
   */
  private void setNondisclosureMask(AjaxScheduleResultData rd, ScheduleBean bean, AjaxScheduleWeeklyGroupSelectData listData) {
    // 公開フラグ=[非公開]
    // かつ ログインユーザーが参加ユーザーでない
    // かつ

    // ログインユーザーが対象ユーザーに対し[公開]
    // に該当する場合
    // もしくは
    // ログインユーザーが対象ユーザーに対し[秘書]
    // かつ対象ユーザー = 作成ユーザーID
    // に該当する場合

    // 非公開マスク表示にする
    if (!rd.isPublic()
      && !rd.isMember()
      && (listData.isPublicOfScheduleAcl(String.valueOf(rd.getUserId())) || listData.isSecretaryImpossible(String.valueOf(rd.getUserId()), String.valueOf(rd
        .getCreateUserId())))) {
      bean.setName("非公開");
      bean.setPlace("");
      bean.setStatus("");
      bean.setPriority(false);
      bean.setMember(false);
      bean.setLoginuser(false);
      bean.setOwner(false);
      // add start 要件No.18 会議案内ファイル添付
      bean.setWithfiles(false);
      // add end
      // add start 要件No.26 スケジュール個別色換え
      bean.setIndividualColor("");
      // add end

    }
  }

  // add end

  /**
   * カレンダー更新処理（予定のドラッグ＆ドロップで実行）
   * 
   * @param action
   *            呼び出し元アクション
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @return 更新に成功した場合true、失敗した場合false
   */
  public boolean doUpdate(ALAction action, RunData rundata, Context context) {
    // remove start
    // if (!ScheduleUtils.hasRelation(rundata)) {
    // aclPortletFeature =
    // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER;
    // }
    // remove end
    try {
      if (!doCheckSecurity(rundata, context)) {
        return false;
      }
      doCheckAclPermission(rundata, context, ALAccessControlConstants.VALUE_ACL_UPDATE);
      boolean res = (setFormData(rundata, context, msgList) && validate(msgList) && updateFormData(rundata, context, msgList));

      // add start
      if (!res) {
        msgList.add("そのスケジュールは編集することができません。");
      }
      // add end

      return res;

    } catch (ALPermissionException e) {
      msgList.add("PermissionError");
      msgList.add(ALAccessControlConstants.DEF_PERMISSION_ERROR_STR);
      return false;
    } catch (Exception e) {
      logger.error("Exception", e);
      return false;
    }
  }

  /**
   * カレンダーコピー登録処理（予定のCTRLキー+ドラッグ＆ドロップで実行）
   * 
   * @param action
   *            呼び出し元アクション
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @return コピー登録に成功した場合true、失敗した場合false
   */
  public boolean doInsert(ALAction action, RunData rundata, Context context) {
    // remove start
    // if (!ScheduleUtils.hasRelation(rundata)) {
    // aclPortletFeature =
    // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER;
    // }
    // remove end
    try {
      if (!doCheckSecurity(rundata, context)) {
        return false;
      }
      doCheckAclPermission(rundata, context, ALAccessControlConstants.VALUE_ACL_INSERT);
      boolean res = (setFormData(rundata, context, msgList) && validate(msgList) && insertFormData(rundata, context, msgList));

      // add start
      if (!res) {
        msgList.add("そのスケジュールはコピー登録することができません。");
      }
      // add end

      return res;

    } catch (ALPermissionException e) {
      msgList.add("PermissionError");
      msgList.add(ALAccessControlConstants.DEF_PERMISSION_ERROR_STR);
      return false;
    } catch (Exception e) {
      logger.error("Exception", e);
      return false;
    }
  }

  /**
   * リクエストパラメータ取得処理
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @param msgList
   *            エラーメッセージ一覧
   */
  public void loadParameters(RunData rundata, Context context, List<String> msgList) {
    ALDateTimeField dummy = new ALDateTimeField("yyyy-MM-dd-HH-mm");
    dummy.setNotNull(true);
    if (ALEipUtils.isMatch(rundata, context)) {
      if (rundata.getParameters().containsKey("start_date") && rundata.getParameters().containsKey("end_date")) {
        start_date = rundata.getParameters().getString("start_date");
        dummy.setValue(start_date);
        if (!dummy.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, "start_date");
          ALEipUtils.removeTemp(rundata, context, "end_date");
          msgList.add("starDate_irregular");
          return;
        }
        end_date = rundata.getParameters().getString("end_date");
        dummy.setValue(end_date);
        if (!dummy.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, "end_date");
          ALEipUtils.removeTemp(rundata, context, "end_date");
          msgList.add("endDate_irregular");
          return;
        }
        if (rundata.getParameters().containsKey("view_date")) {
          view_date = rundata.getParameters().getString("view_date");
          dummy.setValue(view_date);
          if (!dummy.validate(new ArrayList<String>())) {
            ALEipUtils.removeTemp(rundata, context, "view_date");
            ALEipUtils.removeTemp(rundata, context, "view_date");
            msgList.add("viewDate_irregular");
            return;
          }
        }
        if (rundata.getParameters().containsKey(ALEipConstants.ENTITY_ID)) {
          entityId = rundata.getParameters().getInt(ALEipConstants.ENTITY_ID);
        } else {
          msgList.add("entityId_missing");
          return;
        }
        // remove start
        // 不要になったため削除
        // if (rundata.getParameters().containsKey("ign_dup_f")) {
        // ignore_duplicate_facility =
        // rundata.getParameters().getBoolean("ign_dup_f", false);
        // }
        // remove end
        // add start
      } else if (rundata.getParameters().containsKey("straddle_mode")) {
        // 日またぎ更新モードの場合
        straddle_mode = rundata.getParameters().getString("straddle_mode");
        if (STRADDLE_MODE_CHANGE_DAY.equals(straddle_mode)) {
          // 日付更新の場合
          straddle_change_days = rundata.getParameters().getInt("days");
        } else if (STRADDLE_MODE_CHANGE_START_TIME.equals(straddle_mode)) {
          // 開始時刻更新の場合
          straddle_start_time = rundata.getParameters().getString("straddle_start_time");
        } else if (STRADDLE_MODE_CHANGE_END_TIME.equals(straddle_mode)) {
          // 終了時刻更新の場合
          straddle_end_time = rundata.getParameters().getString("straddle_end_time");
        }
        // エンティティID取得
        entityId = rundata.getParameters().getInt(ALEipConstants.ENTITY_ID);
        // add end
      } else {
        // null
        isViewList = true;
      }
    } else {
      msgList.add("not own portlet");
      return;
    }
  }

  /**
   * 入力フォーム値やセッション情報を取得し、フィールドへ設定します。
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @param msgList
   *            エラーメッセージ一覧(未使用)
   * @return フィールドへ値の設定に成功した場合true、失敗した場合false
   * @throws ALPageNotFoundException
   *             画面表示が不可能な問題が発生した場合
   * @throws ALDBErrorException
   *             DBエラーが発生した場合
   */
  public boolean setFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    try {
      userId = ALEipUtils.getUserId(rundata);
      schedule = ScheduleUtils.getEipTSchedule(rundata, entityId, false, userId);
      // remove start
      // 不要になったため削除
      // isEdit = "T".equals(schedule.getEditFlag());
      // remove end
      // if (rundata.getParameters().containsKey("is_span")) {
      // is_span = rundata.getParameters().getBoolean("is_span");
      // }
      if (rundata.getParameters().containsKey("edit_repeat_flag")) {
        edit_repeat_flag = rundata.getParameters().getInt("edit_repeat_flag");
      } else {
        // msgList.add("edit_repeat_flag none");
      }
      // change start
      // ユーザー表示順でソート
      // scheduleMaps = ScheduleUtils.getEipTScheduleMaps(schedule);
      scheduleMaps = ScheduleUtils.getEipTScheduleMapsByUserInfoSort(schedule.getScheduleId());
      // 未分類共有カテゴリを取得
      commonCategory = CommonCategoryUtils.getEipTCommonCategory(Long.valueOf(1));
      // change end

      int listSize = scheduleMaps.size();
      for (int i = 0; i < listSize; i++) {
        EipTScheduleMap map = scheduleMaps.get(i);
        if (ScheduleUtils.SCHEDULEMAP_TYPE_USER.equals(map.getType())) {
          int targetUserId = map.getUserId().intValue();
          // if (userId == targetUserId) {
          // isMember = true;
          // }
          // change start
          // 必須/任意でメンバーを分割
          // memberList.add(ALEipUtils.getALEipUser(targetUserId));
          ALEipUser user = ALEipUtils.getALEipUser(targetUserId);
          if (ScheduleConst.SCHEDULEMAP_REQUIRED_T.equals(map.getRequired())) {
            reqMemberList.add(user);
          } else {
            subMemberList.add(user);
          }
          memberList.add(user);
          // change end
        }
        // else
        // if(ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY.equals(map.getType())){
        // }
      }
      ownerId = schedule.getOwnerId().intValue();
      // add start
      if (null != straddle_mode) {
        // 日またぎ更新モードの場合
        if (STRADDLE_MODE_CHANGE_DAY.equals(straddle_mode)) {
          // 日付更新の場合
          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
          Calendar workCal = Calendar.getInstance();
          // 開始日時の設定
          workCal.setTime(schedule.getStartDate());
          workCal.add(Calendar.DAY_OF_MONTH, straddle_change_days);
          startDate.setValue(df.format(workCal.getTime()));
          workCal.clear();
          // 終了日時の設定
          workCal.setTime(schedule.getEndDate());
          workCal.add(Calendar.DAY_OF_MONTH, straddle_change_days);
          endDate.setValue(df.format(workCal.getTime()));
        } else if (STRADDLE_MODE_CHANGE_START_TIME.equals(straddle_mode)) {
          // 開始時刻更新の場合
          startDate.setValue(straddle_start_time);
          endDate.setValue(schedule.getEndDate());
        } else if (STRADDLE_MODE_CHANGE_END_TIME.equals(straddle_mode)) {
          // 終了時刻更新の場合
          startDate.setValue(schedule.getStartDate());
          endDate.setValue(straddle_end_time);
        }
      } else {
        // add end
        startDate.setValue(start_date);
        endDate.setValue(end_date);
        // add start
      }
      // add end
      viewDate.setValue(view_date);
    } catch (Exception e) {
      logger.error("Exception", e);
      return false;
    }
    return true;
  }

  /**
   * 入力チェック。このメソッドの実行前の処理結果を元に入力エラーか判定します。
   * 
   * @param msgList
   *            エラーメッセージ一覧
   * @return エラーが無い場合true、入力エラーの場合false
   */
  public boolean validate(List<String> msgList) throws ALDBErrorException, ALPageNotFoundException {
    return !(msgList.size() > 0);
  }

  // add start
  /**
   * スケジュールを旧レコードから新レコードへコピーします。<br/> 作成日と更新日は現在日付を設定します。
   * 
   * @param newSc
   *            新スケジュール
   * @param oldSc
   *            旧スケジュール
   * @param ownerUserId
   *            新スケジュールのオーナーのユーザーID
   * @param createUserId
   *            新スケジュールの作成者のユーザーID
   * @param updateUserId
   *            新スケジュールの更新者のユーザーID
   */
  private void copySchedule(EipTSchedule newSc, EipTSchedule oldSc, Integer ownerUserId, Integer createUserId, Integer updateUserId) {
    Date now = new Date();

    // 親ID
    newSc.setParentId(oldSc.getParentId());

    // ユーザID（オーナーID）
    newSc.setOwnerId(oldSc.getOwnerId());

    // 繰り返しパターン
    newSc.setRepeatPattern(oldSc.getRepeatPattern());

    // 開始時間
    newSc.setStartDate(oldSc.getStartDate());

    // 終了時間
    newSc.setEndDate(oldSc.getEndDate());

    // スケジュール名
    newSc.setName(oldSc.getName());

    // 場所
    newSc.setPlace(oldSc.getPlace());

    // 内容
    newSc.setNote(oldSc.getNote());

    // 公開フラグ
    newSc.setPublicFlag(oldSc.getPublicFlag());

    // 編集フラグ：不可固定
    newSc.setEditFlag("F");

    // 作成者：ログインユーザー
    newSc.setCreateUserId(userId);

    // 更新者：ログインユーザー
    newSc.setUpdateUserId(userId);

    // 作成日時
    newSc.setCreateDate(now);

    // 更新日時
    newSc.setUpdateDate(now);

    // add start 要件No.9 スケジュール表示 （仮の予定、確定した予定）
    newSc.setTemporaryFlag(oldSc.getTemporaryFlag());
    // add end
  }

  /**
   * スケジュールマップを旧レコードから新レコードへコピーします。<br/> 回答状態は初期化します。
   * 
   * @param newScMap
   *            新スケジュールマップ
   * @param oldScMap
   *            旧スケジュールマップ
   * @param sc
   *            新スケジュールマップの親にあたるスケジュール
   */
  private void copyScheduleMap(EipTScheduleMap newScMap, EipTScheduleMap oldScMap, EipTSchedule sc) {
    newScMap.setEipTSchedule(sc);
    newScMap.setUserId(oldScMap.getUserId());

    if (oldScMap.getUserId().equals(sc.getOwnerId())) {
      // 新スケジュールの主催者の状態を[所有者]にする
      newScMap.setStatus(ScheduleConst.SCHEDULEMAP_STATUS_OWNER);
    } else {
      // 主催者以外は未回答固定（当処理は日時変更が前提であるため）
      newScMap.setStatus(ScheduleConst.SCHEDULEMAP_STATUS_NON_RES);
    }

    // 種別
    newScMap.setType(oldScMap.getType());

    // 共有カテゴリは未分類固定
    newScMap.setCommonCategoryId(1);
    newScMap.setEipTCommonCategory(commonCategory);

    // 必須フラグ：引き継ぎ
    newScMap.setRequired(oldScMap.getRequired());

    // 重要フラグ：引き継ぎ
    newScMap.setPriority(oldScMap.getPriority());

    // ダミー未回答フラグ：通常
    newScMap.setDummyNonResponse(ScheduleConst.SCHEDULEMAP_DUMMY_NON_RES_F);

    // add start 要件No.26 スケジュール個別色換え
    newScMap.setIndividualColor(oldScMap.getIndividualColor());
    // add end
  }

  // add end

  /**
   * カレンダー更新詳細処理
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @param msgList
   *            エラーメッセージ一覧
   * @return 更新に成功した場合true、失敗した場合false
   * @throws ALDBErrorException
   *             DBエラーが発生した場合
   */
  public boolean updateFormData(RunData rundata, Context context, List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {

    boolean res = false;

    // add start
    // 更新結果スケジュール
    EipTSchedule tempSc = null;

    // add start 要件No.18 会議案内ファイル添付
    Map<String, String> newFilesMap = new HashMap<String, String>();
    // add end

    try {
      // add end
      // remove start
      // setFormDataでスケジュールの主催者に対する権限チェックを実行済みであるため、ここでの権限チェックは廃止
      // boolean authorityForOtherSchedule =
      // ScheduleUtils.hasAuthorityForOtherSchedule(
      // rundata,
      // ALAccessControlConstants.VALUE_ACL_UPDATE);
      // if (isEdit
      // || userId == ownerId
      // || aclPortletFeature ==
      // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER
      // || authorityForOtherSchedule) {
      // remove end

      if (edit_repeat_flag == 0) {
        /** 繰り返しでないスケジュールをコピーしようとした場合 */
        /** スケジュールに変更が加わっていない場合は、更新処理をスキップする */
        if (schedule.getStartDate().equals(startDate.getValue()) && schedule.getEndDate().equals(endDate.getValue())) {
          return true;
        }

        schedule.setStartDate(startDate.getValue());
        schedule.setEndDate(endDate.getValue());
        Date now = new Date();
        schedule.setUpdateDate(now);
        schedule.setUpdateUserId(userId);

        // add start
        // 回答状態の更新
        List<EipTScheduleMap> scMaps = schedule.getEipTScheduleMaps();
        for (EipTScheduleMap scMap : scMaps) {
          if (!ScheduleConst.SCHEDULEMAP_STATUS_OWNER.equals(scMap.getStatus()) && !ScheduleConst.SCHEDULEMAP_STATUS_DUMMY.equals(scMap.getStatus())) {
            // 主催者以外は未回答固定（当処理は日時変更が前提であるため）
            scMap.setStatus(ScheduleConst.SCHEDULEMAP_STATUS_NON_RES);
          }
          // ダミー未回答フラグ：通常
          scMap.setDummyNonResponse(ScheduleConst.SCHEDULEMAP_DUMMY_NON_RES_F);
        }
        // add end

        // remove start
        // /* 施設重複判定 */
        // {
        // int listSize = scheduleMaps.size();
        // List<Integer> facilityIdList = new ArrayList<Integer>();
        //
        // for (int i = 0; i < listSize; i++) {
        // EipTScheduleMap map = scheduleMaps.get(i);
        // if (ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY.equals(map.getType())) {
        // facilityIdList.add(map.getUserId());
        // }
        // }
        // if (!ignore_duplicate_facility) {
        // if (facilityIdList.size() > 0) {
        // if (ScheduleUtils.isDuplicateFacilitySchedule(
        // schedule,
        // facilityIdList,
        // null,
        // null)) {
        // msgList.add("duplicate_facility");
        // Database.rollback();
        // return false;
        // }
        // }
        // }
        // }
        // remove end

        Database.commit();
        res = true;
        // add start
        // メール送信用に更新結果を格納
        tempSc = schedule;
        // add end
        // イベントログに保存
        sendEventLog(rundata, context);
        /* メンバー全員に新着ポートレット登録 */
        sendWhatsNew(schedule, false);

        // remove start
        // メール送信処理を繰り返し予定/繰り返し以外の予定で統一
        // try {
        // // メール送信
        // int msgType =
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE);
        // if (msgType > 0) {
        // // パソコンへメールを送信
        // List<ALEipUserAddr> destMemberList =
        // ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils
        // .getUserId(rundata), false);
        // String subject = "[" + ALOrgUtilsService.getAlias() + "]スケジュール";
        //
        // List<ALAdminMailMessage> messageList =
        // new ArrayList<ALAdminMailMessage>();
        // for (ALEipUserAddr destMember : destMemberList) {
        // ALAdminMailMessage message = new ALAdminMailMessage(destMember);
        // message.setPcSubject(subject);
        // message.setCellularSubject(subject);
        // message.setPcBody(ScheduleUtils.createMsgForPc(
        // rundata,
        // schedule,
        // memberList));
        // message.setCellularBody(ScheduleUtils.createMsgForCellPhone(
        // rundata,
        // schedule,
        // memberList,
        // destMember.getUserId()));
        // messageList.add(message);
        // }
        //
        // ALMailService.sendAdminMail(new ALAdminMailContext(orgId, ALEipUtils
        // .getUserId(rundata), messageList, ALMailUtils
        // .getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE)));
        //
        // }
        // } catch (Exception ex) {
        // msgList.add("メールを送信できませんでした。");
        // logger.error("Exception", ex);
        // return false;
        // }
        // remove end

      } else {
        /** 繰り返しスケジュールを変更しようとした場合 */
        /**
         * 以下の場合は変更が加わっていないとみなし、更新をスキップする。
         * 保存されている開始時刻と終了時刻がendDateとstartDateと一致。 viewDateの日付がstartDateの物と一致。
         */
        Calendar saved_startdate = Calendar.getInstance();
        saved_startdate.setTime(schedule.getStartDate());
        Calendar saved_enddate = Calendar.getInstance();
        saved_enddate.setTime(schedule.getEndDate());
        if (Integer.valueOf(startDate.getHour()) == saved_startdate.get(Calendar.HOUR_OF_DAY)
          && Integer.valueOf(startDate.getMinute()) == saved_startdate.get(Calendar.MINUTE)
          && Integer.valueOf(endDate.getHour()) == saved_enddate.get(Calendar.HOUR_OF_DAY)
          && Integer.valueOf(endDate.getMinute()) == saved_enddate.get(Calendar.MINUTE)
          && viewDate.getMonth().equals(startDate.getMonth())
          && viewDate.getDay().equals(startDate.getDay())
          && viewDate.getYear().equals(startDate.getYear())) {
          return true;
        }

        // if(schedule.getStartDate())

        EipTSchedule newSchedule = Database.create(EipTSchedule.class);

        // add start
        // 共通のスケジュールコピー処理を実行
        copySchedule(newSchedule, schedule, ownerId, userId, userId);
        // add end

        // 繰り返しの親スケジュール ID
        newSchedule.setParentId(schedule.getScheduleId());

        // remove start
        // // 予定
        // newSchedule.setName(schedule.getName());
        // // 場所
        // newSchedule.setPlace(schedule.getPlace());
        // // 内容
        // newSchedule.setNote(schedule.getNote());
        // // 公開フラグ
        // newSchedule.setPublicFlag(schedule.getPublicFlag());
        // // 共有メンバーによる編集／削除フラグ
        // newSchedule.setEditFlag(schedule.getEditFlag());
        //
        // // オーナーID
        // // newSchedule.setOwnerId(Integer.valueOf(userId));
        // newSchedule.setOwnerId(Integer.valueOf(ownerId));
        // // 作成日
        // Date now = new Date();
        // newSchedule.setCreateDate(now);
        // newSchedule.setCreateUserId(Integer.valueOf(ownerId));
        // // 更新日
        // newSchedule.setUpdateDate(now);
        // newSchedule.setUpdateUserId(Integer.valueOf(userId));
        // remove end

        // 終了時間
        newSchedule.setEndDate(endDate.getValue());
        // 繰り返しパターン：単発固定
        newSchedule.setRepeatPattern("N");
        // 開始時間
        newSchedule.setStartDate(startDate.getValue());

        // 2007.3.28 ToDo連携

        int listSize = scheduleMaps.size();
        List<Integer> memberIdList = new ArrayList<Integer>();
        List<Integer> facilityIdList = new ArrayList<Integer>();
        // List newMaps = new ArrayList();

        for (int i = 0; i < listSize; i++) {
          EipTScheduleMap newMap = Database.create(EipTScheduleMap.class);
          EipTScheduleMap map = scheduleMaps.get(i);

          // change start
          // newMap.setEipTSchedule(newSchedule);
          // newMap.setUserId(map.getUserId());
          //
          // if (map.getUserId() == ownerId) {
          // // if (map.getUserId() == userId) {
          // newMap.setStatus("O");
          // } else {
          // EipTScheduleMap tmpMap =
          // getScheduleMap(
          // scheduleMaps,
          // map.getUserId().intValue(),
          // ScheduleUtils.SCHEDULEMAP_TYPE_USER);
          // if (tmpMap != null) {
          // newMap.setStatus(tmpMap.getStatus());
          // } else {
          // newMap.setStatus("T");
          // }
          // }
          // newMap.setType(map.getType());
          //
          // newMap.setCommonCategoryId(map.getCommonCategoryId());
          // newMap.setEipTCommonCategory(map.getEipTCommonCategory());
          // 共通のスケジュールマップコピー処理を実行
          copyScheduleMap(newMap, map, newSchedule);
          // change end

          if (ScheduleUtils.SCHEDULEMAP_TYPE_USER.equals(map.getType())) {
            memberIdList.add(map.getUserId().intValue());
          } else {
            facilityIdList.add(map.getUserId().intValue());
          }
        }

        // remove start
        // 施設判定廃止
        /* 施設重複判定 */
        // if (!ignore_duplicate_facility) {
        // if (facilityIdList.size() > 0) {
        // if (ScheduleUtils.isDuplicateFacilitySchedule(
        // newSchedule,
        // facilityIdList,
        // schedule.getScheduleId(),
        // viewDate.getValue())) {
        // msgList.add("duplicate_facility");
        // Database.rollback();
        // return false;
        // }
        // }
        // }
        // remove end
        // add start 要件No.18 会議案内ファイル添付
        // 添付ファイルをコピー
        ScheduleUtils.copyAvzTScheduleFile(newSchedule, schedule, newFilesMap);
        // 添付ファイルをコピーする(ファイル)。
        ScheduleUtils.copyFiles(ownerId, newFilesMap);
        // add end

        if (viewDate != null) {
          ScheduleUtils.insertDummySchedule(schedule, userId, viewDate.getValue(), viewDate.getValue(), memberIdList, facilityIdList);
        }

        Database.commit();
        res = true;
        // add start
        // メール送信用に更新結果を格納
        tempSc = newSchedule;
        // add end

        // イベントログに保存
        sendEventLog(rundata, context);
        /* メンバー全員に新着ポートレット登録 */
        sendWhatsNew(newSchedule, false);

        // remove start
        // メール送信処理を繰り返し予定/繰り返し以外の予定で統一
        // try {
        // // メール送信
        // int msgType =
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE);
        // if (msgType > 0) {
        // // パソコンへメールを送信
        // List<ALEipUserAddr> destMemberList =
        // ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils
        // .getUserId(rundata), false);
        // String subject = "[" + ALOrgUtilsService.getAlias() + "]スケジュール";
        //
        // List<ALAdminMailMessage> messageList =
        // new ArrayList<ALAdminMailMessage>();
        // for (ALEipUserAddr destMember : destMemberList) {
        // ALAdminMailMessage message = new ALAdminMailMessage(destMember);
        // message.setPcSubject(subject);
        // message.setCellularSubject(subject);
        // // change start
        // // message.setPcBody(ScheduleUtils.createMsgForPc(
        // // rundata,
        // // newSchedule,
        // // memberList));
        // message.setPcBody(ScheduleUtils.createMsgForPc(
        // ALEipUtils.getUserId(rundata),
        // newSchedule,
        // memberList,
        // memberList,
        // "変更しました。",
        // rundata));
        // // change end
        // message.setCellularBody(ScheduleUtils.createMsgForCellPhone(
        // rundata,
        // newSchedule,
        // memberList,
        // destMember.getUserId()));
        // }
        //
        // ALMailService.sendAdminMail(new ALAdminMailContext(orgId, ALEipUtils
        // .getUserId(rundata), messageList, ALMailUtils
        // .getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE)));
        //
        // }
        //
        // } catch (Exception ex) {
        // msgList.add("メールを送信できませんでした。");
        // logger.error("Exception", ex);
        // return false;
        // }
        // remove end

        // remove start
        // } else {
        // msgList.add("そのスケジュールは編集することができません");
        // res = false;
        // remove end
      }
      // add start
    } catch (Exception e) {
      // add start 要件No.18 会議案内ファイル添付
      // ストアディレクトリに作成したファイルを削除する。
      ScheduleUtils.rollbackFiles(ownerId, newFilesMap);
      // add end
      Database.rollback();
      logger.error("予定の更新に失敗しました。ログインユーザー:" + loginUserName + "/スケジュールID:" + schedule.getScheduleId(), e);
      return false;
    }
    // -----------------
    // メール送信処理
    // -----------------

    // add start 受入障害対応No.197対応
    // memberListの各ユーザーの「状態」を判定し、削除、辞退のユーザーについては
    // memberListから除外
    List<EipTScheduleMap> smList = ScheduleUtils.getEipTScheduleMapsByUserInfoSort(schedule.getScheduleId());
    memberList = ScheduleUtils.checkMemberList(memberList, smList);
    // add end

    // メール送信先
    // 参加メンバー（ログインユーザーを除く）を送信先にする
    List<ALEipUserAddr> sendToUserList = ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils.getUserId(rundata), false);
    // メール送信実行
    if (!ScheduleUtils.sendScheduleMail(sendToUserList, tempSc.getOwnerId(), tempSc, reqMemberList, subMemberList,
    // change start 要件No.1 スケジュール案内受信
      // "予定変更",
      ScheduleUtils.MEETING_UPDATE,
      "変更しました。",
      rundata,
      // add start 要件No.1 スケジュール案内受信
      "",
      ScheduleUtils.CREATE_MSG_MODE_REQ
    // add end
      )) {
      msgList.add("メールを送信できませんでした。");
      return false;
    }

    if (schedule.getOwnerId().intValue() != userId) {

      // 秘書設定元へ代理操作の通知を行なう。

      // メール送信先(ALEipUser)秘書設定元送信用
      List<ALEipUser> sendToEipClientUserList = new ArrayList<ALEipUser>(0);

      sendToEipClientUserList.add(ALEipUtils.getALEipUser(schedule.getOwnerId().intValue()));

      List<ALEipUserAddr> sendToClientUserList = ALMailUtils.getALEipUserAddrs(sendToEipClientUserList, userId, false);

      if (!ScheduleUtils.sendScheduleMail(
        sendToClientUserList,
        userId,
        schedule.getOwnerId(),
        schedule,
        reqMemberList,
        subMemberList,
        ScheduleUtils.SUBSTITUTE_UPDATE,
        "変更しました。",
        rundata,
        // add start 要件No.1 スケジュール案内受信
        "",
        ScheduleUtils.CREATE_MSG_MODE_SUBREQ
      // add end
        )) {
        msgList.add("mailErrMsg=メールを送信できませんでした。entityId=" + schedule.getScheduleId());
        return false;
      }
    }
    // add end
    return res;
  }

  /**
   * カレンダーコピー登録詳細処理
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @param msgList
   *            エラーメッセージ一覧
   * @return コピー登録に成功した場合true、失敗した場合false
   * @throws ALDBErrorException
   *             DBエラーが発生した場合
   */
  protected boolean insertFormData(RunData rundata, Context context, List<String> msgList) throws ALDBErrorException {
    boolean res = false;
    // add start
    // 更新結果スケジュール
    EipTSchedule tempSc = null;
    // add start 要件No.18 会議案内ファイル添付
    Map<String, String> newFilesMap = new HashMap<String, String>();
    // add end
    try {
      // add end
      // remove start
      // setFormDataでスケジュールの主催者に対する権限チェックを実行済みであるため、ここでの権限チェックは廃止
      // boolean authorityForOtherSchedule =
      // ScheduleUtils.hasAuthorityForOtherSchedule(
      // rundata,
      // ALAccessControlConstants.VALUE_ACL_INSERT);
      // if (isEdit
      // || userId == ownerId
      // || aclPortletFeature ==
      // ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER
      // || authorityForOtherSchedule) {
      // remove end

      // 繰り返しでないスケジュールを変更しようとした場合
      if (edit_repeat_flag == 0) {

        // スケジュールをコピーする
        EipTSchedule newSchedule = Database.create(EipTSchedule.class);

        // add start
        // 共通のスケジュールコピー処理を実行
        copySchedule(newSchedule, schedule, ownerId, userId, userId);
        // add end

        // 開始時間
        newSchedule.setStartDate(startDate.getValue());
        // 終了時間
        newSchedule.setEndDate(endDate.getValue());

        // remove start
        // Date now = new Date();
        //
        // newSchedule.setCreateDate(now);
        //
        // newSchedule.setUpdateDate(now);
        //
        // newSchedule.setUpdateUserId(userId);
        //
        // newSchedule.setName(schedule.getName());
        //
        // newSchedule.setNote(schedule.getNote());
        //
        // newSchedule.setPlace(schedule.getPlace());
        //
        // newSchedule.setEditFlag(schedule.getEditFlag());
        //
        // newSchedule.setPublicFlag(schedule.getPublicFlag());
        //
        // newSchedule.setRepeatPattern(schedule.getRepeatPattern());
        //
        // newSchedule.setCreateUserId(schedule.getCreateUserId());
        //
        // newSchedule.setOwnerId(schedule.getOwnerId());
        //
        // newSchedule.setParentId(schedule.getParentId());
        // remove end

        // remove start
        // // 施設判定廃止に伴い不要のため、削除
        // List<EipTScheduleMap> newScheduleMaps =
        // new ArrayList<EipTScheduleMap>();
        // remove end

        for (EipTScheduleMap scheduleMap : scheduleMaps) {
          EipTScheduleMap newScheduleMap = Database.create(EipTScheduleMap.class);
          // change start
          // newScheduleMap.setEipTSchedule(newSchedule);
          //
          // newScheduleMap.setEipTCommonCategory(scheduleMap
          // .getEipTCommonCategory());
          //
          // newScheduleMap.setStatus(scheduleMap.getStatus());
          //
          // newScheduleMap.setType(scheduleMap.getType());
          //
          // newScheduleMap.setUserId(scheduleMap.getUserId());
          //
          // newScheduleMaps.add(newScheduleMap);
          // 共通のスケジュールマップコピー処理を実行
          copyScheduleMap(newScheduleMap, scheduleMap, newSchedule);
          // 重要フラグを初期化する
          newScheduleMap.setPriority(ScheduleConst.SCHEDULEMAP_PRIORITY_F);
          // change end
          // add start 要件No.26 スケジュール個別色換え
          newScheduleMap.setIndividualColor("");
          // add end
        }

        // remove start
        // 施設判定廃止
        // /* 施設重複判定 */
        // List<Integer> facilityIdList = new ArrayList<Integer>();
        // for (EipTScheduleMap newScheduleMap : newScheduleMaps) {
        // if (ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY.equals(newScheduleMap
        // .getType())) {
        // facilityIdList.add(newScheduleMap.getUserId());
        // }
        // }
        //
        // if (!ignore_duplicate_facility) {
        // if (facilityIdList.size() > 0) {
        // if (ScheduleUtils.isDuplicateFacilitySchedule(
        // newSchedule,
        // facilityIdList,
        // null,
        // null)) {
        // msgList.add("duplicate_facility");
        // Database.rollback();
        // return false;
        // }
        // }
        // }
        // remove end

        // add start 要件No.18 会議案内ファイル添付
        // 添付ファイルをコピーする(DB)。
        ScheduleUtils.copyAvzTScheduleFile(newSchedule, schedule, newFilesMap);
        // add end
        // add start 要件No.18 会議案内ファイル添付
        // 添付ファイルをコピーする(ファイル)。
        ScheduleUtils.copyFiles(ownerId, newFilesMap);
        // add end

        Database.commit();
        res = true;
        // add start
        // メール送信用に更新結果を格納
        tempSc = newSchedule;
        // add end
        // イベントログに保存
        sendEventLog(rundata, context);
        /* メンバー全員に新着ポートレット登録 */
        sendWhatsNew(newSchedule, true);

        // remove start
        // メール送信処理を繰り返し予定/繰り返し以外の予定で統一
        // try {
        // // メール送信
        // int msgType =
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE);
        // if (msgType > 0) {
        // // パソコンへメールを送信
        // List<ALEipUserAddr> destMemberList =
        // ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils
        // .getUserId(rundata), false);
        // String subject = "[" + ALOrgUtilsService.getAlias() + "]スケジュール";
        //
        // List<ALAdminMailMessage> messageList =
        // new ArrayList<ALAdminMailMessage>();
        // for (ALEipUserAddr destMember : destMemberList) {
        // ALAdminMailMessage message = new ALAdminMailMessage(destMember);
        // message.setPcSubject(subject);
        // message.setCellularSubject(subject);
        // // change start
        // // message.setPcBody(ScheduleUtils.createMsgForPc(
        // // rundata,
        // // schedule,
        // // memberList));
        // message.setPcBody(ScheduleUtils.createMsgForPc(
        // ALEipUtils.getUserId(rundata),
        // schedule,
        // memberList,
        // memberList,
        // "追加しました。",
        // rundata));
        // // change end
        // message.setCellularBody(ScheduleUtils.createMsgForCellPhone(
        // rundata,
        // schedule,
        // memberList,
        // destMember.getUserId()));
        // messageList.add(message);
        // }
        //
        // ALMailService.sendAdminMail(new ALAdminMailContext(
        // orgId,
        // ALEipUtils.getUserId(rundata),
        // messageList,
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE)));
        //
        // }
        // } catch (Exception ex) {
        // msgList.add("メールを送信できませんでした。");
        // logger.error("Exception", ex);
        // return false;
        // }
        // remove end

      } else {
        /** 繰り返しスケジュールを変更しようとした場合 */
        /**
         * 以下の場合は変更が加わっていないとみなし、更新をスキップする。
         * 保存されている開始時刻と終了時刻がendDateとstartDateと一致。 viewDateの日付がstartDateの物と一致。
         */
        Calendar saved_startdate = Calendar.getInstance();
        saved_startdate.setTime(schedule.getStartDate());
        Calendar saved_enddate = Calendar.getInstance();
        saved_enddate.setTime(schedule.getEndDate());
        if (Integer.valueOf(startDate.getHour()) == saved_startdate.get(Calendar.HOUR_OF_DAY)
          && Integer.valueOf(startDate.getMinute()) == saved_startdate.get(Calendar.MINUTE)
          && Integer.valueOf(endDate.getHour()) == saved_enddate.get(Calendar.HOUR_OF_DAY)
          && Integer.valueOf(endDate.getMinute()) == saved_enddate.get(Calendar.MINUTE)
          && viewDate.getMonth().equals(startDate.getMonth())
          && viewDate.getDay().equals(startDate.getDay())
          && viewDate.getYear().equals(startDate.getYear())) {
          return true;
        }

        // if(schedule.getStartDate())

        // スケジュールをコピーする
        EipTSchedule newSchedule = Database.create(EipTSchedule.class);

        // add start
        // 共通のスケジュールコピー処理を実行
        copySchedule(newSchedule, schedule, ownerId, userId, userId);
        // 繰り返しパターン：単発に変換
        newSchedule.setRepeatPattern(ScheduleConst.SCHEDULE_PATTERN_ONEDAY);
        // add end

        // 開始時間
        newSchedule.setStartDate(startDate.getValue());
        // 終了時間
        newSchedule.setEndDate(endDate.getValue());

        // remove start
        // Date now = new Date();
        //
        // newSchedule.setCreateDate(now);
        //
        // newSchedule.setUpdateDate(now);
        //
        // newSchedule.setUpdateUserId(userId);
        //
        // newSchedule.setParentId(schedule.getScheduleId());
        //
        // newSchedule.setName(schedule.getName());
        //
        // newSchedule.setNote(schedule.getNote());
        //
        // newSchedule.setPlace(schedule.getPlace());
        //
        // newSchedule.setEditFlag(schedule.getEditFlag());
        //
        // newSchedule.setPublicFlag(schedule.getPublicFlag());
        //
        // newSchedule.setRepeatPattern(schedule.getRepeatPattern());
        //
        // newSchedule.setCreateUserId(schedule.getCreateUserId());
        //
        // newSchedule.setOwnerId(schedule.getOwnerId());
        //
        // newSchedule.setParentId(schedule.getParentId());
        // remove end

        // remove start
        // 施設判定廃止に関連し不要になったため削除
        // 2007.3.28 ToDo連携
        // List<Integer> memberIdList = new ArrayList<Integer>();
        // List<Integer> facilityIdList = new ArrayList<Integer>();
        // remove end

        for (EipTScheduleMap map : scheduleMaps) {
          EipTScheduleMap newMap = Database.create(EipTScheduleMap.class);
          // change start
          // newMap.setEipTSchedule(newSchedule);
          // newMap.setUserId(map.getUserId());
          //
          // if (map.getUserId() == ownerId) {
          // // if (map.getUserId() == userId) {
          // newMap.setStatus("O");
          // } else {
          // EipTScheduleMap tmpMap =
          // getScheduleMap(
          // scheduleMaps,
          // map.getUserId().intValue(),
          // ScheduleUtils.SCHEDULEMAP_TYPE_USER);
          // if (tmpMap != null) {
          // newMap.setStatus(tmpMap.getStatus());
          // } else {
          // newMap.setStatus("T");
          // }
          // }
          // newMap.setType(map.getType());
          // newMap.setCommonCategoryId(map.getCommonCategoryId());
          // newMap.setEipTCommonCategory(map.getEipTCommonCategory());
          // 共通のスケジュールマップコピー処理を実行
          copyScheduleMap(newMap, map, newSchedule);
          // 重要フラグを初期化する
          newMap.setPriority(ScheduleConst.SCHEDULEMAP_PRIORITY_F);
          // change end
          // add start 要件No.26 スケジュール個別色換え
          newMap.setIndividualColor("");
          // add end

          // remove start
          // 施設判定廃止に関連し不要になったため削除
          // if (ScheduleUtils.SCHEDULEMAP_TYPE_USER.equals(map.getType())) {
          // memberIdList.add(map.getUserId().intValue());
          // } else {
          // facilityIdList.add(map.getUserId().intValue());
          // }
          // remove end
        }

        // remove start
        // 施設判定廃止
        // // 施設重複判定
        // if (!ignore_duplicate_facility) {
        // if (facilityIdList.size() > 0) {
        // if (ScheduleUtils.isDuplicateFacilitySchedule(
        // newSchedule,
        // facilityIdList,
        // schedule.getScheduleId(),
        // viewDate.getValue())) {
        // msgList.add("duplicate_facility");
        // Database.rollback();
        // return false;
        // }
        // }
        // }
        // remove end

        // add start 要件No.18 会議案内ファイル添付
        // 添付ファイルをコピーする(DB)。
        ScheduleUtils.copyAvzTScheduleFile(newSchedule, schedule, newFilesMap);
        // add end
        // add start 要件No.18 会議案内ファイル添付
        // 添付ファイルをコピーする(ファイル)。
        ScheduleUtils.copyFiles(ownerId, newFilesMap);
        // add end

        Database.commit();
        res = true;
        // add start
        // メール送信用に更新結果を格納
        tempSc = newSchedule;
        // add end

        // イベントログに保存
        sendEventLog(rundata, context);
        // メンバー全員に新着ポートレット登録
        sendWhatsNew(newSchedule, true);

        // remove start
        // メール送信処理を繰り返し予定/繰り返し以外の予定で統一
        // try {
        // // メール送信
        // int msgType =
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE);
        // if (msgType > 0) {
        // // パソコンへメールを送信
        // List<ALEipUserAddr> destMemberList =
        // ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils
        // .getUserId(rundata), false);
        // String subject = "[" + ALOrgUtilsService.getAlias() + "]スケジュール";
        //
        // List<ALAdminMailMessage> messageList =
        // new ArrayList<ALAdminMailMessage>();
        // for (ALEipUserAddr destMember : destMemberList) {
        // ALAdminMailMessage message = new ALAdminMailMessage(destMember);
        // message.setPcSubject(subject);
        // message.setCellularSubject(subject);
        // // change start
        // // message.setPcBody(ScheduleUtils.createMsgForPc(
        // // rundata,
        // // newSchedule,
        // // memberList));
        // message.setPcBody(ScheduleUtils.createMsgForPc(
        // ALEipUtils.getUserId(rundata),
        // newSchedule,
        // memberList,
        // memberList,
        // "追加しました。",
        // rundata));
        // // change end
        // message.setCellularBody(ScheduleUtils.createMsgForCellPhone(
        // rundata,
        // newSchedule,
        // memberList,
        // destMember.getUserId()));
        // messageList.add(message);
        // }
        //
        // for (ALEipUserAddr destMember : destMemberList) {
        // List<ALEipUserAddr> destMembers = new ArrayList<ALEipUserAddr>();
        // destMembers.add(destMember);
        //
        // ALMailService.sendAdminMail(new ALAdminMailContext(
        // orgId,
        // ALEipUtils.getUserId(rundata),
        // messageList,
        // ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE)));
        //
        // }
        //
        // }
        //
        // } catch (Exception ex) {
        // msgList.add("メールを送信できませんでした。");
        // logger.error("Exception", ex);
        // return false;
        // }
        // remove end
      }
      // remove start
      // } else {
      // msgList.add("そのスケジュールは編集することができません");
      // res = false;
      // }
      // remove end
      // add start
    } catch (Exception e) {
      // add start 要件No.18 会議案内ファイル添付
      // ストアディレクトリに作成したファイルを削除する。
      ScheduleUtils.rollbackFiles(ownerId, newFilesMap);
      // add end
      Database.rollback();
      logger.error("予定のコピー登録に失敗しました。ログインユーザー:" + loginUserName + "/スケジュールID:" + schedule.getScheduleId(), e);
      return false;
    }
    // -----------------
    // メール送信処理
    // -----------------
    // メール送信先
    // 参加メンバー（ログインユーザーを除く）を送信先にする
    List<ALEipUserAddr> sendToUserList = ALMailUtils.getALEipUserAddrs(memberList, ALEipUtils.getUserId(rundata), false);
    // メール送信実行
    if (!ScheduleUtils.sendScheduleMail(sendToUserList, tempSc.getOwnerId(), tempSc, reqMemberList, subMemberList,
    // change start 要件No.1 スケジュール案内受信
      // "予定作成",
      ScheduleUtils.MEETING_CREATE,
      "作成しました。",
      rundata,
      // add start 要件No.1 スケジュール案内受信
      "",
      ScheduleUtils.CREATE_MSG_MODE_REQ
    // add end
      )) {
      msgList.add("メールを送信できませんでした。");
      return false;
    }

    if (tempSc.getOwnerId().intValue() != userId) {

      // 秘書設定元へ代理操作の通知を行なう。

      // メール送信先(ALEipUser)秘書設定元送信用
      List<ALEipUser> sendToEipClientUserList = new ArrayList<ALEipUser>(0);

      sendToEipClientUserList.add(ALEipUtils.getALEipUser(tempSc.getOwnerId().intValue()));

      List<ALEipUserAddr> sendToClientUserList = ALMailUtils.getALEipUserAddrs(sendToEipClientUserList, userId, false);

      if (!ScheduleUtils.sendScheduleMail(
        sendToClientUserList,
        userId,
        tempSc.getOwnerId(),
        tempSc,
        reqMemberList,
        subMemberList,
        ScheduleUtils.SUBSTITUTE_CREATE,
        "作成しました。",
        rundata,
        // add start 要件No.1 スケジュール案内受信
        "",
        ScheduleUtils.CREATE_MSG_MODE_SUBREQ
      // add end
        )) {
        msgList.add("mailErrMsg=メールを送信できませんでした。entityId=" + tempSc.getScheduleId());
        return false;
      }
    }
    // add end
    return res;
  }

  // add start
  /**
   * 予定登録先を保存する
   * 
   * @param action
   *            呼び出し元アクション
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   */
  public void saveLocationUser(ALAction action, RunData rundata, Context context) {
    // 予定登録先をセッションへ格納する
    if (rundata.getParameters().containsKey(ScheduleConst.SCHEDULE_LOCATION_USER_ID)) {
      ALEipUtils.setTemp(rundata, context, ScheduleConst.SCHEDULE_LOCATION_USER_ID, rundata.getParameters().getString(ScheduleConst.SCHEDULE_LOCATION_USER_ID));
    }
  }

  // add end

  private boolean doCheckAclPermission(RunData rundata, Context context, int defineAclType) throws ALPermissionException {

    // remove start
    // if (defineAclType == 0) {
    // return true;
    // }
    //
    // String pfeature = getAclPortletFeature();
    // if (pfeature == null || "".equals(pfeature)) {
    // return true;
    // }
    //
    // ALAccessControlFactoryService aclservice =
    // (ALAccessControlFactoryService) ((TurbineServices) TurbineServices
    // .getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
    // ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
    //
    // boolean hasAuthority =
    // aclhandler.hasAuthority(
    // ALEipUtils.getUserId(rundata),
    // pfeature,
    // defineAclType);
    //
    // if (!hasAuthority) {
    // throw new ALPermissionException();
    // }
    // remove end

    return true;
  }

  private void sendEventLog(RunData rundata, Context context) {
    ALEipUtils.setTemp(rundata, context, ALEipConstants.MODE, ALEipConstants.MODE_UPDATE);
    ALEventlogFactoryService.getInstance().getEventlogHandler().log(schedule.getScheduleId(), ALEventlogConstants.PORTLET_TYPE_SCHEDULE, schedule.getName());
  }

  private void sendWhatsNew(EipTSchedule newSchedule, boolean isNew) {

    // アクティビティ
    ALEipUser loginUser = null;
    try {
      loginUser = ALEipUtils.getALEipUser(userId);
    } catch (ALDBErrorException e) {
      //
    }
    if (loginUser != null) {
      String loginName = loginUser.getName().getValue();
      List<String> recipients = new ArrayList<String>();
      for (ALEipUser user : memberList) {
        if (loginUser.getUserId().getValue() != user.getUserId().getValue()) {
          recipients.add(user.getName().getValue());
        }
      }
      ScheduleUtils.createShareScheduleActivity(schedule, loginName, recipients, isNew);
    }
  }

  private boolean hasAcl(RunData rundata) {
    ALAccessControlFactoryService aclservice =
      (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
    ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
    boolean hasAuthority = aclhandler.hasAuthority(ALEipUtils.getUserId(rundata),
    // remove start
      // aclPortletFeature =
      // remove end
      ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER,
      ALAccessControlConstants.VALUE_ACL_INSERT);
    if (!hasAuthority) {
      return false;
    }
    return true;
  }

  // remove start
  // 未使用になったので削除
  // private String getAclPortletFeature() {
  // return aclPortletFeature;
  // }
  // remove end

  public List<String> getMsgList() {
    return msgList;
  }

  public boolean getIsViewList() {
    return isViewList;
  }

  // remove start
  // 使用しないため削除
  // private EipTScheduleMap getScheduleMap(List<EipTScheduleMap> scheduleMaps,
  // int userid, String type) {
  // EipTScheduleMap map = null;
  // int size = scheduleMaps.size();
  // for (int i = 0; i < size; i++) {
  // map = scheduleMaps.get(i);
  // if (map.getUserId().intValue() == userid && type.equals(map.getType())) {
  // return map;
  // }
  // }
  // return null;
  // }
  // remove end

  /**
   * セキュリティをチェックします。
   * 
   * @return
   */
  private boolean doCheckSecurity(RunData rundata, Context context) {
    String reqSecid = rundata.getParameters().getString(ALEipConstants.SECURE_ID);
    String sessionSecid = (String) rundata.getUser().getTemp(ALEipConstants.SECURE_ID);
    if (reqSecid == null || !reqSecid.equals(sessionSecid)) {
      return false;
    }

    return true;
  }
}
