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

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Pattern;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.Ordering;
import org.apache.commons.lang.time.DateUtils;
import org.apache.jetspeed.om.profile.Entry;
import org.apache.jetspeed.om.profile.Portlets;
import org.apache.jetspeed.om.security.UserIdPrincipal;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.util.template.JetspeedLink;
import org.apache.jetspeed.util.template.JetspeedLinkFactory;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.util.DynamicURI;
import org.apache.turbine.util.RunData;
import org.apache.turbine.util.TurbineException;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALAbstractField;
import com.aimluck.commons.field.ALCellDateField;
import com.aimluck.commons.field.ALCellDateTimeField;
import com.aimluck.commons.field.ALCellNumberField;
import com.aimluck.commons.field.ALCellStringField;
import com.aimluck.commons.field.ALDateContainer;
import com.aimluck.commons.field.ALDateField;
import com.aimluck.commons.field.ALDateTimeField;
import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.commons.utils.ALDateUtil;
import com.aimluck.commons.utils.ALStringUtil;
import com.aimluck.eip.category.util.CommonCategoryUtils;
import com.aimluck.eip.cayenne.om.account.AvzMUserGroupsend;
import com.aimluck.eip.cayenne.om.portlet.AvzTScheduleAcl;
import com.aimluck.eip.cayenne.om.portlet.AvzTScheduleFile;
import com.aimluck.eip.cayenne.om.portlet.EipMFacility;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
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.cayenne.om.security.TurbineUser;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALData;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.fileupload.beans.FileuploadBean;
import com.aimluck.eip.fileupload.beans.FileuploadLiteBean;
import com.aimluck.eip.fileupload.util.FileuploadUtils;
import com.aimluck.eip.mail.ALAdminMailMessage;
import com.aimluck.eip.mail.ALMailFactoryService;
import com.aimluck.eip.mail.ALMailHandler;
import com.aimluck.eip.mail.ALMailSenderContext;
import com.aimluck.eip.mail.ALSmtpMailContext;
import com.aimluck.eip.mail.ALSmtpMailSender;
import com.aimluck.eip.mail.util.ALEipUserAddr;
import com.aimluck.eip.mail.util.ALMailUtils;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.SQLTemplate;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.schedule.AjaxScheduleResultData;
import com.aimluck.eip.schedule.AjaxTermScheduleWeekContainer;
import com.aimluck.eip.schedule.ScheduleConst;
import com.aimluck.eip.schedule.ScheduleResultData;
import com.aimluck.eip.schedule.ScheduleTermWeekContainer;
import com.aimluck.eip.schedule.ScheduleToDoResultData;
import com.aimluck.eip.schedule.ScheduleToDoWeekContainer;
import com.aimluck.eip.schedule.ScheduleConst.DayOfWeek;
import com.aimluck.eip.schedule.ScheduleConst.DayType;
import com.aimluck.eip.schedule.ScheduleConst.ScheduleLimitPattern;
import com.aimluck.eip.schedule.ScheduleConst.ScheduleWeekNumber;
import com.aimluck.eip.schedule.beans.ScheduleUserBean;
import com.aimluck.eip.schedule.data.ScheduleMemberUser;
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.orgutils.ALOrgUtilsService;
import com.aimluck.eip.services.social.ALActivityService;
import com.aimluck.eip.services.social.model.ALActivityPutRequest;
import com.aimluck.eip.services.storage.ALStorageService;
import com.aimluck.eip.user.beans.UserGroupPositionLiteBean;
import com.aimluck.eip.user.util.UserUtils;
import com.aimluck.eip.userfacility.beans.UserFacilityLiteBean;
import com.aimluck.eip.util.ALCellularUtils;
import com.aimluck.eip.util.ALCommonUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * スケジュールのユーティリティクラスです。
 * 
 */
public class ScheduleUtils {

  /** <code>logger</code> loger */
  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(ScheduleUtils.class.getName());

  /** <code>SCHEDULEMAP_TYPE_USER</code> ユーザ */
  public static final String SCHEDULEMAP_TYPE_USER = "U";

  /** <code>SCHEDULEMAP_TYPE_FACILITY</code> 設備 */
  public static final String SCHEDULEMAP_TYPE_FACILITY = "F";

  /** <code>TARGET_FACILITY_ID</code> ユーザによる表示切り替え用変数の識別子 */
  public static final String TARGET_FACILITY_ID = "f";

  // add start
  /** <code>FIXED_STRING_FORMAT_DATE_KANJI</code>定型文フォーマット：日付：漢字 */
  public static final String FIXED_STRING_FORMAT_DATE_KANJI = "yyyy'年'MM'月'dd'日'";

  /** <code>FIXED_STRING_FORMAT_DATE_SLASH</code>定型文フォーマット：日付：スラッシュ */
  public static final String FIXED_STRING_FORMAT_DATE_SLASH = "yyyy/MM/dd";

  /** 「代理回答」文字列 */
  // change start 要件No.1 スケジュール案内受信
  // public static final String SUBSTITUTE_RESPONSE = "代理回答通知";
  public static final String SUBSTITUTE_RESPONSE = "代理回答";

  // change end

  /** 「代理予定作成」文字列 */
  // change start 要件No.1 スケジュール案内受信
  // public static final String SUBSTITUTE_CREATE = "代理予定作成通知";
  public static final String SUBSTITUTE_CREATE = "代理新規";

  // change end

  /** 「代理予定更新」文字列 */
  // change start 要件No.1 スケジュール案内受信
  // public static final String SUBSTITUTE_UPDATE = "代理予定更新通知";
  public static final String SUBSTITUTE_UPDATE = "代理修正";

  // change end

  /** 「代理予定削除」文字列 */
  // change start 要件No.1 スケジュール案内受信
  // public static final String SUBSTITUTE_DELETE = "代理予定削除通知";
  public static final String SUBSTITUTE_DELETE = "代理削除";

  // change end

  // add end

  // add start 要件No.1 スケジュール案内受信
  /** メール作成モード：会議案内メール */
  public static final int CREATE_MSG_MODE_REQ = 1;

  /** メール作成モード：回答メール */
  public static final int CREATE_MSG_MODE_RES = 2;

  /** メール作成モード：代理会議案内メール */
  public static final int CREATE_MSG_MODE_SUBREQ = 3;

  /** メール作成モード：代理回答メール */
  public static final int CREATE_MSG_MODE_SUBRES = 4;

  /** 「会議案内作成」文字列 */
  public static final String MEETING_CREATE = "新規";

  /** 「会議案内修正」文字列 */
  public static final String MEETING_UPDATE = "修正";

  /** 「会議案内削除」文字列 */
  public static final String MEETING_DELETE = "削除";

  // add end

  // add start 要件No.6 スケジュール画面（月単位）
  /** 月間用先頭曜日指定 日曜日：1、月曜日:2、火曜日：3、水曜日：4、木曜日:5、金曜日:6、土曜日：7 */
  public static final String BEGINNING_DAYOFWEEK_FOR_MONTH = JetspeedResources.getString("aipo.beginning_dayofweek_for_month", "2");

  /** 週間用先頭曜日指定 日曜日：1、月曜日:2、火曜日：3、水曜日：4、木曜日:5、金曜日:6、土曜日：7 */
  public static final String BEGINNING_DAYOFWEEK_FOR_WEEK = JetspeedResources.getString("aipo.beginning_dayofweek_for_week", "2");

  // add end

  // add start 要件No.18 会議案内ファイル添付

  /** スケジュールの添付ファイルを保管するディレクトリの指定 */
  private static final String FOLDER_FILEDIR_SCHEDULE = JetspeedResources.getString("aipo.filedir", "");

  /** スケジュールの添付ファイルを保管するディレクトリのカテゴリキーの指定 */
  protected static final String CATEGORY_KEY = JetspeedResources.getString("aipo.schedule.categorykey", "schedule");

  /** デフォルトエンコーディングを表わすシステムプロパティのキー */
  public static final String FILE_ENCODING = JetspeedResources.getString("content.defaultencoding", "UTF-8");

  // add end

  // add start 要件No.26 スケジュール個別色換え
  /** スケジュール分類・色：分類名リスト */
  public static final List<String> SCHEDULE_CATEGORY_NAME_LIST = new ArrayList<String>(0);

  /** スケジュール分類・色：色コードリスト */
  public static final List<String> SCHEDULE_CATEGORY_COLOR_LIST = new ArrayList<String>(0);

  /**
   * スケジュール分類・色の初期化
   */
  static {
    @SuppressWarnings("unchecked")
    Iterator<String> keys = JetspeedResources.getKeys("aipo.schedule_category_color.");
    while (keys.hasNext()) {
      String[] nameAndColor = JetspeedResources.getStringArray(keys.next());
      SCHEDULE_CATEGORY_NAME_LIST.add(nameAndColor[0]);
      if (nameAndColor.length > 1) {
        SCHEDULE_CATEGORY_COLOR_LIST.add(nameAndColor[1]);
      } else {
        SCHEDULE_CATEGORY_COLOR_LIST.add("");
      }
    }
  }

  // add end

  /**
   * 追加・更新・削除用スケジュール検索[AIPO_COM_002]<br/>
   * 所有者スケジュールに対して操作者に操作権限が無い場合、エラー画面へ遷移させます。<br/>
   * ここで操作者をログインユーザー固定に設定します。
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          Velocityコンテキスト
   * @param isOwner
   *          所有者検索可否
   * @return 検索結果のスケジュール
   * @throws ALPageNotFoundException
   *           検索結果が得られ無かった場合
   * @throws ALDBErrorException
   *           DBエラーが発生した場合
   */
  public static EipTSchedule getEipTSchedule(RunData rundata, Context context, boolean isOwner) throws ALPageNotFoundException, ALDBErrorException {
    return getEipTSchedule(rundata, context, isOwner, ALEipUtils.getUserId(rundata));

  }

  /**
   * 予定一覧での更新・コピー登録用スケジュール取得
   * 
   * @param rundata
   *          実行データ
   * @param scheduleid
   *          スケジュールID
   * @param isOwner
   *          主催者判定するか否か
   * @param userid
   *          権限判定対象のユーザーID
   * @return 検索結果のスケジュール
   * @throws ALDBErrorException
   *           何らかの例外が発生した場合
   */
  public static EipTSchedule getEipTSchedule(RunData rundata, int scheduleid, boolean isOwner, int userid) throws ALPageNotFoundException, ALDBErrorException {

    try {
      SelectQuery<EipTSchedule> query = Database.query(EipTSchedule.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchDbExp(EipTSchedule.SCHEDULE_ID_PK_COLUMN, Integer.valueOf(scheduleid));
      query.setQualifier(exp1);

      if (isOwner) {
        // ユーザーID
        Expression exp2 = ExpressionFactory.matchExp(EipTSchedule.OWNER_ID_PROPERTY, Integer.valueOf(ALEipUtils.getUserId(rundata)));
        query.andQualifier(exp2);
      }

      List<EipTSchedule> schedules = query.fetchList();

      // 指定したSchedule IDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        throw new ALPageNotFoundException();
      }

      EipTSchedule record = schedules.get(0);

      // change start
      // 主催者に対して権限が[本人][秘書]以外はエラーにする
      // // 条件が足りないかも（by Komori 2006/06/09）
      // SelectQuery<EipTScheduleMap> mapquery =
      // Database.query(EipTScheduleMap.class);
      // Expression mapexp1 =
      // ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, record
      // .getScheduleId());
      // mapquery.setQualifier(mapexp1);
      // Expression mapexp2 =
      // ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer
      // .valueOf(userid));
      // mapquery.andQualifier(mapexp2);
      // Expression mapexp3 =
      // ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer
      // .valueOf(userid));
      // mapquery.andQualifier(mapexp3);
      //
      // List<EipTScheduleMap> schedulemaps = mapquery.fetchList();
      // boolean is_member =
      // (schedulemaps != null && schedulemaps.size() > 0) ? true : false;
      //
      // // boolean is_member = orm_map.count(new Criteria().add(
      // // EipTScheduleMapConstants.SCHEDULE_ID, record.getScheduleId()).add(
      // // EipTScheduleMapConstants.USER_ID, userid).add(
      // // EipTScheduleMapConstants.USER_ID, ALEipUtils.getUserId(rundata))) !=
      // 0;
      //
      // boolean is_public = "O".equals(record.getPublicFlag());
      //
      // // アクセス権限がない場合
      // if (!is_member && !is_public) {
      // logger.error("[ScheduleUtils] Cannnot access this record. ");
      // throw new ALPageNotFoundException();
      // }
      //
      // return schedules.get(0);
      String acl = getScheduleAcl(Integer.toString(userid), record.getOwnerId().toString());
      if (!ScheduleConst.SCHEDULE_ACL_MYSELF.equals(acl) && !ScheduleConst.SCHEDULE_ACL_SECRETARY.equals(acl)) {
        throw new Exception("スケジュールに対する更新権限がありません。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName().getValue() + "/スケジュールID:" + scheduleid);
      }
      return record;
      // change end

    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();
    }
  }

  /**
   * 追加・更新・削除用スケジュール検索[AIPO_COM_002]<br/>
   * 所有者スケジュールに対して操作者に操作権限が無い場合、エラー画面へ遷移させます。
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          Velocityコンテキスト
   * @param isOwner
   *          所有者検索可否
   * @param userid
   *          所有者ユーザーID
   * @return 検索結果のスケジュール
   * @throws ALPageNotFoundException
   *           検索結果が得られ無かった場合
   * @throws ALDBErrorException
   *           DBエラーが発生した場合
   */
  public static EipTSchedule getEipTSchedule(RunData rundata, Context context, boolean isOwner, int userid) throws ALPageNotFoundException, ALDBErrorException {

    // String org_id = OrgORMappingMap.getInstance().getOrgId(rundata);

    // スケジュールIDをセッション変数から取得
    String scheduleid = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);

    try {
      // IDが空の場合 || IDがintでない場合
      if (scheduleid == null || Integer.valueOf(scheduleid) == null) {
        logger.error("[ScheduleUtils] ENTITYID is empty.");
        throw new ALPageNotFoundException();
      }
    } catch (NumberFormatException ex) {
      logger.error("[ScheduleUtils] NumberFormatException: ENTITYID is wrong.");
      throw new ALPageNotFoundException();

    }

    try {
      SelectQuery<EipTSchedule> query = Database.query(EipTSchedule.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchDbExp(EipTSchedule.SCHEDULE_ID_PK_COLUMN, scheduleid);
      query.setQualifier(exp1);

      if (isOwner) {
        // ユーザーID
        Expression exp2 = ExpressionFactory.matchExp(EipTSchedule.OWNER_ID_PROPERTY, Integer.valueOf(ALEipUtils.getUserId(rundata)));
        query.andQualifier(exp2);
      }

      List<EipTSchedule> schedules = query.fetchList();

      // 指定したSchedule IDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        throw new ALPageNotFoundException();
      }

      EipTSchedule record = schedules.get(0);

      // change start
      // 秘書設定対応
      // // Integer.valueOf(userid)
      // // 条件が足りないかも（by Komori 2006/06/09）
      // SelectQuery<EipTScheduleMap> mapquery =
      // Database.query(EipTScheduleMap.class);
      // Expression mapexp1 =
      // ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, record
      // .getScheduleId());
      // mapquery.setQualifier(mapexp1);
      // Expression mapexp21 =
      // ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, ALEipUtils
      // .getUserId(rundata));
      // Expression mapexp22 =
      // ExpressionFactory.matchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY
      // + "."
      // + EipTSchedule.CREATE_USER_ID_PROPERTY, Integer.valueOf(ALEipUtils
      // .getUserId(rundata)));
      // mapquery.andQualifier(mapexp21.orExp(mapexp22));
      //
      // List<EipTScheduleMap> schedulemaps = mapquery.fetchList();
      // boolean is_member =
      // (schedulemaps != null && schedulemaps.size() > 0) ? true : false;
      //
      // // boolean is_member = orm_map.count(new Criteria().add(
      // // EipTScheduleMapConstants.SCHEDULE_ID, record.getScheduleId()).add(
      // // EipTScheduleMapConstants.USER_ID, userid).add(
      // // EipTScheduleMapConstants.USER_ID, ALEipUtils.getUserId(rundata))) !=
      // 0;
      //
      // int loginuser_id = ALEipUtils.getUserId(rundata);
      // boolean is_owner = record.getOwnerId().intValue() == loginuser_id;
      // boolean is_createuser =
      // loginuser_id == record.getCreateUserId().intValue();
      // boolean is_public = "O".equals(record.getPublicFlag());
      //
      // // アクセス権限がない場合
      // if (!is_public && !is_member && (!(is_createuser || is_owner))) {
      // ALEipUtils.redirectPermissionError(rundata);
      // }
      String acl = getScheduleAcl(Integer.toString(userid), record.getOwnerId().toString());
      if (!ScheduleConst.SCHEDULE_ACL_MYSELF.equals(acl) && !ScheduleConst.SCHEDULE_ACL_SECRETARY.equals(acl)) {
        throw new Exception("スケジュールに対する更新権限がありません。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName().getValue() + "/スケジュールID:" + scheduleid);
      }

      return schedules.get(0);

    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();
    }
  }

  /**
   * スケジュールへのアクセス権限があるかどうかを調べます。
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static boolean hasAuthorityForScheduleDetail(RunData rundata, Context context, EipTSchedule record, String type) throws ALPageNotFoundException,
      ALDBErrorException {
    try {
      int userId = ALEipUtils.getUserId(rundata);

      SelectQuery<EipTScheduleMap> mapquery = Database.query(EipTScheduleMap.class);
      Expression mapexp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, record.getScheduleId());
      mapquery.setQualifier(mapexp1);
      Expression mapexp21 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.toString(userId));
      Expression mapexp22 =
        ExpressionFactory.matchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.CREATE_USER_ID_PROPERTY, Integer.valueOf(userId));
      mapquery.andQualifier(mapexp21.orExp(mapexp22));
      Expression mapexp3 = ExpressionFactory.matchExp(EipTScheduleMap.TYPE_PROPERTY, type);
      mapquery.andQualifier(mapexp3);

      List<EipTScheduleMap> schedulemaps = mapquery.fetchList();
      boolean is_member = (schedulemaps != null && schedulemaps.size() > 0) ? true : false;

      boolean is_owner = record.getOwnerId().intValue() == userId;
      boolean is_createuser = record.getCreateUserId().intValue() == userId;
      boolean is_public = "O".equals(record.getPublicFlag());

      // アクセス権限がない場合
      if (type.equals("F") || is_public) {
      } else if (!is_member && (!(is_createuser || is_owner))) {
        return false;
      }
      return true;
    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();
    }
  }

  /**
   * ツールチップ表示用の Scheudle オブジェクトモデルを取得する．
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTSchedule getEipTScheduleDetailForTooltip(RunData rundata, Context context, String type) throws ALPageNotFoundException, ALDBErrorException {

    String scheduleid = rundata.getParameters().getString("scheduleid");

    try {
      if (scheduleid == null || Integer.valueOf(scheduleid) == null) {
        logger.error("[ScheduleUtils] ENTITYID is empty.");
        return null;
      }

      SelectQuery<EipTSchedule> query = Database.query(EipTSchedule.class);
      query.getQuery().setRefreshingObjects(true);

      Expression exp1 = ExpressionFactory.matchDbExp(EipTSchedule.SCHEDULE_ID_PK_COLUMN, scheduleid);
      query.setQualifier(exp1);

      Expression exp2 = ExpressionFactory.matchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY + "." + EipTScheduleMap.TYPE_PROPERTY, type);
      query.andQualifier(exp2);

      List<EipTSchedule> schedules = query.fetchList();

      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        return null;
      }

      EipTSchedule record = schedules.get(0);
      // remove start
      // 権限判定廃止
      // if (!hasAuthorityForScheduleDetail(rundata, context, record, type)) {
      // return null;
      // }
      // remove end

      return record;
    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();
    }
  }

  /**
   * 詳細表示用の Scheudle オブジェクトモデルを取得する．
   * 
   * @param rundata
   *          実行データ
   * @param context
   *          コンテキスト
   * @retur スケジュール情報
   * @exception ALPageNotFoundException
   *              データが見つからなかった場合
   * @exception ALDBErrorException
   *              DBエラー
   * @exception Exception
   *              その他エラー
   */
  public static EipTSchedule getEipTScheduleDetail(RunData rundata, Context context, String type) throws ALPageNotFoundException, ALDBErrorException
  // change start
      // 運用課題No.34
      // {
      , Exception {
    // change end

    // スケジュールIDをセッション変数から取得
    String scheduleid = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);

    try {
      // IDが空の場合 || IDがintでない場合
      if (scheduleid == null || Integer.valueOf(scheduleid) == null) {
        logger.error("[ScheduleUtils] ENTITYID is empty.");
        // change start
        // 運用課題No.34
        // ALPageNotFoundExceptionはデータなしエラー扱いにする。
        // throw new ALPageNotFoundException();
        throw new Exception("IDが空");
        // change end
      }
    } catch (NumberFormatException ex) {
      logger.error("[ScheduleUtils] NumberFormatException: ENTITYID is wrong.", ex);
      // change start
      // 運用課題No.34
      // ALPageNotFoundExceptionはデータなしエラー扱いにする。
      // throw new ALPageNotFoundException();
      throw ex;
      // change end
    }

    try {
      SelectQuery<EipTSchedule> query = Database.query(EipTSchedule.class);
      query.getQuery().setRefreshingObjects(true);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchDbExp(EipTSchedule.SCHEDULE_ID_PK_COLUMN, scheduleid);
      query.setQualifier(exp1);

      // ユーザのスケジュール
      Expression exp2 = ExpressionFactory.matchExp(EipTSchedule.EIP_TSCHEDULE_MAPS_PROPERTY + "." + EipTScheduleMap.TYPE_PROPERTY, type);
      query.andQualifier(exp2);

      List<EipTSchedule> schedules = query.fetchList();

      // 指定したSchedule IDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        throw new ALPageNotFoundException();
      }

      // add start
      // 受入障害対応No.195
      int userId = ALEipUtils.getUserId(rundata);
      String target_user_id = rundata.getParameters().getString("userid");
      if (String.valueOf(userId).equals(target_user_id) || null == target_user_id) {
        SelectQuery<EipTScheduleMap> mapQuery = Database.query(EipTScheduleMap.class);
        mapQuery.getQuery().setRefreshingObjects(true);

        Expression exp3 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, scheduleid);
        Expression exp4 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, userId);
        Expression exp5 = ExpressionFactory.matchExp(EipTScheduleMap.DUMMY_NON_RESPONSE_PROPERTY, ScheduleConst.SCHEDULEMAP_DUMMY_NON_RES_T);
        Expression exp6 = ExpressionFactory.matchExp(EipTScheduleMap.STATUS_PROPERTY, ScheduleConst.SCHEDULEMAP_STATUS_REMOVE);
        mapQuery.setQualifier(exp3.andExp(exp4).andExp(exp5.orExp(exp6)));
        List<EipTScheduleMap> scheduleMap = mapQuery.fetchList();
        // 指定したSchedule IDのレコードがある場合
        if (scheduleMap != null && scheduleMap.size() > 0) {
          // change start
          // 運用課題No.34
          // return null;
          logger.error("[ScheduleUtils] Finishing of deletion.");
          // データなし例外を投げる
          throw new ALPageNotFoundException();
          // change end
        }
      }
      // add end

      EipTSchedule record = schedules.get(0);
      // remove start
      // [秘書]の概念があるため、既存の権限判定を使用しない
      // if (!hasAuthorityForScheduleDetail(rundata, context, record, type)) {
      // ALEipUtils.redirectPermissionError(rundata);
      // }
      // remove end
      return record;
    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      // change start
      // 運用課題No.34
      // 例外のハンドリングは呼び出し元に譲渡する
      // throw new ALDBErrorException();
      throw ex;
      // change end
    }
  }

  // add start
  /**
   * 論理キーよりScheudleMapオブジェクトモデルを検索し、結果を返します。
   * 
   * @param userId
   *          ユーザーID（論理キー）
   * @param scheduleId
   *          スケジュールID（論理キー）
   * @return 検索結果のScheudleMapオブジェクトモデルを
   */
  public static EipTScheduleMap getEipTScheduleMapByLogicKey(Integer userId, Integer scheduleId) throws ALPageNotFoundException, ALDBErrorException {

    try {
      SelectQuery<EipTScheduleMap> query = Database.query(EipTScheduleMap.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, scheduleId);
      query.setQualifier(exp1);
      // ユーザーID
      Expression exp2 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, userId);
      query.andQualifier(exp2);

      List<EipTScheduleMap> schedules = query.fetchList();

      // 指定したIDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("スケジュールマップが見つかりませんでした。ユーザーID:" + userId + "/スケジュールID:" + scheduleId);
        throw new ALPageNotFoundException();
      }

      return schedules.get(0);

    } catch (Exception ex) {
      logger.error("スケジュールマップの検索でDBエラーが発生しました。ユーザーID:" + userId + "/スケジュールID:" + scheduleId, ex);
      throw new ALDBErrorException();
    }
  }

  // add end

  /**
   * ScheudleMap オブジェクトモデルを取得します。
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static EipTScheduleMap getEipTScheduleMap(RunData rundata, Context context) throws ALPageNotFoundException, ALDBErrorException {

    // スケジュールIDをセッション変数から取得
    String scheduleid = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);

    try {
      // IDが空の場合 || IDがintでない場合
      if (scheduleid == null || Integer.valueOf(scheduleid) == null) {
        logger.error("[ScheduleUtils] ENTITYID is empty.");
        throw new ALPageNotFoundException();
      }
    } catch (NumberFormatException ex) {
      logger.error("[ScheduleUtils] NumberFormatException: ENTITYID is wrong.", ex);
      throw new ALPageNotFoundException();

    }

    try {
      SelectQuery<EipTScheduleMap> query = Database.query(EipTScheduleMap.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, scheduleid);
      query.setQualifier(exp1);
      // ユーザーID
      Expression exp2 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.valueOf(ALEipUtils.getUserId(rundata)));
      query.andQualifier(exp2);

      List<EipTScheduleMap> schedules = query.fetchList();

      // 指定したIDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        throw new ALPageNotFoundException();
      }

      return schedules.get(0);

    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();

    }
  }

  public static List<EipTScheduleMap> getEipTScheduleMaps(EipTSchedule schedule) throws ALPageNotFoundException, ALDBErrorException {

    // スケジュールIDを取得
    Integer scheduleid = schedule.getScheduleId();

    try {
      SelectQuery<EipTScheduleMap> query = Database.query(EipTScheduleMap.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, scheduleid);
      query.setQualifier(exp1);

      List<EipTScheduleMap> schedules = query.fetchList();

      // 指定したIDのレコードが見つからない場合
      if (schedules == null || schedules.size() == 0) {
        logger.error("[ScheduleUtils] Not found record.");
        throw new ALPageNotFoundException();
      }

      return schedules;

    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();

    }
  }

  /**
   * 共有メンバーを取得します。
   * 
   * @param rundata
   * @param context
   * @param includeLoginUser
   *          ログインユーザーを共有メンバーとして取り扱う場合，true．
   * @return
   */
  public static List<ALEipUser> getUsers(RunData rundata, Context context, boolean includeLoginUser) throws ALPageNotFoundException, ALDBErrorException {
    List<ALEipUser> list = new ArrayList<ALEipUser>();

    // スケジュールIDをセッション変数から取得
    String scheduleid = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);

    try {
      // IDが空の場合 || IDがintでない場合
      if (scheduleid == null || Integer.valueOf(scheduleid) == null) {
        logger.error("[ScheduleUtils] ENTITYID is empty.");
        throw new ALPageNotFoundException();
      }
    } catch (NumberFormatException ex) {
      logger.error("[ScheduleUtils] NumberFormatException: ENTITYID is wrong.", ex);
      throw new ALPageNotFoundException();

    }

    try {
      SelectQuery<EipTScheduleMap> mapquery = Database.query(EipTScheduleMap.class);

      // スケジュールID
      Expression exp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, Integer.valueOf(scheduleid));
      mapquery.setQualifier(exp1);
      if (!includeLoginUser) {
        Expression exp2 = ExpressionFactory.noMatchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.valueOf(ALEipUtils.getUserId(rundata)));
        mapquery.andQualifier(exp2);
      }
      List<EipTScheduleMap> schedulemaps = mapquery.fetchList();

      List<Integer> uidlist = new ArrayList<Integer>();
      EipTScheduleMap map = null;
      int mapsize = schedulemaps.size();
      for (int i = 0; i < mapsize; i++) {
        map = schedulemaps.get(i);
        if (!uidlist.contains(map.getUserId())) {
          uidlist.add(map.getUserId());
        }
      }

      SelectQuery<TurbineUser> userquery = Database.query(TurbineUser.class);
      Expression userexp = ExpressionFactory.inDbExp(TurbineUser.USER_ID_PK_COLUMN, uidlist);
      userquery.setQualifier(userexp);
      List<Ordering> orders = new ArrayList<Ordering>();
      orders.add(new Ordering(TurbineUser.LAST_NAME_KANA_PROPERTY, true));
      orders.add(new Ordering(TurbineUser.FIRST_NAME_KANA_PROPERTY, true));
      userquery.getQuery().addOrderings(orders);

      List<TurbineUser> ulist = userquery.fetchList();

      TurbineUser tuser;
      ALEipUser user;
      for (int j = 0; j < ulist.size(); j++) {
        tuser = ulist.get(j);
        user = new ALEipUser();
        user.initField();
        user.setUserId(tuser.getUserId().intValue());
        user.setName(tuser.getLoginName());
        user.setAliasName(tuser.getFirstName(), tuser.getLastName());
        list.add(user);
      }

    } catch (Exception e) {
      logger.error("[ScheduleUtils]", e);
      throw new ALDBErrorException();

    }
    return list;
  }

  /**
   * 施設メンバーを取得します。
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static int[] getFacilityIds(EipTSchedule schedule) throws ALPageNotFoundException, ALDBErrorException {
    List<?> list = schedule.getEipTScheduleMaps();

    List<Integer> flist = new ArrayList<Integer>();
    EipTScheduleMap map = null;
    int size = list.size();
    for (int i = 0; i < size; i++) {
      map = (EipTScheduleMap) list.get(i);
      if (SCHEDULEMAP_TYPE_FACILITY.equals(map.getType())) {
        flist.add(map.getUserId());
      }
    }

    int fsize = flist.size();
    int[] ids = new int[fsize];
    for (int i = 0; i < fsize; i++) {
      ids[i] = (flist.get(i)).intValue();
    }
    return ids;
  }

  // add start
  /**
   * 繰り返しスケジュールの表示可否判定（判定範囲がある場合）[AIPO_COM_003]<br/>
   * 判定開始日時から判定終了日時まで日単位で表示可能か判定する。
   * 
   * @param chkStartDateTime
   *          判定開始日時
   * @param chkEndDateTime
   *          判定終了日時
   * @param ptn
   *          チェック対象スケジュールの繰り返しパターン
   * @param startDateTime
   *          チェック対象スケジュールの開始時間
   * @param endDateTime
   *          チェック対象スケジュールの終了時間
   * @return 表示可能な場合true、不可能な場合false
   */
  public static boolean isView(Date chkStartDateTime, Date chkEndDateTime, String ptn, Date startDateTime, Date endDateTime) {

    // 判定開始日と判定終了日の日数を求める
    int chkDays = differenceDays(chkEndDateTime, chkStartDateTime);

    // 作業用定数を取得
    // 予定.開始日（有効期限開始日）を取得
    Date startDate = DateUtils.truncate(startDateTime, Calendar.DAY_OF_MONTH);
    // 予定.終了日（有効期限終了日）を取得
    Date endDate = DateUtils.truncate(endDateTime, Calendar.DAY_OF_MONTH);
    // 予定開始時刻取得用カレンダー
    Calendar wkStartTimeCal = Calendar.getInstance();
    wkStartTimeCal.setTime(startDateTime);

    // 基準日入力フィールド
    ALDateTimeField baseDate = new ALDateTimeField();
    // 基準日カレンダー
    Calendar baseDateCal = Calendar.getInstance();
    baseDateCal.setTime(chkStartDateTime);
    baseDateCal = DateUtils.truncate(baseDateCal, Calendar.DAY_OF_MONTH);

    // 日数で処理を繰り返す
    boolean result = false;
    for (int i = 0; i <= chkDays; i++) {
      if (i > 0) {
        // 次の日を基準日にする
        baseDateCal.add(Calendar.DAY_OF_MONTH, 1);
      }

      // 繰り返しパターン別判定実行
      baseDate.setValue(baseDateCal.getTime());
      result = isView(baseDate, ptn, startDateTime, endDateTime);
      if (!result) {
        continue;
      }

      // 基準日の予定開始時間を取得
      Calendar baseStartTimeCal = Calendar.getInstance();
      baseStartTimeCal.setTime(baseDateCal.getTime());
      baseStartTimeCal.set(Calendar.HOUR_OF_DAY, wkStartTimeCal.get(Calendar.HOUR_OF_DAY));
      baseStartTimeCal.set(Calendar.MINUTE, wkStartTimeCal.get(Calendar.MINUTE));

      // 基準日が有効期限内 かつ 基準日の予定開始時間が判定期間内(主にリマインダー用) か判定する
      if ((startDate.getTime() <= baseDateCal.getTimeInMillis() && baseDateCal.getTimeInMillis() <= endDate.getTime())
        && (chkStartDateTime.getTime() <= baseStartTimeCal.getTimeInMillis() && baseStartTimeCal.getTimeInMillis() <= chkEndDateTime.getTime())) {
        result = true;
        break;
      } else {
        result = false;
      }
    }

    // 該当しない場合は偽で終了する
    return result;
  }

  /**
   * 日時オブジェクトと日付コードより、該当する日を返します。<br/>
   * 日付コードが[最終日]の場合は日時オブジェクトの月末最終日を返します。<br/>
   * 日付コードが[最終日]でない場合は日付コードの日を返します。
   * 
   * @param date
   *          日時オブジェクト
   * @param dayCode
   *          日付コード
   * @return 日
   */
  public static int getDayFromDayCode(Date date, String dayCode) {
    int day;
    if (ScheduleConst.SCHEDULE_REPEAT_PATTERN_LAST.equals(dayCode)) {
      // 最終日の場合
      Calendar lastDay = Calendar.getInstance();
      lastDay.setTime(date);
      day = lastDay.getActualMaximum(Calendar.DAY_OF_MONTH);
    } else {
      // 最終日でない場合
      day = Integer.parseInt(dayCode);
    }
    return day;
  }

  // add end
  /**
   * 指定した繰り返しパターンにマッチするかどうかを返します。[AIPO_COM_003]
   * 
   * @param date
   *          判定日
   * @param ptn
   *          チェック対象スケジュールの繰り返しパターン
   * @param startDate
   *          チェック対象スケジュールの開始時間
   * @param limitDate
   *          チェック対象スケジュールの終了時間
   * @return 表示可能な場合true、不可能な場合false
   */
  public static boolean isView(ALDateTimeField date, String ptn, Date startDate, Date limitDate) {
    int count = 0;
    boolean result = false;
    Calendar cal = Calendar.getInstance();
    cal.setTime(date.getValue());
    // 毎日
    if (ptn.charAt(0) == 'D') {
      result = true;
      count = 1;
      // 毎週
    } else if (ptn.charAt(0) == 'W') {

      int dow = cal.get(Calendar.DAY_OF_WEEK);
      switch (dow) {
        // 日
        case Calendar.SUNDAY:
          result = ptn.charAt(1) != '0';
          break;
        // 月
        case Calendar.MONDAY:
          result = ptn.charAt(2) != '0';
          break;
        // 火
        case Calendar.TUESDAY:
          result = ptn.charAt(3) != '0';
          break;
        // 水
        case Calendar.WEDNESDAY:
          result = ptn.charAt(4) != '0';
          break;
        // 木
        case Calendar.THURSDAY:
          result = ptn.charAt(5) != '0';
          break;
        // 金
        case Calendar.FRIDAY:
          result = ptn.charAt(6) != '0';
          break;
        // 土
        case Calendar.SATURDAY:
          result = ptn.charAt(7) != '0';
          break;
        default:
          result = false;
          break;
      }
      count = 8;
      // 毎月
    } else if (ptn.charAt(0) == 'M') {
      int mday = Integer.parseInt(ptn.substring(1, 3));
      result = Integer.parseInt(date.getDay()) == mday;
      count = 3;
      // add start
      // 定期パターン増加対応
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_DAILY.charAt(0)) {
      // 間隔 X日ごとに設定 pattern AxxxL
      int intervalDay = Integer.parseInt(ptn.substring(1, 4));
      if (isApplicateDayForA(date.getValue(), startDate, intervalDay)) {
        result = true;
      }
      count = ptn.length() - 1;
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_WEEKLY.charAt(0)) {
      // 間隔 X週ごとに設定 pattern BxxnnnnnnnL
      if (isApplicateWeek(date.getValue(), startDate, ptn)) {
        result = true;
      }
      count = ptn.length() - 1;
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_MONTHLY_DAY.charAt(0)) {
      // xヶ月ごとの dd日に設定 pattern CxxddN
      int intervalMonth = Integer.parseInt(ptn.substring(1, 3));
      int mday = getDayFromDayCode(date.getValue(), ptn.substring(3, 5));
      if (Integer.parseInt(date.getDay()) == mday) {
        if (isApplicateMonth(date.getValue(), startDate, intervalMonth)) {
          result = true;
        }
      }
      count = ptn.length() - 1;
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_MONTHLY_WEEK.charAt(0)) {
      // xxヶ月ごとの 第Y Z曜日に設定 ExxWyzN
      int intervalMonth = Integer.parseInt(ptn.substring(1, 3));
      if (isApplicateMonth(date.getValue(), startDate, intervalMonth)) {
        int day = getDayForMonthlyWeekPattern(Integer.parseInt(date.getYear()), Integer.parseInt(date.getMonth()), ptn.substring(4, 5), ptn.substring(5, 6));
        if (day == Integer.parseInt(date.getDay())) {
          result = true;
        }
      }
      count = ptn.length() - 1;
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_YEARLY_DAY.charAt(0)) {
      // X月Y日に設定 pattern FmmddN
      int month = Integer.parseInt(ptn.substring(1, 3));
      int mday = getDayFromDayCode(date.getValue(), ptn.substring(3, 5));
      if (Integer.parseInt(date.getMonth()) == month && Integer.parseInt(date.getDay()) == mday) {
        result = true;
      }
      count = ptn.length() - 1;
    } else if (ptn.charAt(0) == ScheduleConst.SCHEDULE_PATTERN_YEARLY_WEEK.charAt(0)) {
      // X月第Y Z曜日に設定 GmmWyzN
      int month = Integer.parseInt(ptn.substring(1, 3));
      if (month == Integer.parseInt(date.getMonth())) {
        int day = getDayForMonthlyWeekPattern(Integer.parseInt(date.getYear()), month, ptn.substring(4, 5), ptn.substring(5, 6));
        if (day == Integer.parseInt(date.getDay())) {
          result = true;
        }
      }
      count = ptn.length() - 1;
      // add end
    } else {
      return true;
    }

    if (result) {
      if (ptn.charAt(count) == 'L') {
        // 締め切り日がある場合
        if (equalsToDate(startDate, date.getValue(), false) || equalsToDate(limitDate, date.getValue(), false)) {
          // 繰り返しの開始日と終了日
          result = true;
        } else {
          // 繰り返しの開始日と終了日の間に指定した日が入っているかを検証．
          result = result && startDate.before(cal.getTime()) && limitDate.after(cal.getTime());
        }
      }
    }

    return result;
  }

  /**
   * 指定したエントリー名を持つ個人設定ページに含まれるポートレットへの URI を取得する．
   * 
   * @param rundata
   * @param portletEntryName
   *          PSML ファイルに記述されているタグ entry の要素 parent
   * @return
   */
  public static String getPortletURIinPersonalConfigPane(RunData rundata, String portletEntryName) {
    try {
      Portlets portlets = ((JetspeedRunData) rundata).getProfile().getDocument().getPortlets();
      if (portlets == null) {
        return null;
      }

      Portlets[] portletList = portlets.getPortletsArray();
      if (portletList == null) {
        return null;
      }

      int length = portletList.length;
      for (int i = 0; i < length; i++) {
        Entry[] entries = portletList[i].getEntriesArray();
        if (entries == null || entries.length <= 0) {
          continue;
        }

        int ent_length = entries.length;
        for (int j = 0; j < ent_length; j++) {
          if (entries[j].getParent().equals(portletEntryName)) {
            JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);

            DynamicURI duri = jsLink.getLink(JetspeedLink.CURRENT, null, null, JetspeedLink.CURRENT, null);
            duri =
              duri.addPathInfo(JetspeedResources.PATH_PANEID_KEY, portletList[i].getId() + "," + entries[j].getId()).addQueryData(
                JetspeedResources.PATH_ACTION_KEY,
                "controls.Restore");
            return duri.toString();
          }
        }
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
    return null;
  }

  public static String getPortletURItoTodoDetailPane(RunData rundata, String portletEntryName, long entityid, String schedulePortletId) {
    return getPortletURItoTodoModePane(rundata, portletEntryName, entityid, schedulePortletId, "detail");
  }

  public static String getPortletURItoTodoPublicDetailPane(RunData rundata, String portletEntryName, long entityid, String schedulePortletId) {
    return getPortletURItoTodoModePane(rundata, portletEntryName, entityid, schedulePortletId, "public_detail");
  }

  public static String getPortletURItoTodoModePane(RunData rundata, String portletEntryName, long entityid, String schedulePortletId, String mode) {
    if (mode == null || "".equals(mode)) {
      return null;
    }

    try {
      Portlets portlets = ((JetspeedRunData) rundata).getProfile().getDocument().getPortlets();
      if (portlets == null) {
        return null;
      }

      Portlets[] portletList = portlets.getPortletsArray();
      if (portletList == null) {
        return null;
      }

      int length = portletList.length;
      for (int i = 0; i < length; i++) {
        Entry[] entries = portletList[i].getEntriesArray();
        if (entries == null || entries.length <= 0) {
          continue;
        }

        int ent_length = entries.length;
        for (int j = 0; j < ent_length; j++) {
          if (entries[j].getParent().equals(portletEntryName)) {
            JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);

            DynamicURI duri = jsLink.getLink(JetspeedLink.CURRENT, null, null, JetspeedLink.CURRENT, null);
            duri =
              duri
                .addPathInfo(JetspeedResources.PATH_PANEID_KEY, portletList[i].getId())
                .addPathInfo(JetspeedResources.PATH_PORTLETID_KEY, entries[j].getId())
                .addQueryData(JetspeedResources.PATH_ACTION_KEY, "controls.Maximize")
                .addQueryData(ALEipConstants.MODE, mode)
                .addQueryData(ALEipConstants.ENTITY_ID, entityid)
                .addQueryData("sch", schedulePortletId);
            int jmode = ((JetspeedRunData) rundata).getMode();
            if (jmode == JetspeedRunData.MAXIMIZE) {
              duri.addQueryData("prev", JetspeedRunData.MAXIMIZE);
            } else {
              duri.addQueryData("prev", JetspeedRunData.NORMAL);
            }
            return duri.toString();
          }
        }
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
    return null;
  }

  public static String getPortletURItoTodoDetailPaneForCell(RunData rundata, String portletEntryName, long entityid, String schedulePortletId) {
    return getPortletURItoTodoModePaneForCell(rundata, portletEntryName, entityid, schedulePortletId, "detail");
  }

  public static String getPortletURItoTodoModePaneForCell(RunData rundata, String portletEntryName, long entityid, String schedulePortletId, String mode) {
    if (mode == null || "".equals(mode)) {
      return null;
    }

    try {
      Portlets portlets = ((JetspeedRunData) rundata).getProfile().getDocument().getPortlets();
      if (portlets == null) {
        return null;
      }

      Entry[] entries = portlets.getEntriesArray();
      if (entries == null || entries.length <= 0) {
        return null;
      }

      int ent_length = entries.length;
      for (int j = 0; j < ent_length; j++) {
        if (entries[j].getParent().equals(portletEntryName)) {
          JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);

          DynamicURI duri = jsLink.getLink(JetspeedLink.CURRENT, null, null, JetspeedLink.CURRENT, null);
          duri =
            duri
              .addPathInfo(JetspeedResources.PATH_PORTLETID_KEY, entries[j].getId())
              .addQueryData(JetspeedResources.PATH_ACTION_KEY, "controls.Maximize")
              .addQueryData(ALEipConstants.MODE, mode)
              .addQueryData(ALEipConstants.ENTITY_ID, entityid)
              .addQueryData("sch", schedulePortletId);
          return duri.toString();
        }
      }

    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
    return null;
  }

  /**
   * 指定した2つの日付を比較する．
   * 
   * @param date1
   * @param date2
   * @param checkTime
   *          時間まで比較する場合，true．
   * @return 等しい場合，true．
   */
  public static boolean equalsToDate(Date date1, Date date2, boolean checkTime) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    int date1Year = cal.get(Calendar.YEAR);
    int date1Month = cal.get(Calendar.MONTH) + 1;
    int date1Day = cal.get(Calendar.DATE);
    int date1Hour = cal.get(Calendar.HOUR);
    int date1Minute = cal.get(Calendar.MINUTE);
    cal.setTime(date2);
    int date2Year = cal.get(Calendar.YEAR);
    int date2Month = cal.get(Calendar.MONTH) + 1;
    int date2Day = cal.get(Calendar.DATE);
    int date2Hour = cal.get(Calendar.HOUR);
    int date2Minute = cal.get(Calendar.MINUTE);
    if (checkTime) {
      if (date1Year == date2Year && date1Month == date2Month && date1Day == date2Day && date1Hour == date2Hour && date1Minute == date2Minute) {
        return true;
      }
    } else {
      if (date1Year == date2Year && date1Month == date2Month && date1Day == date2Day) {
        return true;
      }
    }
    return false;
  }

  /**
   * 指定した2つの日付を比較する．
   * 
   * @param date1
   * @param date2
   * @return
   */
  public static int compareToDate(Date date1, Date date2) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    int date1Year = cal.get(Calendar.YEAR);
    int date1Month = cal.get(Calendar.MONTH) + 1;
    int date1Day = cal.get(Calendar.DATE);
    cal.setTime(date2);
    int date2Year = cal.get(Calendar.YEAR);
    int date2Month = cal.get(Calendar.MONTH) + 1;
    int date2Day = cal.get(Calendar.DATE);

    if (date1Year == date2Year && date1Month == date2Month && date1Day == date2Day) {
      return 0;
    }

    if (date1Year < date2Year) {
      return 1;
    } else if (date2Year > date1Year) {
      return -1;
    } else {
      if (date1Month < date2Month) {
        return 1;
      } else if (date2Month > date1Month) {
        return -1;
      } else {
        if (date1Day < date2Day) {
          return 1;
        } else {
          return -1;
        }
      }
    }
  }

  /**
   * 指定した2つの時刻のみを比較する．
   * 
   * @param date1
   * @param date2
   * @return
   */
  public static int compareTime(Date date1, Date date2) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    int date1Hour = cal.get(Calendar.HOUR_OF_DAY);
    int date1Minute = cal.get(Calendar.MINUTE);
    cal.setTime(date2);
    int date2Hour = cal.get(Calendar.HOUR_OF_DAY);
    int date2Minute = cal.get(Calendar.MINUTE);

    if (date1Hour == date2Hour && date1Minute == date2Minute) {
      return 0;
    }

    if (date1Hour < date2Hour) {
      return 1;
    } else if (date1Hour > date2Hour) {
      return -1;
    } else {
      if (date1Minute < date2Minute) {
        return 1;
      } else {
        return -1;
      }
    }

  }

  /**
   * アクセスしてきたユーザが利用するブラウザ名が Windows の MSIE であるかを判定する．
   * 
   * @param rundata
   * @return MSIE の場合は，true．
   */
  public static boolean isMsieBrowser(RunData rundata) {
    // String os = "Win";
    String browserNames = "MSIE";

    // User-Agent の取得
    String userAgent = rundata.getRequest().getHeader("User-Agent");
    if (userAgent == null || userAgent.equals("")) {
      return false;
    }

    if (userAgent.indexOf("Win") < 0) {
      return false;
    }

    if (userAgent.indexOf(browserNames) > 0) {
      return true;
    }
    return false;
  }

  /**
   * ダミースケジュールを登録する．
   * 
   * @param schedule
   * @param ownerid
   * @param startDate
   * @param endDate
   * @param memberIdList
   * @throws ALDBErrorException
   */
  public static void insertDummySchedule(EipTSchedule schedule, int ownerid, Date startDate, Date endDate, int[] memberIdList, int[] facilityIdList)
      throws ALDBErrorException {

    // ダミーのスケジュールを登録する．
    EipTSchedule dummySchedule = Database.create(EipTSchedule.class);

    // 親スケジュール ID
    dummySchedule.setParentId(schedule.getScheduleId());
    // 予定
    dummySchedule.setName("dummy");
    // 場所
    dummySchedule.setPlace("");
    // 内容
    dummySchedule.setNote("");
    // 公開フラグ
    dummySchedule.setPublicFlag("P");
    // 共有メンバーによる編集／削除フラグ
    dummySchedule.setEditFlag("F");
    // オーナーID
    dummySchedule.setOwnerId(Integer.valueOf(ownerid));
    // 作成日
    Date now2 = new Date();
    dummySchedule.setCreateDate(now2);
    dummySchedule.setCreateUserId(Integer.valueOf(ownerid));
    // 更新日
    dummySchedule.setUpdateDate(now2);
    dummySchedule.setUpdateUserId(Integer.valueOf(ownerid));
    dummySchedule.setRepeatPattern("N");
    dummySchedule.setStartDate(startDate);
    dummySchedule.setEndDate(endDate);

    EipTCommonCategory category = CommonCategoryUtils.getEipTCommonCategory(Long.valueOf(1));

    // orm.doInsert(dummySchedule);
    int size = memberIdList.length;
    for (int i = 0; i < size; i++) {
      EipTScheduleMap map = Database.create(EipTScheduleMap.class);
      int userid = memberIdList[i];
      map.setEipTSchedule(dummySchedule);
      map.setUserId(Integer.valueOf(userid));

      // D: ダミースケジュール
      map.setStatus("D");
      map.setType(ScheduleUtils.SCHEDULEMAP_TYPE_USER);

      map.setCommonCategoryId(Integer.valueOf(1));
      map.setEipTCommonCategory(category);
    }

    if (facilityIdList != null && facilityIdList.length > 0) {
      int fsize = facilityIdList.length;
      for (int i = 0; i < fsize; i++) {
        EipTScheduleMap map = Database.create(EipTScheduleMap.class);
        int fid = facilityIdList[i];
        map.setEipTSchedule(dummySchedule);
        map.setUserId(Integer.valueOf(fid));

        // D: ダミースケジュール
        map.setStatus("D");
        map.setType(ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY);

        map.setCommonCategoryId(Integer.valueOf(1));
        map.setEipTCommonCategory(category);
      }
    }

    // スケジュールを登録
    Database.commit();
  }

  /**
   * ダミースケジュールを登録する（携帯電話対応時には上記のメソッドに変更する）．
   * 
   * @param schedule
   * @param ownerid
   * @param startDate
   * @param endDate
   * @param memberIdList
   * @throws ALDBErrorException
   */
  public static void insertDummySchedule(EipTSchedule schedule, int ownerid, Date startDate, Date endDate, int[] memberIdList) throws ALDBErrorException {

    // ダミーのスケジュールを登録する．
    EipTSchedule dummySchedule = Database.create(EipTSchedule.class);
    // 親スケジュール ID
    dummySchedule.setParentId(schedule.getScheduleId());
    // 予定
    dummySchedule.setName("dummy");
    // 場所
    dummySchedule.setPlace("");
    // 内容
    dummySchedule.setNote("");
    // 公開フラグ
    dummySchedule.setPublicFlag("P");
    // 共有メンバーによる編集／削除フラグ
    dummySchedule.setEditFlag("F");
    // オーナーID
    dummySchedule.setOwnerId(Integer.valueOf(ownerid));
    // 作成日
    Date now2 = new Date();
    dummySchedule.setCreateDate(now2);
    dummySchedule.setCreateUserId(Integer.valueOf(ownerid));
    // 更新日
    dummySchedule.setUpdateDate(now2);
    dummySchedule.setUpdateUserId(Integer.valueOf(ownerid));
    dummySchedule.setRepeatPattern("N");
    dummySchedule.setStartDate(startDate);
    dummySchedule.setEndDate(endDate);

    EipTCommonCategory category = CommonCategoryUtils.getEipTCommonCategory(Long.valueOf(1));

    // // スケジュールを登録
    // orm.doInsert(dummySchedule);
    int size = memberIdList.length;
    for (int i = 0; i < size; i++) {
      EipTScheduleMap map = Database.create(EipTScheduleMap.class);
      int userid = memberIdList[i];
      // map.setPrimaryKey(dummySchedule.getScheduleId(), userid);
      map.setEipTSchedule(dummySchedule);
      map.setUserId(Integer.valueOf(userid));
      // D: ダミースケジュール
      map.setStatus("D");
      map.setType(ScheduleUtils.SCHEDULEMAP_TYPE_USER);

      map.setCommonCategoryId(Integer.valueOf(1));
      map.setEipTCommonCategory(category);
    }

    // スケジュールを登録
    Database.commit();
  }

  public static void insertDummySchedule(EipTSchedule schedule, int ownerid, Date startDate, Date endDate, List<Integer> memberIdList,
      List<Integer> facilityIdList) throws ALDBErrorException {

    // ダミーのスケジュールを登録する．
    EipTSchedule dummySchedule = Database.create(EipTSchedule.class);

    // 親スケジュール ID
    dummySchedule.setParentId(schedule.getScheduleId());
    // 予定
    dummySchedule.setName("dummy");
    // 場所
    dummySchedule.setPlace("");
    // 内容
    dummySchedule.setNote("");
    // 公開フラグ
    dummySchedule.setPublicFlag("P");
    // 共有メンバーによる編集／削除フラグ
    dummySchedule.setEditFlag("F");
    // オーナーID
    dummySchedule.setOwnerId(Integer.valueOf(ownerid));
    // 作成日
    Date now2 = new Date();
    dummySchedule.setCreateDate(now2);
    dummySchedule.setCreateUserId(Integer.valueOf(ownerid));
    // 更新日
    dummySchedule.setUpdateDate(now2);
    dummySchedule.setUpdateUserId(Integer.valueOf(ownerid));
    dummySchedule.setRepeatPattern("N");
    dummySchedule.setStartDate(startDate);
    dummySchedule.setEndDate(endDate);

    EipTCommonCategory category = CommonCategoryUtils.getEipTCommonCategory(Long.valueOf(1));

    // orm.doInsert(dummySchedule);
    int size = memberIdList.size();
    for (int i = 0; i < size; i++) {
      EipTScheduleMap map = Database.create(EipTScheduleMap.class);
      int userid = (memberIdList.get(i)).intValue();
      map.setEipTSchedule(dummySchedule);
      map.setUserId(Integer.valueOf(userid));

      // D: ダミースケジュール
      map.setStatus("D");
      map.setType(ScheduleUtils.SCHEDULEMAP_TYPE_USER);

      map.setCommonCategoryId(Integer.valueOf(1));
      map.setEipTCommonCategory(category);
    }

    if (facilityIdList != null) {
      int fsize = facilityIdList.size();
      for (int i = 0; i < fsize; i++) {
        EipTScheduleMap map = Database.create(EipTScheduleMap.class);
        int fid = (facilityIdList.get(i)).intValue();
        map.setEipTSchedule(dummySchedule);
        map.setUserId(Integer.valueOf(fid));

        // D: ダミースケジュール
        map.setStatus("D");
        map.setType(ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY);

        map.setCommonCategoryId(Integer.valueOf(1));
        map.setEipTCommonCategory(category);
      }
    }

    // スケジュールを登録
    Database.commit();
  }

  // 運用課題No.52
  // add start
  /**
   * 引数のスケジュール一覧を開始時刻の昇順＞終了時刻の昇順でソートする。
   * 
   * @param list
   *          スケジュール一覧
   */
  public static void sortByTimeForResultData(List<ScheduleResultData> list) {
    Collections.sort(list, new Comparator<ScheduleResultData>() {
      private final Calendar cal = Calendar.getInstance();

      @Override
      public int compare(ScheduleResultData o1, ScheduleResultData o2) {
        // 開始時刻を取得
        cal.setTime(o1.getStartDate().getValue());
        int hour1 = cal.get(Calendar.HOUR_OF_DAY);
        int minute1 = cal.get(Calendar.MINUTE);

        cal.setTime(o2.getStartDate().getValue());
        int hour2 = cal.get(Calendar.HOUR_OF_DAY);
        int minute2 = cal.get(Calendar.MINUTE);

        // 開始時刻で比較
        if (hour1 != hour2) {
          return hour1 - hour2;
        } else if (minute1 != minute2) {
          return minute1 - minute2;
        } else {
          // 終了時刻を取得
          cal.setTime(o1.getEndDate().getValue());
          hour1 = cal.get(Calendar.HOUR_OF_DAY);
          minute1 = cal.get(Calendar.MINUTE);

          cal.setTime(o2.getEndDate().getValue());
          hour2 = cal.get(Calendar.HOUR_OF_DAY);
          minute2 = cal.get(Calendar.MINUTE);

          // 終了時刻で比較
          if (hour1 != hour2) {
            return hour1 - hour2;
          } else if (minute1 != minute2) {
            return minute1 - minute2;
          }
        }

        return 0;
      }
    });
  }

  // add end

  // add start No.5 スケジュール印刷（日単位）
  /**
   * 引数のスケジュール一覧を開始時刻の昇順＞終了時刻の降順＞スケジュールIDの昇順でソートする。
   * 
   * @param list
   *          スケジュール一覧
   */
  public static void sortByTimeForResultDataDesc(List<ScheduleResultData> list) {
    Collections.sort(list, new Comparator<ScheduleResultData>() {
      private final Calendar cal = Calendar.getInstance();

      @Override
      public int compare(ScheduleResultData o1, ScheduleResultData o2) {
        // 開始時刻を取得
        cal.setTime(o1.getStartDate().getValue());
        int hour1 = cal.get(Calendar.HOUR_OF_DAY);
        int minute1 = cal.get(Calendar.MINUTE);

        cal.setTime(o2.getStartDate().getValue());
        int hour2 = cal.get(Calendar.HOUR_OF_DAY);
        int minute2 = cal.get(Calendar.MINUTE);

        // 開始時刻で比較
        if (hour1 != hour2) {
          return hour1 - hour2;
        } else if (minute1 != minute2) {
          return minute1 - minute2;
        } else {
          // 終了時刻を取得
          cal.setTime(o1.getEndDate().getValue());
          hour1 = cal.get(Calendar.HOUR_OF_DAY);
          minute1 = cal.get(Calendar.MINUTE);

          cal.setTime(o2.getEndDate().getValue());
          hour2 = cal.get(Calendar.HOUR_OF_DAY);
          minute2 = cal.get(Calendar.MINUTE);

          // 終了時刻で比較
          if (hour1 != hour2) {
            return hour2 - hour1;
          } else if (minute2 != minute1) {
            return minute2 - minute1;
          } else {
            long id1 = o1.getScheduleId().getValue();
            long id2 = o2.getScheduleId().getValue();
            if (id1 != id2) {
              return (int) (id1 - id2);
            }
          }
        }

        return 0;
      }
    });
  }

  // add end

  /**
   * 引数のデータオブジェクトを開始時刻の昇順＞終了時刻の昇順でソートする．
   * 
   * @param list
   *          スケジュールマップ（データオブジェクト）一覧
   */
  public static void sortByTime(List<EipTScheduleMap> list) {
    Collections.sort(list, new Comparator<EipTScheduleMap>() {
      private final Calendar cal = Calendar.getInstance();

      @Override
      public int compare(EipTScheduleMap o1, EipTScheduleMap o2) {
        // 開始時刻を取得
        EipTSchedule s1 = o1.getEipTSchedule();
        cal.setTime(s1.getStartDate());
        int hour1 = cal.get(Calendar.HOUR_OF_DAY);
        int minute1 = cal.get(Calendar.MINUTE);

        EipTSchedule s2 = o2.getEipTSchedule();
        cal.setTime(s2.getStartDate());
        int hour2 = cal.get(Calendar.HOUR_OF_DAY);
        int minute2 = cal.get(Calendar.MINUTE);

        // 開始時刻で比較
        if (hour1 != hour2) {
          return hour1 - hour2;
        } else if (minute1 != minute2) {
          return minute1 - minute2;
        } else {
          // 終了時刻を取得
          cal.setTime(s1.getEndDate());
          hour1 = cal.get(Calendar.HOUR_OF_DAY);
          minute1 = cal.get(Calendar.MINUTE);

          cal.setTime(s2.getEndDate());
          hour2 = cal.get(Calendar.HOUR_OF_DAY);
          minute2 = cal.get(Calendar.MINUTE);

          // 終了時刻で比較
          if (hour1 != hour2) {
            return hour1 - hour2;
          } else if (minute1 != minute2) {
            return minute1 - minute2;
          }
        }

        return 0;
      }
    });
  }

  /**
   * ダミースケジュールが上にくるようにソートする．
   * 
   * @param list
   * @return
   */
  public static List<EipTScheduleMap> sortByDummySchedule(List<EipTScheduleMap> list) {
    // 重複スケジュールの表示調節のために，
    // ダミースケジュールをリストの始めに寄せる．
    List<EipTScheduleMap> dummyList = new ArrayList<EipTScheduleMap>();
    List<EipTScheduleMap> normalList = new ArrayList<EipTScheduleMap>();
    for (EipTScheduleMap scheduleMap : list) {
      if ("D".equals(scheduleMap.getStatus())) {
        dummyList.add(scheduleMap);
      } else {
        normalList.add(scheduleMap);
      }
    }

    List<EipTScheduleMap> newList = new ArrayList<EipTScheduleMap>();
    newList.addAll(dummyList);
    newList.addAll(normalList);
    return newList;
  }

  /**
   * 現在選択しているタブ名を取得する．
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static String getCurrentTab(RunData rundata, Context context) {
    // 自ポートレットからのリクエストであれば、パラメータを展開しセッションに保存する。
    if (ALEipUtils.isMatch(rundata, context)) {
      // 現在選択されているタブ
      // oneday : １日表示
      // weekly : 週間表示
      // monthly: 月間表示
      if (rundata.getParameters().containsKey("tab")) {
        ALEipUtils.setTemp(rundata, context, "tab", rundata.getParameters().getString("tab"));
      }
    }
    String currentTab;
    String tmpCurrentTab = ALEipUtils.getTemp(rundata, context, "tab");
    if (tmpCurrentTab == null
      || !(tmpCurrentTab.equals("oneday") || tmpCurrentTab.equals("weekly") || tmpCurrentTab.equals("monthly") || tmpCurrentTab.equals("oneday-group") || tmpCurrentTab
        .equals("weekly-group"))) {
      currentTab = "oneday";
    } else {
      currentTab = tmpCurrentTab;
    }
    return currentTab;
  }

  /**
   * Date のオブジェクトを指定した形式の文字列に変換する．
   * 
   * @param date
   * @param dateFormat
   * @return
   */
  public static String translateDate(Date date, String dateFormat) {
    if (date == null) {
      return "Unknown";
    }

    // 日付を表示形式に変換
    SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
    sdf.setTimeZone(TimeZone.getDefault());
    return sdf.format(date);
  }

  /**
   * 指定した曜日が，選択範囲に入っているかを検証する．
   * 
   * @param selectedWeek
   *          指定曜日
   * @param startWeek
   *          期間開始曜日
   * @param endWeek
   *          期間終了曜日
   * @return 選択範囲に入っている場合，true．
   */
  public static boolean includeWeek(int selectedWeek, int startWeek, int endWeek) {
    if (startWeek <= endWeek) {
      if (startWeek <= selectedWeek && selectedWeek <= endWeek) {
        return true;
      } else {
        return false;
      }
    } else {
      if (selectedWeek < startWeek && endWeek < selectedWeek) {
        return false;
      } else {
        return true;
      }
    }
  }

  /**
   * 第一引数のリストに，第二引数で指定したユーザ ID が含まれているかを検証する．
   * 
   * @param memberIdList
   * @param memberId
   * @return
   */
  public static boolean isContains(List<Integer> memberIdList, int userId) {
    int size = memberIdList.size();
    Integer tmpInt = null;
    for (int i = 0; i < size; i++) {
      tmpInt = memberIdList.get(i);
      if (userId == tmpInt.intValue()) {
        return true;
      }
    }
    return false;
  }

  /**
   * 第一引数のリストに，第二引数で指定したユーザ ID が含まれているかを検証する．
   * 
   * @param memberIdList
   * @param memberId
   * @return
   */
  public static boolean isContains(List<ALEipUser> memberList, ALEipUser user) {
    int size = memberList.size();
    long userid = user.getUserId().getValue();
    ALEipUser member = null;
    for (int i = 0; i < size; i++) {
      member = memberList.get(i);
      if (member.getUserId().getValue() == userid) {
        return true;
      }
    }
    return false;
  }

  public static boolean removeUser(List<ALEipUser> memberList, ALEipUser user) {
    if (memberList == null || memberList.size() == 0 || user == null) {
      return false;
    }

    int index = -1;
    int size = memberList.size();
    long userid = user.getUserId().getValue();
    ALEipUser member = null;
    for (int i = 0; i < size; i++) {
      member = memberList.get(i);
      if (member.getUserId().getValue() == userid) {
        index = i;
        break;
      }
    }

    if (index >= 0) {
      memberList.remove(index);
      return true;
    } else {
      return false;
    }
  }

  public static EipTScheduleMap getScheduleMap(List<EipTScheduleMap> scheduleMaps, int userid) {
    EipTScheduleMap map = null;
    int size = scheduleMaps.size();
    for (int i = 0; i < size; i++) {
      map = scheduleMaps.get(i);
      if (map.getUserId().intValue() == userid) {
        return map;
      }
    }
    return null;
  }

  // add start
  /**
   * 携帯スケジュール用の日付フィールド入力チェック用メソッド
   */
  // add end
  public static boolean setFormDataDelegate(RunData rundata, Context context, ALData formdata, Field[] fields, List<String> msgList)
      throws ALPageNotFoundException, ALDBErrorException {
    if (fields == null || fields.length == 0) {
      return false;
    }

    boolean res = false;

    try {
      String FORMAT_DATE = "yyyyMMdd";
      String FORMAT_TIME = "HHmm";
      int FORMAT_DATE_LEN = FORMAT_DATE.length();
      int FORMAT_TIME_LEN = FORMAT_TIME.length();

      int length = fields.length;
      for (int i = 0; i < length; i++) {
        fields[i].setAccessible(true);
        String name = fields[i].getName();
        Object obj = fields[i].get(formdata);
        // フィールドが ALCellDateTimeField の場合
        if (obj instanceof ALCellDateTimeField) {
          String dateString = new StringBuffer().append(name).append("_date").toString();
          String timeString = new StringBuffer().append(name).append("_time").toString();

          ALCellDateTimeField field = (ALCellDateTimeField) obj;
          String dateStr = null;
          String timeStr = null;
          Calendar cal = Calendar.getInstance();
          if (rundata.getParameters().containsKey(dateString)) {
            dateStr = rundata.getParameters().getString(dateString);
          } else {
            continue;
          }
          if (rundata.getParameters().containsKey(timeString)) {
            timeStr = rundata.getParameters().getString(timeString);
          } else {
            continue;
          }

          // add start
          if (null == dateStr || "".equals(dateStr)) {
            // 未入力の場合
            if (CellScheduleUtils.SCHEDULE_TYPE_SPAN.equals(rundata.getParameters().getString("schedule_type"))
              || CellScheduleUtils.SCHEDULE_TYPE_CROSS_OVER.equals(rundata.getParameters().getString("schedule_type"))) {
              // 期間スケジュールもしくは日またぎ
              if ("start_date_date".equals(dateString)) {
                // 開始日が入力パターン以外の場合
                msgList.add("『 開始日 』を入力してください。");
              } else {
                // 終了日が入力パターン以外の場合
                msgList.add("『 終了日 』を入力してください。");
              }
            } else {
              msgList.add("『 日付 』を入力してください。");
            }
            continue;
          }
          // add end
          if (dateStr.length() != FORMAT_DATE_LEN) {
            // 文字列の長さが正しくない場合
            // change start
            // msgList.add("『日付』で入力された年月日は存在しません");
            if (CellScheduleUtils.SCHEDULE_TYPE_SPAN.equals(rundata.getParameters().getString("schedule_type"))
              || CellScheduleUtils.SCHEDULE_TYPE_CROSS_OVER.equals(rundata.getParameters().getString("schedule_type"))) {
              // 期間スケジュールもしくは日またぎ
              if ("start_date_date".equals(dateString)) {
                // 開始日が入力パターン以外の場合
                msgList.add("『 開始日 』を正しく入力してください。");
              } else {
                // 終了日が入力パターン以外の場合
                msgList.add("『 終了日 』を正しく入力してください。");
              }
            } else {
              msgList.add("『 日付 』を正しく入力してください。");
            }
            // change end
            continue;
          }

          if (timeStr.length() != FORMAT_TIME_LEN) {
            // 文字列の長さが正しくない場合
            // change start
            // msgList.add("『時間』で入力された時間は存在しません");
            if ("end_date_time".equals(timeString)) {
              msgList.add("終了時刻には23:59までの時刻を入力してください。");
            } else {
              msgList.add("開始時刻には23:59までの時刻を入力してください。");
            }
            // change end
            continue;
          }

          List<String> tmpList = new ArrayList<String>();

          ALCellStringField sf = new ALCellStringField(dateStr);
          sf.setTrim(true);
          sf.setCharacterType(ALStringField.TYPE_NUMBER);
          sf.setValue(dateStr);
          sf.validate(tmpList);
          if (tmpList.size() != 0) {
            // change start
            // msgList.add("『日付』で入力された年月日は存在しません");
            if (CellScheduleUtils.SCHEDULE_TYPE_SPAN.equals(rundata.getParameters().getString("schedule_type"))
              || CellScheduleUtils.SCHEDULE_TYPE_CROSS_OVER.equals(rundata.getParameters().getString("schedule_type"))) {
              // 期間スケジュールもしくは日またぎ
              if ("start_date_date".equals(dateString)) {
                // 開始日が入力パターン以外の場合
                msgList.add("『 開始日 』を正しく入力してください。");
              } else {
                // 終了日が入力パターン以外の場合
                msgList.add("『 終了日 』を正しく入力してください。");
              }
            } else {
              msgList.add("『 日付 』を正しく入力してください。");
            }
            // change end
            continue;
          }

          sf = new ALCellStringField(timeStr);
          sf.setTrim(true);
          sf.setCharacterType(ALStringField.TYPE_NUMBER);
          sf.setValue(timeStr);
          sf.validate(tmpList);
          if (tmpList.size() != 0) {
            // change start
            // msgList.add("『時間』で入力された時間は存在しません");
            if ("end_date_time".equals(timeString)) {
              msgList.add("終了時刻には23:59までの時刻を入力してください。");
            } else if ("start_date_time".equals(timeString)) {
              msgList.add("開始時刻には23:59までの時刻を入力してください。");
            }
            // change end
            continue;
          }

          Date date = null;
          // 日付を表示形式に変換
          SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE);
          sdf.setLenient(false);
          sdf.setTimeZone(TimeZone.getDefault());
          if (!dateStr.equals("")) {
            try {
              date = sdf.parse(dateStr);
            } catch (Exception e) {
              // change start
              // msgList.add("『日付』で入力された年月日は存在しません");
              if (CellScheduleUtils.SCHEDULE_TYPE_SPAN.equals(rundata.getParameters().getString("schedule_type"))
                || CellScheduleUtils.SCHEDULE_TYPE_CROSS_OVER.equals(rundata.getParameters().getString("schedule_type"))) {
                // 期間スケジュールもしくは日またぎ
                if ("start_date_date".equals(dateString)) {
                  // 開始日が入力パターン以外の場合
                  msgList.add("『 開始日 』を正しく入力してください。");
                } else {
                  // 終了日が入力パターン以外の場合
                  msgList.add("『 終了日 』を正しく入力してください。");
                }
              } else {
                msgList.add("『 日付 』を正しく入力してください。");
              }
              // change end
              continue;
            }
          } else {
            continue;
          }
          Date time = null;
          SimpleDateFormat sdf2 = new SimpleDateFormat(FORMAT_TIME);
          sdf2.setLenient(false);
          sdf2.setTimeZone(TimeZone.getDefault());
          if (!timeStr.equals("")) {
            try {
              time = sdf2.parse(timeStr);
            } catch (Exception e) {
              // change start
              // msgList.add("『時間』で入力された時間は存在しません");
              if ("end_date_time".equals(timeString)) {
                msgList.add("終了時刻には23:59までの時刻を入力してください。");
              } else if ("start_date_time".equals(timeString)) {
                msgList.add("開始時刻には23:59までの時刻を入力してください。");
              }
              // change end
              continue;
            }
          } else {
            continue;
          }

          Calendar cal2 = Calendar.getInstance();
          cal2.setTime(time);

          cal.setLenient(false);
          cal.setTime(date);
          cal.set(Calendar.HOUR_OF_DAY, cal2.get(Calendar.HOUR_OF_DAY));
          cal.set(Calendar.MINUTE, cal2.get(Calendar.MINUTE));
          cal.set(Calendar.SECOND, 0);
          cal.set(Calendar.MILLISECOND, 0);

          field.setValue(cal.getTime());

          // フィールドが ALCellDateField の場合
        } else if (obj instanceof ALCellDateField) {
          ALCellDateField field = (ALCellDateField) obj;
          Date date = null;
          ALDateContainer con = new ALDateContainer();
          String dateString = new StringBuffer().append(name).toString();
          String dateStr = null;
          if (rundata.getParameters().containsKey(name)) {
            dateStr = rundata.getParameters().getString(dateString);
          } else {
            continue;
          }
          // add start
          if (null == dateStr || "".equals(dateStr)) {
            // 未入力の場合
            // msgList.add("『日付』で入力された年月日は存在しません");
            if ("limit_start_date".equals(dateString)) {
              // 繰り返しスケジュール開始日が入力パターン以外の場合
              msgList.add("『 開始日 』を入力してください。");
            } else if ("start_date_date".equals(dateString)) {
              // 1日スケジュール開始日が未入力の場合
              msgList.add("『 日付 』を入力してください。");
            } else if ("limit_end_date".equals(dateString)) {
              if ("date".equals(rundata.getParameters().getString("limit_flag"))) {
                // 繰り返しスケジュール終了日が未入力パターン以外の場合
                msgList.add("『 終了日 』を入力してください。");
              }
            }
            continue;
          }
          // add end
          if (dateStr.length() != FORMAT_DATE_LEN) {
            // 文字列の長さが正しくない場合
            // change start
            // 繰り返し終了日は選択によっては未入力の場合があるのでここではチェックしない
            // msgList.add("『日付』で入力された年月日は存在しません");
            if ("limit_start_date".equals(dateString)) {
              // 繰り返しスケジュール開始日が入力パターン以外の場合
              msgList.add("『 開始日 』を正しく入力してください。");
            } else if ("start_date_date".equals(dateString)) {
              // 1日スケジュール開始日が未入力の場合
              msgList.add("『 日付 』を正しく入力してください。");
            } else if ("limit_end_date".equals(dateString)) {
              if ("date".equals(rundata.getParameters().getString("limit_flag"))) {
                // 繰り返しスケジュール終了日が未入力パターン以外の場合
                msgList.add("『 終了日 』を正しく入力してください。");
              }
            }
            // change end
            continue;
          }

          List<String> tmpList = new ArrayList<String>();
          ALCellStringField sf = new ALCellStringField(dateStr);
          sf.setTrim(true);
          sf.setCharacterType(ALStringField.TYPE_NUMBER);
          sf.setValue(dateStr);
          sf.validate(tmpList);
          if (tmpList.size() != 0) {
            // change start
            // msgList.add("『日付』で入力された年月日は存在しません");
            if ("limit_start_date".equals(dateString)) {
              // 繰り返しスケジュール開始日が入力パターン以外の場合
              msgList.add("『 開始日 』を正しく入力してください。");
            } else if ("start_date_date".equals(dateString)) {
              // 1日スケジュール開始日が未入力の場合
              msgList.add("『 日付 』を正しく入力してください。");
            } else if ("limit_end_date".equals(dateString)) {
              if ("date".equals(rundata.getParameters().getString("limit_flag"))) {
                // 繰り返しスケジュール終了日が未入力パターン以外の場合
                msgList.add("『 終了日 』を正しく入力してください。");
              }
            }
            // change end
            continue;
          }

          // 日付を表示形式に変換
          SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE);
          sdf.setLenient(false);
          sdf.setTimeZone(TimeZone.getDefault());
          try {
            date = sdf.parse(dateStr);
          } catch (Exception e) {
            // change start
            // msgList.add("『日付』で入力された年月日は存在しません");
            if ("limit_start_date".equals(dateString)) {
              // 繰り返しスケジュール開始日が入力パターン以外の場合
              msgList.add("『 開始日 』を正しく入力してください。");
            } else if ("start_date_date".equals(dateString)) {
              // 1日スケジュール開始日が未入力の場合
              msgList.add("『 日付 』を正しく入力してください。");
            } else if ("limit_end_date".equals(dateString)) {
              if ("date".equals(rundata.getParameters().getString("limit_flag"))) {
                // 繰り返しスケジュール終了日が未入力パターン以外の場合
                msgList.add("『 終了日 』を正しく入力してください。");
              }
            }
            // change end
            continue;
          }

          Calendar cal = Calendar.getInstance();
          cal.setLenient(false);
          cal.setTime(date);
          cal.set(Calendar.HOUR_OF_DAY, 0);
          cal.set(Calendar.MINUTE, 0);
          cal.set(Calendar.SECOND, 0);
          cal.set(Calendar.MILLISECOND, 0);

          con.setYear(cal.get(Calendar.YEAR));
          con.setMonth(cal.get(Calendar.MONTH) + 1);
          con.setDay(cal.get(Calendar.DATE));
          field.setValue(con);

          // フィールドが ALAbstractField の場合
        } else if (obj instanceof ALAbstractField) {
          ALAbstractField field = (ALAbstractField) obj;
          if (rundata.getParameters().containsKey(name)) {
            field.setValue(rundata.getParameters().getString(name));
          }
        }
      }

      res = true;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return res;
  }

  /**
   * パラメータを読み込みます。
   * 
   * @param rundata
   * @param context
   */
  public static void loadParametersDelegate(RunData rundata, Context context, String tmpStart, String tmpEnd, String tmpView) {
    ALDateTimeField dummy = new ALDateTimeField("yyyy-MM-dd-HH-mm");
    dummy.setNotNull(true);
    if (ALEipUtils.isMatch(rundata, context)) {
      Calendar cal = Calendar.getInstance();
      int min = cal.get(Calendar.MINUTE);
      if (min <= 15) {
        cal.set(Calendar.MINUTE, 15);
      } else if (min <= 30) {
        cal.set(Calendar.MINUTE, 30);
      } else if (min <= 45) {
        cal.set(Calendar.MINUTE, 45);
      } else {
        cal.set(Calendar.MINUTE, 60);
      }
      Date now = cal.getTime();

      if (rundata.getParameters().containsKey("form_start")) {
        tmpStart = rundata.getParameters().getString("form_start");
        ALEipUtils.setTemp(rundata, context, "tmpStart", tmpStart);
        dummy.setValue(tmpStart);
        if (!dummy.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, "form_start");
          ALEipUtils.removeTemp(rundata, context, "form_end");
          logger.debug("[ScheduleFormData] Parameter cannot validate");
          ALEipUtils.redirectPageNotFound(rundata);
          return;
        }
      } else {
        dummy.setValue(now);
        ALEipUtils.setTemp(rundata, context, "tmpStart", dummy.toString());
      }
      if (rundata.getParameters().containsKey("form_end")) {
        tmpEnd = rundata.getParameters().getString("form_end");
        ALEipUtils.setTemp(rundata, context, "tmpEnd", tmpEnd);
        dummy.setValue(tmpEnd);
        if (!dummy.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, "form_start");
          ALEipUtils.removeTemp(rundata, context, "form_end");
          logger.debug("[ScheduleFormData] Parameter cannot validate");
          ALEipUtils.redirectPageNotFound(rundata);
          return;
        }
      } else {
        dummy.setValue(now);
        ALEipUtils.setTemp(rundata, context, "tmpEnd", dummy.toString());
      }
    }
    tmpStart = ALEipUtils.getTemp(rundata, context, "tmpStart");
    // tmpEnd = ALEipUtils.getTemp(rundata, context, "tmpEnd");
    loadParametersViewDate(rundata, context, tmpStart, tmpView);
  }

  public static void loadParametersViewDate(RunData rundata, Context context, String tmpStart, String tmpView) {
    if (ALEipUtils.isMatch(rundata, context)) {
      if (rundata.getParameters().containsKey("view_date")) {
        ALDateTimeField dummy = new ALDateTimeField("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;
        }
      } else {
        if (tmpView == null || tmpView.equals("")) {
          if (tmpStart != null && !tmpStart.equals("")) {
            tmpView = tmpStart;
            ALEipUtils.setTemp(rundata, context, "tmpView", tmpView);
          }
        }
      }
    }
  }

  // add start
  /**
   * スケジュール作成(編集)入力チェック（繰り返しパターン拡張版）
   * 
   * @param is_repeat
   *          繰り返しフラグ
   * @param is_span
   *          期間フラグ
   * @param is_straddle
   *          日またぎフラグ
   * @param start_date
   *          開始日時
   * @param end_date
   *          終了日時
   * @param repeat_type
   *          繰り返しパターン
   * @param day_interval
   *          日間隔（日パターンのみ）
   * @param week_intervall
   *          週間隔（週パターンのみ）
   * @param weekDoWList
   *          曜日チェック一覧（週パターンのみ）
   * @param month_type
   *          月パターン
   * @param md_month_interval
   *          月間隔（月・日パターンのみ）
   * @param mw_month_interval
   *          月間隔（月・曜日パターンのみ）
   * @param limit_type
   *          有効期限終了パターン（繰り返しのみ）
   * @param limit_start_date
   *          有効期限開始日（繰り返しのみ）
   * @param limit_end_date
   *          有効期限終了日（繰り返しのみ）
   * @param repeat_num
   *          反復回数（有効期限終了パターン：反復回数のみ）
   * @param msgList
   *          エラーメッセージ一覧
   * @return エラーメッセージが1つ以上の場合false。そうでない場合true。
   * @throws ALPageNotFoundException
   *           有効期限の日付変換に失敗した場合
   */
  public static boolean validateDelegate(boolean is_repeat, boolean is_span, boolean is_straddle, ALDateTimeField start_date, ALDateTimeField end_date,
      ALStringField repeat_type, ALNumberField day_interval, ALNumberField week_interval, List<String> weekDoWList, ALStringField month_type,
      ALNumberField md_month_interval, ALNumberField mw_month_interval, ALStringField limit_type, ALDateField limit_start_date, ALDateField limit_end_date,
      ALNumberField repeat_num, List<String> msgList) throws ALPageNotFoundException {

    // 開始日時（主に時刻）
    boolean canStartDateCheck = start_date.validate(msgList);
    // 終了日時（主に時刻）
    boolean canEndDateCheck = end_date.validate(msgList);

    // 運用課題No.51
    // 日付不正値の対応
    final String YEAR_ERR = "『 <span class='em'>%1$s</span> 』の取得に失敗しました。当ウインドウを閉じて入力をやり直してください。";
    if (is_repeat) {
      // (繰り返し予定)有効期限開始年の不正値チェック
      if (null == limit_start_date.getYear() || "".equals(limit_start_date.getYear()) || Integer.parseInt(limit_start_date.getYear()) < 2000) {
        msgList.add(String.format(YEAR_ERR, "繰り返し期間開始年"));
        return false;
      }
      // (繰り返し予定)有効期限終了年の不正値チェック
      if (ScheduleConst.LIMIT_TYPE_DATE.equals(limit_type.getValue())
        && (null == limit_end_date.getYear() || "".equals(limit_end_date.getYear()) || Integer.parseInt(limit_end_date.getYear()) < 2000)) {
        msgList.add(String.format(YEAR_ERR, "繰り返し期間終了年"));
        return false;
      }
    } else {
      // (繰り返し以外)開始年の不正値チェック
      if (canStartDateCheck && (null == start_date.getYear() || "".equals(start_date.getYear()) || Integer.parseInt(start_date.getYear()) < 2000)) {
        msgList.add(String.format(YEAR_ERR, "開始年"));
        return false;
      }
      // (繰り返し以外)終了年の不正値チェック
      if (canEndDateCheck && (null == end_date.getYear() || "".equals(end_date.getYear()) || Integer.parseInt(end_date.getYear()) < 2000)) {
        msgList.add(String.format(YEAR_ERR, "終了年"));
        return false;
      }
    }

    // 開始日時＆終了日時
    if (canStartDateCheck && canEndDateCheck && is_span) {
      // 期間予定
      if (end_date.getValue().before(start_date.getValue())) {
        msgList.add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span> 』以降の日付を指定してください。");
      }
    } else if (canStartDateCheck && canEndDateCheck && is_straddle) {
      // 日またぎ予定
      if (end_date.getValue().before(start_date.getValue()) || ScheduleUtils.equalsToDate(start_date.getValue(), end_date.getValue(), false)) {
        msgList.add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span> 』以降の日時を指定してください。");
      }
    } else {
      // 単発または繰り返し
      if (end_date.getValue().before(start_date.getValue())) {
        msgList.add("『 <span class='em'>終了時刻</span> 』は『 <span class='em'>開始時刻</span> 』以降の時刻を指定してください。");
      }
    }

    // 繰り返し予定
    if (is_repeat) {
      if (ScheduleConst.REPEAT_TYPE_DAY.equals(repeat_type.getValue())) {
        // 日パターン
        day_interval.validate(msgList);
      } else if (ScheduleConst.REPEAT_TYPE_WEEK.equals(repeat_type.getValue())) {
        // 週パターン
        week_interval.validate(msgList);
        boolean hasChecked = false;
        for (String dow : weekDoWList) {
          if (ScheduleConst.DOW_CHECKED.equals(dow)) {
            hasChecked = true;
            break;
          }
        }
        if (!hasChecked) {
          msgList.add("曜日をひとつ以上指定してください。");
        }
      } else if (ScheduleConst.REPEAT_TYPE_MONTH.equals(repeat_type.getValue())) {
        // 月パターン
        if (ScheduleConst.MONTH_TYPE_MD.equals(month_type.getValue())) {
          // 月・日パターン
          md_month_interval.validate(msgList);
        } else {
          // 月・曜日パターン
          mw_month_interval.validate(msgList);
        }
      }

      // 有効期限
      if (ScheduleConst.LIMIT_TYPE_NOFT.equals(limit_type.getValue())) {
        // 反復回数
        repeat_num.validate(msgList);
      } else if (ScheduleConst.LIMIT_TYPE_DATE.equals(limit_type.getValue())) {
        // 終了日
        try {
          if (!ScheduleUtils.equalsToDate(limit_start_date.getValue().getDate(), limit_end_date.getValue().getDate(), false)
            && limit_start_date.getValue().getDate().after(limit_end_date.getValue().getDate())) {
            msgList.add("『 <span class='em'>繰り返し期間終了日</span> 』は『 <span class='em'>繰り返し期間開始日</span> 』以降の日付を指定してください。");
          }
        } catch (Exception e) {
          // カレンダーウィジットで登録するため、不正日付は想定外
          String limitStartDateStr = "";
          String limitEndDateStr = "";
          if (null != limit_start_date) {
            limitStartDateStr = limit_start_date.toString();
          }
          if (null != limit_end_date) {
            limitEndDateStr = limit_end_date.toString();
          }
          logger.error("繰り返し期間の日付変換でエラーが発生しました。繰り返し期間開始日:" + limitStartDateStr + "/繰り返し期間終了日:" + limitEndDateStr, e);
          throw new ALPageNotFoundException();
        }
      }
    }
    return msgList.size() == 0;
  }

  // add end

  // change start
  // 携帯版でも
  // スケジュール作成(編集)入力チェック（繰り返しパターン拡張版）を使用する
  //
  // /**
  // * スケジュールの時刻系要素バリデーション処理移譲メソッド
  // *
  // * @param start_date
  // * @param end_date
  // * @param repeat_type
  // * @param is_repeat
  // * @param is_span
  // * @param week_0
  // * @param week_1
  // * @param week_2
  // * @param week_3
  // * @param week_4
  // * @param week_5
  // * @param week_6
  // * @param limit_flag
  // * @param limit_start_date
  // * @param limit_end_date
  // * @param month_day
  // * @param login_user
  // * @param entityid
  // * @param msgList
  // * エラーメッセージリスト
  // * @param isCellPhone
  // * 携帯電話かどうか
  // * @return
  // * @throws ALDBErrorException
  // * @throws ALPageNotFoundException
  // */
  // public static boolean validateDelegate(ALDateTimeField start_date,
  // ALDateTimeField end_date, ALStringField repeat_type, boolean is_repeat,
  // boolean is_span, ALStringField week_0, ALStringField week_1,
  // ALStringField week_2, ALStringField week_3, ALStringField week_4,
  // ALStringField week_5, ALStringField week_6, ALStringField limit_flag,
  // ALDateField limit_start_date, ALDateField limit_end_date,
  // ALNumberField month_day, ALEipUser login_user, String entityid,
  // List<String> msgList, boolean isCellPhone) throws ALDBErrorException,
  // ALPageNotFoundException {
  //
  // int YEAR_FIRST = 2004;
  // int YEAR_END = 2016;
  //
  // if (end_date == null) {
  // msgList.add("終了日時を正しく入力してください。");
  // end_date = start_date;
  // }
  //
  // Calendar startDate = Calendar.getInstance();
  // startDate.setTime(start_date.getValue());
  // Calendar endDate = Calendar.getInstance();
  // endDate.setTime(end_date.getValue());
  //
  // if (is_repeat) {
  // // 開始日時 と 終了日時 の日付を、開始日時 の日付に一致させる
  // Calendar tmp_end_date = Calendar.getInstance();
  // tmp_end_date.set(Calendar.YEAR, Integer.valueOf(start_date.getYear()));
  // tmp_end_date.set(
  // Calendar.MONTH,
  // Integer.valueOf(start_date.getMonth()) - 1);
  // tmp_end_date.set(Calendar.DATE, Integer.valueOf(start_date.getDay()));
  // tmp_end_date.set(Calendar.HOUR_OF_DAY, Integer
  // .valueOf(end_date.getHour()));
  // tmp_end_date.set(Calendar.MINUTE, Integer.valueOf(end_date.getMinute()));
  // tmp_end_date.set(Calendar.SECOND, 0);
  // end_date.setValue(tmp_end_date.getTime());
  // }
  //
  // if (is_span) {
  // // 開始日時 と 終了日時 の時間を 0時0分0秒 に設定する
  // Calendar tmp_start_date = Calendar.getInstance();
  // tmp_start_date.setTime(start_date.getValue());
  // tmp_start_date.set(Calendar.HOUR_OF_DAY, 0);
  // tmp_start_date.set(Calendar.MINUTE, 0);
  // tmp_start_date.set(Calendar.SECOND, 0);
  // start_date.setValue(tmp_start_date.getTime());
  //
  // Calendar tmp_end_date = Calendar.getInstance();
  // tmp_end_date.setTime(end_date.getValue());
  // tmp_end_date.set(Calendar.HOUR_OF_DAY, 0);
  // tmp_end_date.set(Calendar.MINUTE, 0);
  // tmp_end_date.set(Calendar.SECOND, 0);
  // end_date.setValue(tmp_end_date.getTime());
  // }
  //
  // // 開始日時
  // start_date.validate(msgList);
  // int startyear = startDate.get(Calendar.YEAR);
  // if ((startyear < YEAR_FIRST || startyear > YEAR_END) && isCellPhone) {
  // // 携帯画面用条件
  // msgList.add("『 <span class='em'>開始日時</span> 』は"
  // + YEAR_FIRST
  // + "年から"
  // + YEAR_END
  // + "年の間で指定してください。");
  // }
  // if (startDate.get(Calendar.MINUTE) % 15.0 != 0 && isCellPhone) {
  // // 携帯画面用条件
  // msgList.add("『 <span class='em'>開始時間</span> 』は15分単位で指定してください。");
  // }
  //
  // // 終了日時
  // end_date.validate(msgList);
  // int endyear = startDate.get(Calendar.YEAR);
  // if ((endyear < YEAR_FIRST || endyear > YEAR_END) && isCellPhone) {
  // // 携帯画面用条件
  // msgList.add("『 <span class='em'>終了日時</span> 』は"
  // + YEAR_FIRST
  // + "年から"
  // + YEAR_END
  // + "年の間で指定してください。");
  // }
  // if (endDate.get(Calendar.MINUTE) % 15.0 != 0 && isCellPhone) {
  // // 携帯画面用条件
  // msgList.add("『 <span class='em'>終了時間</span> 』は15分単位で指定してください。");
  // }
  //
  // // 開始日時＆終了日時
  // if (is_span) {
  // if (end_date.getValue().before(start_date.getValue())) {
  // msgList
  // .add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span>
  // 』以降の日付を指定してください。");
  // }
  // } else {
  // if (end_date.getValue().before(start_date.getValue())) {
  // msgList
  // .add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span>
  // 』以降の時間を指定してください。");
  // }
  // }
  //
  // if (is_repeat) {
  // try {
  // if ("W".equals(repeat_type.getValue())) {
  // // 毎週の繰り返し
  // if (week_0.getValue() == null
  // && week_1.getValue() == null
  // && week_2.getValue() == null
  // && week_3.getValue() == null
  // && week_4.getValue() == null
  // && week_5.getValue() == null
  // && week_6.getValue() == null) {
  // msgList.add("『 <span class='em'>毎週</span> 』は曜日をひとつ以上指定してください。");
  // }
  // } else if ("M".equals(repeat_type.getValue())) {
  // // 毎月の繰り返し
  // if (month_day.getValue() == 0 && isCellPhone) {
  // // 携帯画面用条件
  // msgList.add("『 <span class='em'>毎月</span> 』は日にちを指定してください。");
  // } else {
  // month_day.validate(msgList);
  // }
  // }
  //
  // if ("ON".equals(limit_flag.getValue())) {
  // if (!ScheduleUtils.equalsToDate(
  // limit_start_date.getValue().getDate(),
  // limit_end_date.getValue().getDate(),
  // false)
  // && limit_start_date.getValue().getDate().after(
  // limit_end_date.getValue().getDate())) {
  // msgList
  // .add("『 <span class='em'>繰り返し期間終了日</span> 』は『 <span
  // class='em'>繰り返し期間開始日</span> 』以降の日付を指定してください。");
  // }
  //
  // if (isCellPhone) {
  // // 携帯画面用条件
  // Calendar limitStartDate = Calendar.getInstance();
  // limitStartDate.setTime(limit_start_date.getValue().getDate());
  // int limitstartyear = limitStartDate.get(Calendar.YEAR);
  // if ((limitstartyear < YEAR_FIRST || limitstartyear > YEAR_END)) {
  // msgList.add("『 <span class='em'>期限の開始日時</span> 』は"
  // + YEAR_FIRST
  // + "年から"
  // + YEAR_END
  // + "年の間で指定してください。");
  // }
  // Calendar limitEndDate = Calendar.getInstance();
  // limitEndDate.setTime(limit_end_date.getValue().getDate());
  // int limitendyear = limitEndDate.get(Calendar.YEAR);
  // if ((limitendyear < YEAR_FIRST || limitendyear > YEAR_END)) {
  // msgList.add("『 <span class='em'>期限の終了日時</span> 』は"
  // + YEAR_FIRST
  // + "年から"
  // + YEAR_END
  // + "年の間で指定してください。");
  // }
  // }
  //
  // // 繰り返し期間の正当性を調べる
  // // リピートパターン文字列作成
  // char lim = 'N';
  // Calendar cal = Calendar.getInstance();
  // cal.setTime(end_date.getValue());
  // if ("ON".equals(limit_flag.getValue())) {
  // lim = 'L';
  // }
  // String repeat_pattern;
  // int date_count = 0;
  // if ("D".equals(repeat_type.getValue())) {
  // repeat_pattern =
  // new StringBuffer().append('D').append(lim).toString();
  // } else if ("W".equals(repeat_type.getValue())) {
  // repeat_pattern =
  // new StringBuffer().append('W').append(
  // week_0.getValue() != null ? 1 : 0).append(
  // week_1.getValue() != null ? 1 : 0).append(
  // week_2.getValue() != null ? 1 : 0).append(
  // week_3.getValue() != null ? 1 : 0).append(
  // week_4.getValue() != null ? 1 : 0).append(
  // week_5.getValue() != null ? 1 : 0).append(
  // week_6.getValue() != null ? 1 : 0).append(lim).toString();
  // date_count =
  // (week_0.getValue() != null ? 1 : 0)
  // + (week_1.getValue() != null ? 1 : 0)
  // + (week_2.getValue() != null ? 1 : 0)
  // + (week_3.getValue() != null ? 1 : 0)
  // + (week_4.getValue() != null ? 1 : 0)
  // + (week_5.getValue() != null ? 1 : 0)
  // + (week_6.getValue() != null ? 1 : 0);
  // } else {
  // DecimalFormat format = new DecimalFormat("00");
  // repeat_pattern =
  // new StringBuffer().append('M').append(
  // format.format(month_day.getValue())).append(lim).toString();
  // date_count = 1;
  // }
  // // 開始時刻(期間初日)
  // Calendar sDate = new GregorianCalendar();
  // sDate.set(Calendar.YEAR, Integer.valueOf(limit_start_date.getYear()));
  // sDate.set(Calendar.MONTH, Integer
  // .valueOf(limit_start_date.getMonth()) - 1);
  // sDate.set(Calendar.DATE, Integer.valueOf(limit_start_date.getDay()));
  // sDate.set(Calendar.HOUR_OF_DAY, 0);
  // sDate.set(Calendar.MINUTE, 0);
  // sDate.set(Calendar.SECOND, 0);
  // // 繰り返し最終日の終了時刻
  // Calendar finalDate = new GregorianCalendar();
  // finalDate.set(Calendar.YEAR, Integer
  // .valueOf(limit_end_date.getYear()));
  // finalDate.set(Calendar.MONTH, Integer.valueOf(limit_end_date
  // .getMonth()) - 1);
  // finalDate
  // .set(Calendar.DATE, Integer.valueOf(limit_end_date.getDay()));
  // finalDate.set(Calendar.HOUR_OF_DAY, 23);
  // finalDate.set(Calendar.MINUTE, 59);
  // finalDate.set(Calendar.SECOND, 59);
  // int countAvailableDate = 0;
  // while (sDate.before(finalDate) || sDate.equals(finalDate)) {
  // if (ScheduleUtils.matchDay(sDate, repeat_pattern)) {
  // countAvailableDate++;
  // if (countAvailableDate >= date_count) {
  // break;
  // }
  // }
  // sDate.add(Calendar.DATE, 1);
  // }
  // if (countAvailableDate < date_count) {
  // msgList
  // .add("予定の入る日が含まれる様に『 <span class='em'>繰り返し期間</span> 』を指定してください。");
  // }
  // }
  //
  // } catch (NumberFormatException nfe) {
  // logger
  // .error("[ScheduleFormData] NumberFormatException: Limit Date is wrong.");
  // throw new ALPageNotFoundException();
  // } catch (ALIllegalDateException ad) {
  // logger
  // .error("[ScheduleFormData] ALIllegalDateException: Limit Date is wrong.");
  // throw new ALPageNotFoundException();
  // }
  // }
  //
  // return (msgList.size() == 0);
  // }
  /**
   * 携帯用スケジュール作成(編集)入力チェック（繰り返しパターン拡張版）
   * 
   * @param is_repeat
   *          繰り返しフラグ
   * @param is_span
   *          期間フラグ
   * @param is_straddle
   *          日またぎフラグ
   * @param start_date
   *          開始日時
   * @param end_date
   *          終了日時
   * @param repeat_type
   *          繰り返しパターン
   * @param day_interval
   *          日間隔（日パターンのみ）
   * @param week_intervall
   *          週間隔（週パターンのみ）
   * @param weekDoWList
   *          曜日チェック一覧（週パターンのみ）
   * @param month_type
   *          月パターン
   * @param md_month_interval
   *          月間隔（月・日パターンのみ）
   * @param mw_month_interval
   *          月間隔（月・曜日パターンのみ）
   * @param limit_type
   *          有効期限終了パターン（繰り返しのみ）
   * @param limit_start_date
   *          有効期限開始日（繰り返しのみ）
   * @param limit_end_date
   *          有効期限終了日（繰り返しのみ）
   * @param repeat_num
   *          反復回数（有効期限終了パターン：反復回数のみ）
   * @param msgList
   *          エラーメッセージ一覧
   * @return エラーメッセージが1つ以上の場合false。そうでない場合true。
   * @param isCellPhone
   *          携帯電話かどうか
   * @throws ALPageNotFoundException
   *           有効期限の日付変換に失敗した場合
   */
  public static boolean validateDelegate(boolean is_repeat, boolean is_span, boolean is_straddle, ALCellDateTimeField start_date, ALCellDateTimeField end_date,
      ALCellStringField repeat_type, ALCellNumberField day_interval, ALCellNumberField week_interval, List<String> weekDoWList, ALCellStringField month_type,
      ALCellNumberField md_month_interval, ALCellNumberField mw_month_interval, ALCellStringField limit_type, ALCellDateField limit_start_date,
      ALCellDateField limit_end_date, ALCellNumberField repeat_num, List<String> msgList, boolean isCellPhone) throws ALPageNotFoundException {

    // 開始日時（主に時刻）
    boolean canStartDateCheck = start_date.validate(msgList);
    // 終了日時（主に時刻）
    boolean canEndDateCheck = end_date.validate(msgList);

    // 開始日時＆終了日時
    if (canStartDateCheck && canEndDateCheck && is_span) {
      // 期間予定
      if (end_date.getValue().before(start_date.getValue())) {
        msgList.add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span> 』以降の日付を指定してください。");
      }
    } else if (canStartDateCheck && canEndDateCheck && is_straddle) {
      // 日またぎ予定
      if (end_date.getValue().before(start_date.getValue()) || ScheduleUtils.equalsToDate(start_date.getValue(), end_date.getValue(), false)) {
        msgList.add("『 <span class='em'>終了日時</span> 』は『 <span class='em'>開始日時</span> 』以降の日時を指定してください。");
      }
    } else {
      // 単発または繰り返し
      if (end_date.getValue().before(start_date.getValue())) {
        msgList.add("『 <span class='em'>終了時刻</span> 』は『 <span class='em'>開始時刻</span> 』以降の時刻を指定してください。");
      }
    }

    // 繰り返し予定
    if (is_repeat) {
      if (ScheduleConst.REPEAT_TYPE_DAY.equals(repeat_type.getValue())) {
        // 日パターン
        day_interval.validate(msgList);
      } else if (ScheduleConst.REPEAT_TYPE_WEEK.equals(repeat_type.getValue())) {
        // 週パターン
        week_interval.validate(msgList);
        boolean hasChecked = false;
        for (String dow : weekDoWList) {
          if (ScheduleConst.DOW_CHECKED.equals(dow)) {
            hasChecked = true;
            break;
          }
        }
        if (!hasChecked) {
          msgList.add("曜日をひとつ以上指定してください。");
        }
      } else if (ScheduleConst.REPEAT_TYPE_MONTH.equals(repeat_type.getValue())) {
        // 月パターン
        if (ScheduleConst.MONTH_TYPE_MD.equals(month_type.getValue())) {
          // 月・日パターン
          md_month_interval.validate(msgList);
        } else {
          // 月・曜日パターン
          mw_month_interval.validate(msgList);
        }
      }
      // 繰り返し期間開始日
      boolean is_limit_start_date = limit_start_date.validate(msgList);
      // 有効期限
      if (ScheduleConst.LIMIT_TYPE_NOFT.equals(limit_type.getValue())) {
        // 反復回数
        repeat_num.validate(msgList);
      } else if (ScheduleConst.LIMIT_TYPE_DATE.equals(limit_type.getValue())) {
        // 終了日
        try {
          // 繰り返し期間終了日
          boolean is_limit_end_date = limit_end_date.validate(msgList);
          if (is_limit_start_date && is_limit_end_date) {
            if (!ScheduleUtils.equalsToDate(limit_start_date.getValue().getDate(), limit_end_date.getValue().getDate(), false)
              && limit_start_date.getValue().getDate().after(limit_end_date.getValue().getDate())) {
              msgList.add("『 <span class='em'>繰り返し期間終了日</span> 』は『 <span class='em'>繰り返し期間開始日</span> 』以降の日付を指定してください。");
            }
          }
        } catch (Exception e) {
          logger.error("繰り返し期間の日付でエラーが発生しました。", e);
          throw new ALPageNotFoundException();
        }
      }
    }
    return msgList.size() == 0;
  }

  // change end

  /**
   * 同一期間内に複数の ToDo を追加する. 第一引数の List を排他制御しないで処理するので注意.
   * 
   * @param weekSpanConList
   *          複数の期間スケジュールを保持するリスト
   * @param viewStartDate
   *          表示開始の年月日
   * @param index
   *          期間スケジュールの追加位置
   * @param rd
   *          期間スケジュール
   */
  public static void addToDo(List<ScheduleToDoWeekContainer> weekConList, Date viewStartDate, int index, ScheduleToDoResultData rd) {
    try {
      boolean success = false;
      if (weekConList.size() > 0) {
        ScheduleToDoWeekContainer tmpWeekCon = null;
        int size = weekConList.size();
        for (int i = 0; i < size; i++) {
          tmpWeekCon = weekConList.get(i);
          success = tmpWeekCon.canAddTodo(rd);
          if (success) {
            tmpWeekCon.addToDoResultData(index, rd);
            break;
          }
        }
      }

      if (!success) {
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(viewStartDate);
        // 週間スケジュールコンテナの初期化
        ScheduleToDoWeekContainer weekCon = new ScheduleToDoWeekContainer();
        weekCon.initField();
        weekCon.setViewStartDate(cal2);
        weekCon.addToDoResultData(index, rd);
        weekConList.add(weekCon);
      }

    } catch (Exception e) {
      logger.error("Exception", e);
    }
  }

  public static boolean isZeroLength(String[] strs) {
    if (strs == null || strs.length <= 0) {
      return true;
    }

    int len = strs.length;
    for (int i = 0; i < len; i++) {
      if (strs[i] == null || "".equals(strs[i])) {
        return true;
      }
    }
    return false;
  }

  public static boolean isSpanDuplicate(int user_id, Date start_date, Date end_date, Integer update_id) {
    SelectQuery<EipTScheduleMap> query = Database.query(EipTScheduleMap.class);

    Expression exp1 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.valueOf(user_id));
    query.setQualifier(exp1);
    Expression exp2 = ExpressionFactory.greaterOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY, start_date);
    query.andQualifier(exp2);
    Expression exp3 = ExpressionFactory.lessOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY, end_date);
    query.andQualifier(exp3);
    Expression exp4 = ExpressionFactory.matchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "S");
    query.andQualifier(exp4);

    if (update_id != null) {
      Expression mapexp = ExpressionFactory.noMatchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, Integer.valueOf(update_id));
      query.andQualifier(mapexp);
    }

    List<EipTScheduleMap> list = query.fetchList();
    int count = (list != null && list.size() > 0) ? list.size() : 0;
    return count > 0;
  }

  public static List<ALEipUser> getALEipUsers(String[] ids) throws ALDBErrorException {

    int ids_len = ids.length;
    Integer tmp_id = null;
    List<Integer> tmp_ids = new ArrayList<Integer>();
    for (int i = 0; i < ids_len; i++) {
      try {
        tmp_id = Integer.valueOf(ids[i]);
        if (tmp_id.intValue() > 3) {
          tmp_ids.add(tmp_id);
        }
      } catch (Exception e) {
      }
    }

    Expression exp = ExpressionFactory.inDbExp(TurbineUser.USER_ID_PK_COLUMN, tmp_ids);
    List<TurbineUser> users = Database.query(TurbineUser.class, exp).fetchList();
    if (users.size() == 0) {
      return null;
    }

    List<ALEipUser> uList = new ArrayList<ALEipUser>();
    TurbineUser tuser = null;
    ALEipUser user = null;
    int len = users.size();
    for (int i = 0; i < len; i++) {
      tuser = users.get(i);
      user = new ALEipUser();
      user.initField();
      user.setUserId(tuser.getUserId().intValue());
      user.setName(tuser.getLoginName());
      user.setAliasName(tuser.getFirstName(), tuser.getLastName());
      uList.add(user);
    }
    return uList;
  }

  public static List<UserFacilityLiteBean> getALEipUserFacility(String[] ids, RunData rundata) throws ALDBErrorException {

    List<UserFacilityLiteBean> ulist = new ArrayList<UserFacilityLiteBean>();

    int ids_len = ids.length;
    Integer tmp_id = null;
    List<Integer> tmp_ids = new ArrayList<Integer>();
    List<String> f_ids = new ArrayList<String>();
    for (int i = 0; i < ids_len; i++) {
      if (ids[i].startsWith("f")) {
        // facilityIDをセット
        f_ids.add(ids[i].replace("f", ""));
      } else {
        // ユーザーID
        try {
          tmp_id = Integer.valueOf(ids[i]);
          if (tmp_id.intValue() > 3) {
            tmp_ids.add(tmp_id);
          }
        } catch (Exception e) {
        }
      }
    }

    UserFacilityLiteBean user = null;
    // tmp_ids と f_ids をつかって
    // ユーザーIDのデータを取得
    if (tmp_ids != null && tmp_ids.size() > 0) {
      StringBuffer tmp_ids_str = new StringBuffer();
      int tmp_ids_len = tmp_ids.size() - 1;
      for (int i = 0; i < tmp_ids_len; i++) {
        tmp_ids_str.append(tmp_ids.get(i)).append(",");
      }
      tmp_ids_str.append(tmp_ids.get(tmp_ids_len));

      // SQLの作成
      StringBuffer statement = new StringBuffer();
      statement.append("SELECT DISTINCT ");
      statement.append("  B.USER_ID, B.LOGIN_NAME, B.FIRST_NAME, B.LAST_NAME, D.POSITION ");
      statement.append("FROM turbine_user_group_role as A ");
      statement.append("LEFT JOIN turbine_user as B ");
      statement.append("  on A.USER_ID = B.USER_ID ");
      statement.append("LEFT JOIN turbine_group as C ");
      statement.append("  on A.GROUP_ID = C.GROUP_ID ");
      statement.append("LEFT JOIN eip_m_user_position as D ");
      statement.append("  on A.USER_ID = D.USER_ID ");
      statement.append("WHERE B.USER_ID > 3 AND B.DISABLED = 'F'");
      statement.append(" AND B.USER_ID IN (").append(tmp_ids_str.toString()).append(")");
      statement.append("ORDER BY D.POSITION");
      String query = statement.toString();

      List<TurbineUser> users = Database.sql(TurbineUser.class, query).fetchList();

      int recNum = users.size();
      for (int j = 0; j < recNum; j++) {
        TurbineUser tuser = users.get(j);
        user = new UserFacilityLiteBean();
        user.initField();
        user.setUserFacilityId(tuser.getUserId());
        user.setName(tuser.getLoginName());
        user.setAliasName(tuser.getFirstName(), tuser.getLastName());
        user.setUserFacilityType("U");
        if (Integer.toString(ALEipUtils.getUserId(rundata)).equals(user.getUserFacilityId())) {
          ulist.add(0, user);
        } else {
          ulist.add(user);
        }
      }
    }

    // facilityIDを元にデータを取得
    if (f_ids != null && f_ids.size() > 0) {
      Expression f_exp = ExpressionFactory.inDbExp(EipMFacility.FACILITY_ID_PK_COLUMN, f_ids);
      List<EipMFacility> facilities = Database.query(EipMFacility.class, f_exp).fetchList();
      if (facilities.size() == 0) {
        return null;
      }
      int f_size = facilities.size();
      for (int i = 0; i < f_size; i++) {
        EipMFacility f_user = facilities.get(i);
        user = new UserFacilityLiteBean();
        user.initField();
        user.setUserFacilityId(f_user.getFacilityId().intValue());
        user.setName("f" + user.getUserFacilityId());
        user.setAliasName(f_user.getFacilityName());
        user.setUserFacilityType("F");
        ulist.add(user);
      }
    }

    return ulist;
  }

  /*
   * 同一期間内に複数の 期間スケジュール を追加する. 第一引数の List を排他制御しないで処理するので注意.
   * 
   * @param weekSpanConList 複数の期間スケジュールを保持するリスト @param viewStartDate 表示開始の年月日
   * 
   * @param index 期間スケジュールの追加位置 @param rd 期間スケジュール
   */
  public static void addTerm(List<AjaxTermScheduleWeekContainer> weekConList, Date viewStartDate, int index, AjaxScheduleResultData rd) {
    try {
      boolean success = false;
      if (weekConList.size() > 0) {
        AjaxTermScheduleWeekContainer tmpWeekCon = null;
        int size = weekConList.size();
        for (int i = 0; i < size; i++) {
          tmpWeekCon = weekConList.get(i);
          success = tmpWeekCon.canAddTerm(rd);
          if (success) {
            tmpWeekCon.addTermResultData(index, rd);
            break;
          }
        }
      }

      if (!success) {
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(viewStartDate);
        // 週間スケジュールコンテナの初期化
        AjaxTermScheduleWeekContainer weekCon = new AjaxTermScheduleWeekContainer();
        weekCon.initField();
        weekCon.setViewStartDate(cal2);
        weekCon.addTermResultData(index, rd);
        weekConList.add(weekCon);
      }

    } catch (Exception e) {
      logger.error("Exception", e);
    }
  }

  /*
   * 同一期間内に複数の 期間スケジュール を追加する. 第一引数の List を排他制御しないで処理するので注意.
   * 
   * @param weekConList 複数の期間スケジュールを保持するリスト @param viewStartDate 表示開始の年月日 @param
   * index 期間スケジュールの追加位置 @param rd 期間スケジュール
   */
  public static void addTermSchedule(List<ScheduleTermWeekContainer> weekConList, Date viewStartDate, int index, ScheduleResultData rd) {
    try {
      boolean success = false;
      if (weekConList.size() > 0) {
        ScheduleTermWeekContainer tmpWeekCon = null;
        int size = weekConList.size();
        for (int i = 0; i < size; i++) {
          tmpWeekCon = weekConList.get(i);
          success = tmpWeekCon.canAddTerm(rd);
          if (success) {
            tmpWeekCon.addTermResultData(index, rd);
            break;
          }
        }
      }

      if (!success) {
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(viewStartDate);
        // 週間スケジュールコンテナの初期化
        ScheduleTermWeekContainer weekCon = new ScheduleTermWeekContainer();
        weekCon.initField();
        weekCon.setViewStartDate(cal2);
        weekCon.addTermResultData(index, rd);
        weekConList.add(weekCon);
      }

    } catch (Exception e) {
      logger.error("Exception", e);
    }
  }

  /**
   * 
   * @return
   */
  public static Date getEmptyDate() {
    Calendar cal = Calendar.getInstance();
    cal.set(9999, 11, 31);
    return cal.getTime();
  }

  public static String hasAuthOther(RunData rundata) {
    try {
      ALAccessControlFactoryService aclservice =
        (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
      ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
      if (aclhandler.hasAuthority(
        ALEipUtils.getUserId(rundata),
        ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER,
        ALAccessControlConstants.VALUE_ACL_LIST)) {
        return "T";
      }
    } catch (Exception e) {
      logger.error(e);
    }
    return "F";
  }

  public static String hasAuthSelf(RunData rundata) {
    try {
      ALAccessControlFactoryService aclservice =
        (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
      ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
      if (aclhandler.hasAuthority(
        ALEipUtils.getUserId(rundata),
        ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF,
        ALAccessControlConstants.VALUE_ACL_LIST)) {
        return "T";
      }
    } catch (Exception e) {
      logger.error(e);
    }
    return "F";
  }

  public static String hasAuthOtherUpdate(RunData rundata) {
    try {
      ALAccessControlFactoryService aclservice =
        (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
      ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
      if (aclhandler.hasAuthority(
        ALEipUtils.getUserId(rundata),
        ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER,
        ALAccessControlConstants.VALUE_ACL_UPDATE)) {
        return "T";
      }
    } catch (Exception e) {
      logger.error(e);
    }
    return "F";
  }

  public static String hasAuthSelfUpdate(RunData rundata) {
    try {
      ALAccessControlFactoryService aclservice =
        (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
      ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
      if (aclhandler.hasAuthority(
        ALEipUtils.getUserId(rundata),
        ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF,
        ALAccessControlConstants.VALUE_ACL_UPDATE)) {
        return "T";
      }
    } catch (Exception e) {
      logger.error(e);
    }
    return "F";
  }

  public static int getOwnerId(RunData rundata) {
    String scheduleId = rundata.getParameters().getString(ALEipConstants.ENTITY_ID);
    if (scheduleId == null | "".equals(scheduleId)) {
      return ALEipUtils.getUserId(rundata);
    }
    Expression exp = ExpressionFactory.matchDbExp(EipTSchedule.SCHEDULE_ID_PK_COLUMN, Integer.valueOf(scheduleId));
    List<EipTSchedule> list = Database.query(EipTSchedule.class, exp).fetchList();
    if (list.size() == 0) {
      return ALEipUtils.getUserId(rundata);
    } else {
      return list.get(0).getOwnerId().intValue();
    }
  }

  public static boolean hasRelation(RunData rundata) {
    String scheduleId = rundata.getParameters().getString(ALEipConstants.ENTITY_ID);
    if (scheduleId == null | "".equals(scheduleId)) {
      return false;
    }
    int userId = ALEipUtils.getUserId(rundata);
    Expression exp11 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, Integer.valueOf(scheduleId));
    Expression exp12 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.valueOf(userId));
    List<EipTScheduleMap> list = Database.query(EipTScheduleMap.class, exp11).andQualifier(exp12).fetchList();
    if (list.size() == 0) {
      return false;
    } else {
      return true;
    }
  }

  public static boolean hasMinimumAuthority(RunData rundata) {
    ALAccessControlFactoryService aclservice =
      (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
    ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();

    boolean hasAuthority =
      aclhandler.hasAuthority(ALEipUtils.getUserId(rundata), ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF, ALAccessControlConstants.VALUE_ACL_LIST);

    if (!hasAuthority) {
      ALEipUtils.redirectPermissionError(rundata);
      return false;
    }
    return true;
  }

  /**
   * パソコンへ送信するメールの内容を作成し返します。</br> 処理中例外が発生した場合は空文字を返します。
   * 
   * @param sendFromUserId
   *          送信元ユーザー
   * @param clientUserId
   *          秘書設定元ユーザーID（秘書が代理回答した以外は0）
   * @param schedule
   *          スケジュール
   * @param actionText
   *          アクション文
   * @param rundata
   *          実行データ
   * @param isDelete
   *          削除メールの場合trueを設定（スケジュール詳細へのリンクを出力しない）
   * @param comment
   *          返信コメント もしくは 削除理由
   * @param mode
   *          会議案内／回答メール／代理会議案内／代理回答メール
   * @return メール本文
   */
  // change start
  // public static String createMsgForPc(RunData rundata, EipTSchedule
  // schedule,
  // List<ALEipUser> memberList) {
  // change start No.1 スケジュール案内受信
  // public static String createMsgForPc(int sendFromUserId, int clientUserId,
  // EipTSchedule schedule, List<? extends ALEipUser> reqMember,
  // List<? extends ALEipUser> subMember, String actionText,
  // String subjectActionText, RunData rundata, boolean isDelete) {
  public static String createMsgForPc(int sendFromUserId, int clientUserId, EipTSchedule schedule, List<? extends ALEipUser> reqMember,
      List<? extends ALEipUser> subMember, String actionText, String subjectActionText, RunData rundata, boolean isDelete, String comment, int mode) {
    // change end
    // change end

    boolean enableAsp = JetspeedResources.getBoolean("aipo.asp", false);
    // remove start
    // ALEipUser loginUser = null;
    // ALBaseUser user = null;
    // remove end
    String date_detail = "";

    ALEipUser sendFromUser = null;
    // ------------------------------
    // 送信者情報を取得
    // ------------------------------
    try {
      // change start
      // loginUser = ALEipUtils.getALEipUser(rundata);
      // user =
      // (ALBaseUser) JetspeedSecurity.getUser(new UserIdPrincipal(loginUser
      // .getUserId()
      // .toString()));
      // user =
      // (ALBaseUser) JetspeedSecurity.getUser(new UserIdPrincipal(sendToUser
      // .getUserId()
      // .toString()));
      // date_detail = getMsgDate(schedule);
      sendFromUser = ALEipUtils.getALEipUser(sendFromUserId);
      // change end
    } catch (Exception e) {
      // add start
      logger.error("メール本文作成時、送信元ユーザー情報取得に失敗しました。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName() + "/スケジュールID:" + schedule.getScheduleId(), e);
      // add end
      return "";
    }

    // add start
    // ------------------------------
    // 日付・時間帯を取得
    // ------------------------------
    // 日付・時間帯の出力定型文を作成
    String dateTime = getScheduleDateTimeFixedText(schedule.getRepeatPattern(), schedule.getStartDate(), schedule.getEndDate(), "yyyy/M/d", "H:mm", "～");
    String repeatText = getRepeatScheduleFixedText(schedule.getRepeatPattern());
    if ("".equals(repeatText)) {
      // 繰り返し文字が得られない場合は、[{時間帯}]のフォーマットにする
      date_detail = dateTime;
    } else {
      // 繰り返し文字が得られた場合は、[{繰り返し文字}+半角スペース+{時間帯}+半角スペース+({有効期限})]のフォーマットにする
      date_detail = repeatText + " " + dateTime + " (" + getScheduleLimitDateFixedText(schedule.getStartDate(), schedule.getEndDate(), "yyyy/MM/dd", "～") + ")";
    }

    // ------------------------------
    // 送信者の役職リストを取得
    // ------------------------------
    List<UserGroupPositionLiteBean> sendToUserPostionList = UserUtils.getPostPositionBeanList(sendFromUserId);

    // ------------------------------
    // スケジュール詳細リンクを取得
    // ------------------------------
    // 開始日を取得（必須パラメータであるため）
    ALDateTimeField view_date = new ALDateTimeField("yyyy-MM-dd");
    view_date.setValue(schedule.getStartDate());
    // JetspeedLinkを取得
    JetspeedLink jsLink = null;
    try {
      jsLink = JetspeedLinkFactory.getInstance(rundata);
    } catch (TurbineException e) {
      logger.error("メール本文作成時、スケジュール詳細リンクURL取得に失敗しました。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName() + "/スケジュールID:" + schedule.getScheduleId(), e);
      return "";
    }
    // フルURLを取得
    String url =
      jsLink
        .getPortletById(rundata.getParameters().getString(JetspeedResources.PATH_PORTLETID_KEY))
        .addQueryData("template", "ScheduleDetailScreen")
        .addQueryData("entityId", schedule.getScheduleId())
        .addQueryData("view_date", view_date.toString())
        .toString();
    url += "&userid=%1$d";
    // フルURLからプロトコル、ドメイン、コンテキストパスを除去
    String resultUrl = Pattern.compile("(^http|^https)://[.[^/]]*/[.[^/]]*/").matcher(url).replaceFirst("");
    logger.debug("スケジュール詳細リンク:フルURL[" + url + "]/処理用URL[" + resultUrl + "]");

    // スケジュール詳細リンクタイトル
    final String scDetailLinkTitle = "(スケジュール詳細を開く)";
    // add end

    // 改行コードを取得
    String CR = System.getProperty("line.separator");

    // 戻り値文字列バッファ
    StringBuffer body = new StringBuffer("");

    // ------------------------------
    // 本文作成開始
    // ------------------------------
    // add start
    String SYMBOL = ALMailUtils.PREFIX_PATTERN_SKIP_PC;
    String LINKSYMBOL = ALMailUtils.PREFIX_PATTERN_SKIP_CEL;
    if (isDelete) {
      SYMBOL = ALMailUtils.PREFIX_PATTERN_REMOVE_BOTH;
      LINKSYMBOL = ALMailUtils.PREFIX_PATTERN_SKIP_BOTH;
    }
    // add end

    // change start
    // body.append(loginUser.getAliasName().toString());
    body.append(sendFromUser.getAliasName().toString());
    // change end

    // change start
    // メールアドレスでなく、役職を表示
    // if (!"".equals(user.getEmail())) {
    // body.append("(").append(user.getEmail()).append(")");
    // }
    if (null != sendToUserPostionList
      && sendToUserPostionList.size() > 0
      && null != sendToUserPostionList.get(0).getPositionName()
      && !"".equals(sendToUserPostionList.get(0).getPositionName())) {
      body.append("(").append(sendToUserPostionList.get(0).getPositionName()).append(")");
    }
    // change end

    // change start
    // アクション文対応
    // body.append("さんが予定を追加しました。").append(CR).append(CR);
    // body.append("さんが予定を" + actionText).append(CR).append(CR);
    // change start No.1 スケジュール案内受信
    // if ("予定作成".equals(subjectActionText)) {
    // body.append(
    // "さんから会議案内が来ました。" + CR + LINKSYMBOL + "下記リンクをクリックして詳細を確認して下さい。").append(
    // CR).append(CR);
    // } else if ("予定変更".equals(subjectActionText)) {
    // body
    // .append(
    // "さんが会議案内を" + actionText + CR + LINKSYMBOL + "下記リンクをクリックして詳細を確認して下さい。")
    // .append(CR)
    // .append(CR);
    // } else if ("予定削除".equals(subjectActionText)) {
    // body.append("さんが会議案内を" + actionText).append(CR).append(CR);
    // } else if ("予定回答".equals(subjectActionText)) {
    // body.append("さんが会議への参加を" + actionText).append(CR).append(CR);
    // } else if (SUBSTITUTE_RESPONSE.equals(subjectActionText)
    // || SUBSTITUTE_CREATE.equals(subjectActionText)
    // || SUBSTITUTE_UPDATE.equals(subjectActionText)
    // || SUBSTITUTE_DELETE.equals(subjectActionText)) {
    // ALEipUser clientUser = null;
    // try {
    // clientUser = ALEipUtils.getALEipUser(clientUserId);
    // } catch (ALDBErrorException e) {
    // logger.error("メール本文作成時、送信元ユーザー情報取得に失敗しました。ログインユーザー:"
    // + ALEipUtils.getALEipUser(rundata).getName()
    // + "/スケジュールID:"
    // + schedule.getScheduleId(), e);
    // // add end
    // return "";
    // }
    // // ------------------------------
    // // 秘書設定元ユーザーの役職リストを取得
    // // ------------------------------
    // List<UserGroupPositionLiteBean> clientUserPostionList =
    // UserUtils.getPostPositionBeanList(clientUserId);
    //
    // StringBuffer positionName = new StringBuffer();
    // if (null != clientUserPostionList
    // && clientUserPostionList.size() > 0
    // && null != clientUserPostionList.get(0).getPositionName()
    // && !"".equals(clientUserPostionList.get(0).getPositionName())) {
    // positionName.append("(").append(
    // clientUserPostionList.get(0).getPositionName()).append(")");
    // }
    //
    // if (SUBSTITUTE_RESPONSE.equals(subjectActionText)) {
    //
    // body.append(
    // "さんが"
    // + clientUser.getAliasName()
    // + positionName.toString()
    // + "さんの代わりに会議への参加を"
    // + actionText).append(CR).append(CR);
    // } else {
    // body.append(
    // "さんが"
    // + clientUser.getAliasName()
    // + positionName.toString()
    // + "さんの代わりに予定を"
    // + actionText).append(CR).append(CR);
    // }
    //
    // }
    // change end
    if (mode == CREATE_MSG_MODE_REQ) {
      // 会議案内メール本文
      if ("新規".equals(subjectActionText)) {
        body.append("さんから会議案内が来ました。" + CR + LINKSYMBOL + "下記リンクをクリックして詳細を確認して下さい。").append(CR).append(CR);
      } else if ("修正".equals(subjectActionText)) {
        body.append("さんが会議案内を" + actionText + CR + LINKSYMBOL + "下記リンクをクリックして詳細を確認して下さい。").append(CR).append(CR);
      } else if ("削除".equals(subjectActionText)) {
        body.append("さんが会議案内を" + actionText).append(CR).append(CR);
      }
    } else if (mode == CREATE_MSG_MODE_RES) {
      // 回答メール本文
      body.append("さんが会議への参加を" + actionText).append(CR).append(CR);
    } else if (mode == CREATE_MSG_MODE_SUBREQ || mode == CREATE_MSG_MODE_SUBRES) {
      ALEipUser clientUser = null;
      try {
        clientUser = ALEipUtils.getALEipUser(clientUserId);
      } catch (ALDBErrorException e) {
        logger.error("メール本文作成時、送信元ユーザー情報取得に失敗しました。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName() + "/スケジュールID:" + schedule.getScheduleId(), e);
        // add end
        return "";
      }
      // ------------------------------
      // 秘書設定元ユーザーの役職リストを取得
      // ------------------------------
      List<UserGroupPositionLiteBean> clientUserPostionList = UserUtils.getPostPositionBeanList(clientUserId);

      StringBuffer positionName = new StringBuffer();
      if (null != clientUserPostionList
        && clientUserPostionList.size() > 0
        && null != clientUserPostionList.get(0).getPositionName()
        && !"".equals(clientUserPostionList.get(0).getPositionName())) {
        positionName.append("(").append(clientUserPostionList.get(0).getPositionName()).append(")");
      }

      if (mode == CREATE_MSG_MODE_SUBRES) {

        body.append("さんが" + clientUser.getAliasName() + positionName.toString() + "さんの代わりに会議への参加を" + actionText).append(CR).append(CR);
      } else {
        body.append("さんが" + clientUser.getAliasName() + positionName.toString() + "さんの代わりに予定を" + actionText).append(CR).append(CR);
      }
    }
    // change start

    // add start 要件No.1 スケジュール案内受信
    if (comment != null && !"".equals(comment)) {
      String[] commentArray = ALMailUtils.getLines(comment);
      String scheduleComment = "";
      int count = 0;
      while (count < commentArray.length) {
        scheduleComment = scheduleComment + ALMailUtils.PREFIX_PATTERN_COMMENT + commentArray[count] + CR;
        count++;
      }
      body.append(scheduleComment);
      body.append(ALMailUtils.PREFIX_PATTERN_COMMENT + CR);
    }
    // add end

    // 受入テストフェーズ課題・障害台帳 No.28 remove start

    body.append(SYMBOL + "[予定]").append(CR).append(SYMBOL + schedule.getName().toString()).append(CR);
    body.append(SYMBOL + "[日時]").append(CR).append(SYMBOL + date_detail).append(CR);

    if (schedule.getPlace().toString().length() > 0) {
      body.append(SYMBOL + "[場所] ").append(CR).append(SYMBOL + schedule.getPlace().toString()).append(CR);
    }

    if (schedule.getNote().toString().length() > 0) {
      // change start 2011.12.15 強化テスト対応No.75
      // body.append(SYMBOL + "[内容]").append(CR).append(
      // SYMBOL + schedule.getNote().toString()).append(CR);
      String[] noteArray = ALMailUtils.getLines(schedule.getNote().toString());
      String scheduleNote = "";
      int count = 0;
      while (count < noteArray.length) {
        scheduleNote = scheduleNote + SYMBOL + noteArray[count] + CR;
        count++;
      }
      // change start 要件No.1 スケジュール案内受信
      // body.append(SYMBOL +
      // "[内容]").append(CR).append(scheduleNote).append(CR);
      body.append(SYMBOL + "[内容]").append(CR).append(scheduleNote);
      body.append(SYMBOL + CR);
      // change end
      // change end
    }
    // remove end

    // change start
    // 参加メンバーの必須/任意対応
    // if (memberList != null) {
    // int size = memberList.size();
    // int i;
    // body.append("[参加者]").append(CR);
    // for (i = 0; i < size; i++) {
    // if (i != 0) {
    // body.append(", ");
    // }
    // ALEipUser member = memberList.get(i);
    // body.append(member.getAliasName());
    // }
    // body.append(CR);
    // }

    // 受入テストフェーズ課題・障害台帳 No.28 remove start
    // 必須メンバー設定
    int reqMenberIndex = 0;
    for (ALEipUser m : reqMember) {
      if (reqMenberIndex == 0) {
        body.append(SYMBOL + "[必須参加者]").append(CR);
      }
      if (reqMenberIndex > 0) {
        body.append(", ");
      } else {
        body.append(SYMBOL);
      }
      body.append(m.getAliasName());
      reqMenberIndex++;
    }
    if (reqMenberIndex > 0) {
      body.append(CR);
    }

    // 任意メンバー設定
    int subMenberIndex = 0;
    for (ALEipUser m : subMember) {
      if (subMenberIndex == 0) {
        body.append(SYMBOL + "[任意参加者]").append(CR);
      }
      if (subMenberIndex != 0) {
        body.append(", ");
      } else {
        body.append(SYMBOL);
      }
      body.append(m.getAliasName());
      subMenberIndex++;
    }
    if (subMenberIndex > 0) {
      body.append(CR);
    }
    // 受入テストフェーズ課題・障害台帳 No.28 remove end
    // change end

    // change start 要件No.1 スケジュール案内受信
    // body.append(CR);
    body.append(SYMBOL + CR);
    // change end

    // remove start 要件No.1 スケジュール案内受信
    // body.append("[").append(ALOrgUtilsService.getAlias()).append(
    // "へのアクセス（PC向け）]").append(CR);
    // remove end
    if (enableAsp) {
      body.append("　").append(ALMailUtils.getGlobalurl()).append(CR);
      // add start
      if (!isDelete) {
        // add start 強化テストNo.72
        if (!SUBSTITUTE_DELETE.equals(subjectActionText)) {
          // add end
          // スケジュール詳細リンク表示
          body.append(scDetailLinkTitle).append(CR).append("　").append(ALMailUtils.getGlobalurl() + resultUrl).append(CR);
        }
      }
      // add end
    } else {
      // remove start 要件No.1 スケジュール案内受信
      // body.append("・社内").append(CR);
      // remove end
      // change start
      // 無駄な改行を削除
      // body.append("
      // ").append(ALMailUtils.getLocalurl()).append(CR).append(CR);
      // change end
      // remove start No.1 スケジュール案内受信
      // body.append(" ").append(ALMailUtils.getLocalurl()).append(CR);
      // remove end
      // add start
      if (!isDelete) {
        // add start 要件No.1 スケジュール案内受信
        body.append("・社内").append(CR);
        // add end
        // add start 強化テストNo.72
        if (!SUBSTITUTE_DELETE.equals(subjectActionText)) {
          // add end
          // スケジュール詳細リンク表示
          body.append(scDetailLinkTitle).append(CR).append("　").append(ALMailUtils.getLocalurl() + resultUrl).append(CR);
        }
      }

      // remove start 要件No.1 スケジュール案内受信
      // body.append("・社外").append(CR);
      // remove end
      // remove start No.1 スケジュール案内受信
      // body.append(" ").append(ALMailUtils.getGlobalurl()).append(CR);
      // remove end
      // add start
      if (!isDelete) {
        // add start 要件No.1 スケジュール案内受信
        body.append("・社外").append(CR);
        // add end
        // add start 強化テストNo.72
        if (!SUBSTITUTE_DELETE.equals(subjectActionText)) {
          // add end
          // スケジュール詳細リンク表示
          body.append(scDetailLinkTitle).append(CR).append("　").append(ALMailUtils.getGlobalurl() + resultUrl).append(CR);
        }
      }
      // add end
    }
    // add start
    // フッターの前に一律改行を追加
    body.append(CR);
    // add end

    // remove start No.1 スケジュール案内受信
    // body.append("---------------------").append(CR);
    // body.append(ALOrgUtilsService.getAlias()).append(CR);
    // remove end

    return body.toString();
  }

  // change end

  /**
   * 携帯電話へ送信するメールの内容を作成する．
   * 
   * @return
   */
  public static String createMsgForCellPhone(RunData rundata, EipTSchedule schedule, List<ALEipUser> memberList, int destUserID) {
    ALEipUser loginUser = null;
    ALBaseUser user = null;
    String date_detail = "";
    try {
      loginUser = ALEipUtils.getALEipUser(rundata);
      user = (ALBaseUser) JetspeedSecurity.getUser(new UserIdPrincipal(loginUser.getUserId().toString()));
      date_detail = getMsgDate(schedule);
    } catch (Exception e) {
      return "";
    }
    String CR = System.getProperty("line.separator");
    StringBuffer body = new StringBuffer("");
    body.append(loginUser.getAliasName().toString());
    if (!"".equals(user.getEmail())) {
      body.append("(").append(user.getEmail()).append(")");
    }
    body.append("さんが予定を追加しました。").append(CR).append(CR);
    body.append("[予定]").append(CR).append(schedule.getName().toString()).append(CR);
    body.append("[日時]").append(CR).append(date_detail).append(CR);

    if (memberList != null) {
      int size = memberList.size();
      int i;
      body.append("[参加者]").append(CR);
      for (i = 0; i < size; i++) {
        if (i != 0) {
          body.append(", ");
        }
        ALEipUser member = memberList.get(i);
        body.append(member.getAliasName());
      }
      body.append(CR);
    }
    body.append(CR);

    ALEipUser destUser;
    try {
      destUser = ALEipUtils.getALEipUser(destUserID);
    } catch (ALDBErrorException ex) {
      logger.error("Exception", ex);
      return "";
    }
    body.append("[").append(ALOrgUtilsService.getAlias()).append("へのアクセス]").append(CR);
    body.append("　").append(ALMailUtils.getGlobalurl()).append("?key=").append(ALCellularUtils.getCellularKey(destUser)).append(CR);
    body.append("---------------------").append(CR);
    body.append(ALOrgUtilsService.getAlias()).append(CR);
    return body.toString();
  }

  public static String getMsgDate(EipTSchedule schedule) {
    Calendar start_cal = Calendar.getInstance();
    start_cal.setTime(schedule.getStartDate());
    Calendar end_cal = Calendar.getInstance();
    end_cal.setTime(schedule.getEndDate());

    StringBuffer result = new StringBuffer();
    // DN -> 毎日 (A = N -> 期限なし A = L -> 期限あり)
    // WnnnnnnnN W01111110 -> 毎週(月～金用)
    // MnnN M25 -> 毎月25日
    // S -> 期間での指定
    String ptn = schedule.getRepeatPattern();
    int count = 0;
    boolean is_repeat = true;
    boolean is_span = false;
    // 毎日
    if (ptn.charAt(0) == 'D') {
      result.append("毎日");
      count = 1;
      // 毎週
    } else if (ptn.charAt(0) == 'W') {
      result.append(new StringBuffer()
        .append("毎週 ")
        .append(ptn.charAt(1) != '0' ? "日" : "")
        .append(ptn.charAt(2) != '0' ? "月" : "")
        .append(ptn.charAt(3) != '0' ? "火" : "")
        .append(ptn.charAt(4) != '0' ? "水" : "")
        .append(ptn.charAt(5) != '0' ? "木" : "")
        .append(ptn.charAt(6) != '0' ? "金" : "")
        .append(ptn.charAt(7) != '0' ? "土" : "")
        .append(" 曜日")
        .toString());
      count = 8;
      // 毎月
    } else if (ptn.charAt(0) == 'M') {
      result.append("毎月 ").append(Integer.parseInt(ptn.substring(1, 3))).append("日").toString();
      count = 3;
      // 期間
    } else if (ptn.charAt(0) == 'S') {
      is_span = true;
      is_repeat = false;
    } else {
      is_repeat = false;
    }

    ALDateTimeField date_field = new ALDateTimeField("yyyy/MM/dd");
    ALDateTimeField time_field = new ALDateTimeField("HH:mm");

    if (!is_span) {
      if (!is_repeat) {
        date_field.setValue(schedule.getStartDate());
        result.append(date_field.toString());
      }
      time_field.setValue(schedule.getStartDate());
      result.append(" ").append(time_field.toString()).append("～");
      time_field.setValue(schedule.getEndDate());
      result.append(time_field.toString()).append(" ");
    } else {
      Date start = schedule.getStartDate();
      Date end = schedule.getEndDate();
      date_field.setValue(start);
      result.append(date_field.toString());
      if (!start.equals(end)) {
        result.append("～");
        date_field.setValue(end);
        result.append(date_field.toString());
      }
    }

    if (is_repeat) {
      if (ptn.charAt(count) == 'N') {
        // schedule.setLimit(false);
      } else {
        // schedule.setLimit(true);
        // 期限
        date_field.setValue(schedule.getStartDate());
        result.append(" （").append(date_field.toString()).append("～");
        date_field.setValue(schedule.getEndDate());
        result.append(date_field.toString()).append("）").toString();
      }
    }
    return result.toString();
  }

  public static boolean isDuplicateFacilitySchedule(EipTSchedule schedule, List<Integer> facilityIdList, Integer _old_scheduleid, Date _old_viewDate) {
    /* ダミースケジュール検索用 */
    GregorianCalendar cald = new GregorianCalendar();

    boolean result = false;
    {

      Date start_date;
      Date end_date;
      String repeat_pattern;
      String repeat_type;
      boolean week_0;
      boolean week_1;
      boolean week_2;
      boolean week_3;
      boolean week_4;
      boolean week_5;
      boolean week_6;
      String limit_flag;
      int month_day = -1;
      Integer db_scheduleid = null;
      boolean[] week_array = new boolean[7];
      boolean unlimited_repeat = false;
      try {
        start_date = schedule.getStartDate();

        end_date = schedule.getEndDate();

        repeat_pattern = schedule.getRepeatPattern();

        repeat_type = repeat_pattern.substring(0, 0);

        limit_flag = repeat_pattern.substring(repeat_pattern.length() - 1);

        week_0 = repeat_pattern.matches("W1.......");

        week_1 = repeat_pattern.matches("W.1......");

        week_2 = repeat_pattern.matches("W..1.....");

        week_3 = repeat_pattern.matches("W...1....");

        week_4 = repeat_pattern.matches("W....1...");

        week_5 = repeat_pattern.matches("W.....1..");

        week_6 = repeat_pattern.matches("W......1.");

        if (repeat_pattern.startsWith("M")) {
          month_day = Integer.parseInt(repeat_pattern.substring(1, 3));
        }

        // 単体スケジュールは期限1日のみのスケジュールとして判定
        if (repeat_pattern.startsWith("N")) {
          Calendar cal = Calendar.getInstance();
          cal.setTime(start_date);
          int dow = cal.get(Calendar.DAY_OF_WEEK);
          week_0 = (dow == Calendar.SUNDAY);
          week_1 = (dow == Calendar.MONDAY);
          week_2 = (dow == Calendar.TUESDAY);
          week_3 = (dow == Calendar.WEDNESDAY);
          week_4 = (dow == Calendar.THURSDAY);
          week_5 = (dow == Calendar.FRIDAY);
          week_6 = (dow == Calendar.SATURDAY);
          month_day = cal.get(Calendar.DAY_OF_MONTH);
        } else if (repeat_pattern.endsWith("N")) {
          unlimited_repeat = true;
        }

        week_array[0] = week_0;
        week_array[1] = week_1;
        week_array[2] = week_2;
        week_array[3] = week_3;
        week_array[4] = week_4;
        week_array[5] = week_5;
        week_array[6] = week_6;

      } catch (Exception e) {
        return false;
      }

      // 施設予約状況をチェックする
      if (facilityIdList.size() > 0) {
        List<Integer> fids = facilityIdList;
        SelectQuery<EipTScheduleMap> fquery = Database.query(EipTScheduleMap.class);
        Expression fexp1 = ExpressionFactory.inExp(EipTScheduleMap.USER_ID_PROPERTY, fids);
        fquery.setQualifier(fexp1);

        Expression fexp2 = ExpressionFactory.matchExp(EipTScheduleMap.TYPE_PROPERTY, ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY);
        fquery.andQualifier(fexp2);

        Expression oneexp = null;
        Expression rdexp = null;
        Expression rwexp = null;
        // Expression rwlexp = null;
        Expression rmexp = null;

        { // １日スケジュールの検索
          Expression exp100 = ExpressionFactory.matchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "N");

          try {
            if (!unlimited_repeat) {
              Expression exp101 = ExpressionFactory.lessOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY, end_date);
              Expression exp102 = ExpressionFactory.greaterExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY, start_date);
              oneexp = exp100.andExp(exp101.andExp(exp102));
            } else {
              oneexp = exp100;
            }
          } catch (Exception e) {

          }
        }

        { // 繰り返しスケジュールの検索
          // char lim = 'N';
          if ("ON".equals(limit_flag)) {
            // lim = 'L';
          }

          { // "D".equals(repeat_type.getValue())
            Expression dexp01 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "D_");
            rdexp = dexp01;
          }

          { // "W".equals(repeat_type.getValue())
            Expression wexp = null;
            List<Expression> wexps = new ArrayList<Expression>();
            if (week_0 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W1_______");
              wexps.add(wexp);
            }
            if (week_1 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_1______");
              wexps.add(wexp);
            }
            if (week_2 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W__1_____");
              wexps.add(wexp);
            }
            if (week_3 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W___1____");
              wexps.add(wexp);
            }
            if (week_4 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W____1___");
              wexps.add(wexp);
            }
            if (week_5 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_____1__");
              wexps.add(wexp);
            }
            if (week_6 == true) {
              wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W______1_");
              wexps.add(wexp);
            }
            if (wexps.size() > 0) {
              rwexp = wexps.get(0);
              int wexpssize = wexps.size();
              for (int k = 1; k < wexpssize; k++) {
                rwexp = rwexp.orExp(wexps.get(k));
              }
            } else {
              rwexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W________");
            }
          }

          { // "M".equals(repeat_type.getValue())
            if (month_day > 0) { // 毎月、もしくは単体の場合
              DecimalFormat exF = new DecimalFormat("00");
              String md_str = exF.format(month_day);
              rmexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "M" + md_str + "_");
            } else {
              rmexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "M___");
            }
          }

          Expression repeatexp = oneexp;
          if (rdexp != null) {
            repeatexp = repeatexp.orExp(rdexp);
          }
          if (rwexp != null) {
            repeatexp = repeatexp.orExp(rwexp);
          }
          if (rmexp != null) {
            repeatexp = repeatexp.orExp(rmexp);
          }
          fquery.andQualifier(repeatexp);
        }

        db_scheduleid = schedule.getScheduleId();
        if (db_scheduleid != null && db_scheduleid >= 0) {
          Expression exp00 = ExpressionFactory.noMatchDbExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.SCHEDULE_ID_PK_COLUMN, db_scheduleid);
          fquery.andQualifier(exp00);
        }

        fquery.distinct(true);
        List<EipTScheduleMap> f_list = fquery.fetchList();
        if (f_list != null && f_list.size() > 0) {
          // 繰り返しスケジュール同士の時刻幅での比較
          boolean existFacility = false;
          int f_list_size = f_list.size();
          for (int i = 0; i < f_list_size; i++) {
            EipTScheduleMap map = f_list.get(i);

            Date dbStartDate = map.getEipTSchedule().getStartDate();
            Date dbEndDate = map.getEipTSchedule().getEndDate();

            boolean containtsRs = false;
            // 繰り返し期限付きの処理
            String ptn = map.getEipTSchedule().getRepeatPattern();

            if (ptn.charAt(0) == 'N') { // 単体スケジュール
              if ("D".equals(repeat_type) || "N".equals(repeat_type)) { // 毎日 or
                // 単体
                try {
                  if ((dbStartDate.before(end_date) && dbEndDate.after(start_date)) || unlimited_repeat) {
                    containtsRs = true;
                  }
                } catch (Exception e) {
                  containtsRs = false;
                }
              } else {
                if ((dbStartDate.before(end_date) && dbEndDate.after(start_date)) || unlimited_repeat) {
                  containtsRs = true;
                }
              }

            } else if (ptn.charAt(0) == 'D') {
              if (ptn.charAt(1) == 'L') {
                try {
                  if ((dbStartDate.before(end_date) && dbEndDate.after(start_date)) || unlimited_repeat) {
                    containtsRs = true;
                  }
                } catch (Exception e) {
                  containtsRs = false;
                }
              } else {
                containtsRs = true;
              }
            } else if (ptn.charAt(0) == 'W') {
              if (ptn.charAt(8) == 'L') {
                try {
                  if ((dbStartDate.before(end_date) && dbEndDate.after(start_date)) || unlimited_repeat) {
                    containtsRs = true;
                  }
                } catch (Exception e) {
                  containtsRs = false;
                }
              } else {
                containtsRs = true;
              }
            } else if (ptn.charAt(0) == 'M') {
              if (ptn.charAt(3) == 'L') {
                try {
                  if ((dbStartDate.before(end_date) && dbEndDate.after(start_date)) || unlimited_repeat) {
                    containtsRs = true;
                  }
                } catch (Exception e) {
                  containtsRs = false;
                }
              } else {
                containtsRs = true;
              }
            } else {
              containtsRs = true;
            }

            if (containtsRs) {
              int ss_flg = ScheduleUtils.compareTime(start_date, dbEndDate);
              int se_flg = ScheduleUtils.compareTime(end_date, dbStartDate);
              if (ss_flg > 0 && se_flg < 0) {
                /* 期限無しのスケジュール同士の場合は重複とみなす */
                if (!"N".equals(ptn) && ptn.endsWith("N") && unlimited_repeat) {
                  existFacility = true;
                } else {
                  Date _start_date = null;
                  Date _end_date = null;

                  if (!"N".equals(ptn) && ptn.endsWith("N") && !unlimited_repeat) {
                    _start_date = (Date) start_date.clone();
                    _end_date = (Date) end_date.clone();
                  } else if (("N".equals(ptn) || !ptn.endsWith("N")) && unlimited_repeat) {
                    _start_date = (Date) dbStartDate.clone();
                    _end_date = (Date) dbEndDate.clone();
                  } else if (("N".equals(ptn) || !ptn.endsWith("N")) && !unlimited_repeat) {

                    if (dbStartDate.after(start_date)) {
                      _start_date = (Date) dbStartDate.clone();
                    } else {
                      _start_date = (Date) start_date.clone();
                    }

                    if (dbEndDate.before(end_date)) {
                      _end_date = (Date) dbEndDate.clone();
                    } else {
                      _end_date = (Date) end_date.clone();
                    }

                  }

                  if ((_start_date == null) || (_end_date == null)) {
                    continue;
                  }

                  /* 期限内の日付を全て比較 */
                  Expression dexp1 = ExpressionFactory.matchExp(EipTSchedule.NAME_PROPERTY, "dummy");

                  Expression dexp2 = ExpressionFactory.matchExp(EipTSchedule.PARENT_ID_PROPERTY, map.getScheduleId());

                  if (db_scheduleid != null) {
                    Expression dexp21 = ExpressionFactory.matchExp(EipTSchedule.PARENT_ID_PROPERTY, db_scheduleid);
                    dexp2 = dexp2.orExp(dexp21);
                  }
                  Expression dexp3 = null;

                  cald.setTime(_start_date);
                  cald.set(Calendar.MILLISECOND, 0);
                  cald.set(Calendar.SECOND, 0);
                  cald.set(Calendar.MINUTE, 0);
                  cald.set(Calendar.HOUR_OF_DAY, 0);
                  Date ddate = cald.getTime();
                  List<EipTSchedule> temp = null;

                  if ("N".equals(repeat_pattern)) {
                    /* 繰り返しスケジュールのうちひとつだけを移動した場合の処理 */
                    if ((_old_scheduleid != null) && (_old_viewDate != null)) {
                      if ((_old_scheduleid.intValue() == map.getScheduleId().intValue()) && compareToDate(_start_date, _old_viewDate) == 0) {
                        continue;
                      }
                    }

                    try {
                      dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                      temp = Database.query(EipTSchedule.class, dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                      if (temp == null || temp.size() <= 0) {
                        existFacility = true;
                        break;
                      }
                    } catch (Exception e) {
                      logger.error("[DuplicateFacilityCheck]: ", e);
                      existFacility = true;
                      break;
                    }
                  } else if (repeat_pattern.startsWith("D")) {
                    while (!ddate.after(_end_date)) {
                      if (matchDay(cald, ptn)) {
                        try {
                          dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                          temp = Database.query(EipTSchedule.class, dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                          if (temp == null || temp.size() <= 0) {
                            existFacility = true;
                            break;
                          }
                        } catch (Exception e) {
                          logger.error("[DuplicateFacilityCheck]: ", e);
                          existFacility = true;
                          break;
                        }
                      }
                      cald.add(Calendar.DATE, 1);
                      ddate = cald.getTime();
                    }
                  } else if (repeat_pattern.startsWith("W")) {
                    /* ダミースケジュールを探す */
                    int wlen = week_array.length;
                    if (wlen < 1) {
                      continue;
                    }
                    int k;
                    while (!ddate.after(_end_date)) {
                      k = (cald.get(Calendar.DAY_OF_WEEK) - 1) % wlen;
                      if ((week_array[k] == true) && matchDay(cald, ptn)) {
                        try {
                          dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                          temp = Database.query(EipTSchedule.class, dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                          if (temp == null || temp.size() <= 0) {
                            existFacility = true;
                            break;
                          }
                        } catch (Exception e) {
                          logger.error("[DuplicateFacilityCheck]: ", e);
                          existFacility = true;
                          break;
                        }
                      }
                      cald.add(Calendar.DATE, 1);
                      ddate = cald.getTime();
                    }
                  } else if (repeat_pattern.startsWith("M")) {
                    /* 比較開始日までカレンダー移動 */
                    cald.setTime(dbStartDate);
                    cald.set(Calendar.MILLISECOND, 0);
                    cald.set(Calendar.SECOND, 0);
                    cald.set(Calendar.MINUTE, 0);
                    cald.set(Calendar.HOUR_OF_DAY, 0);

                    if (month_day > 0) {
                      cald.set(Calendar.DAY_OF_MONTH, month_day);
                    } else {
                      continue;
                    }
                    Date tmp_date = cald.getTime();
                    while (tmp_date.before(ddate)) {
                      cald.add(Calendar.MONTH, 1);
                      /* 月によって日にちがないときのための処理 */
                      while (month_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                        cald.add(Calendar.MONTH, 1);
                        cald.set(Calendar.DAY_OF_MONTH, month_day);
                        if (tmp_date.before(tmp_date)) {
                          break;
                        }
                      }
                      tmp_date = cald.getTime();
                    }
                    ddate = tmp_date;
                    /* 比較開始 */
                    while (!ddate.after(_end_date)) {
                      if (matchDay(cald, ptn)) {
                        try {
                          dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                          temp = Database.query(EipTSchedule.class, dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                          if (temp == null || temp.size() <= 0) {
                            existFacility = true;
                            break;
                          }
                        } catch (Exception e) {
                          logger.error("[DuplicateFacilityCheck]: ", e);
                          existFacility = true;
                          break;
                        }
                      }
                      cald.add(Calendar.MONTH, 1);
                      /* 月によって日にちがないときのための処理 */
                      while (month_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                        cald.add(Calendar.MONTH, 1);
                        cald.set(Calendar.DAY_OF_MONTH, month_day);
                        if (!ddate.after(_end_date)) {
                          break;
                        }
                      }
                      ddate = cald.getTime();
                    }
                  } else {
                    continue;
                  }
                }
                // existFacility = true;
              }
            }
            if (existFacility) {
              break;
            }
          }
          if (existFacility) {
            return existFacility;
          }
        }
      }
    }
    return result;
  }

  public static boolean matchDay(Calendar cal, String repeat_ptn) { // カレンダーの日付が繰り返しパターンと重なっているか判定
    if (repeat_ptn == null || "".equals(repeat_ptn)) {
      return false;
    }
    if (repeat_ptn.startsWith("M")) {
      int month_day = Integer.parseInt(repeat_ptn.substring(1, 3));
      int ptn_day = cal.get(Calendar.DAY_OF_MONTH);
      return (month_day == ptn_day);
    } else if (repeat_ptn.startsWith("W")) {
      int dow = cal.get(Calendar.DAY_OF_WEEK);
      if (dow == Calendar.SUNDAY) {
        return repeat_ptn.matches("W1.......");
      }
      if (dow == Calendar.MONDAY) {
        return repeat_ptn.matches("W.1......");
      }
      if (dow == Calendar.TUESDAY) {
        return repeat_ptn.matches("W..1.....");
      }
      if (dow == Calendar.WEDNESDAY) {
        return repeat_ptn.matches("W...1....");
      }
      if (dow == Calendar.THURSDAY) {
        return repeat_ptn.matches("W....1...");
      }
      if (dow == Calendar.FRIDAY) {
        return repeat_ptn.matches("W.....1..");
      }
      if (dow == Calendar.SATURDAY) {
        return repeat_ptn.matches("W......1.");
      }
      return false;
    } else {
      return true;
    }
  }

  /**
   * 他人のスケジュールに対する権限があるかどうかを調べます。
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static boolean hasAuthorityForOtherSchedule(RunData rundata, int type) {
    boolean acl_delete_other = false;
    ALAccessControlFactoryService aclservice =
      (ALAccessControlFactoryService) ((TurbineServices) TurbineServices.getInstance()).getService(ALAccessControlFactoryService.SERVICE_NAME);
    ALAccessControlHandler aclhandler = aclservice.getAccessControlHandler();
    if (aclhandler.hasAuthority(ALEipUtils.getUserId(rundata), ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER, type)) {
      acl_delete_other = true;
    }

    return acl_delete_other;
  }

  public static void createShareScheduleActivity(EipTSchedule schedule, String loginName, List<String> recipients, boolean isNew) {
    if (recipients != null && recipients.size() > 0) {
      String title = new StringBuilder("予定「").append(ALCommonUtils.compressString(schedule.getName(), 30)).append(isNew ? "」を追加しました。" : "」を編集しました。").toString();
      String portletParams =
        new StringBuilder("?template=ScheduleDetailScreen").append("&entityid=").append(schedule.getScheduleId()).append("&view_date=").append(
          ALDateUtil.format(schedule.getStartDate(), "yyyy-MM-dd-00-00")).toString();
      ALActivityService.create(new ALActivityPutRequest().withAppId("Schedule").withLoginName(loginName).withPortletParams(portletParams).withRecipients(
        recipients).withTile(title).witchPriority(1f).withExternalId(String.valueOf(schedule.getScheduleId())));
    }
  }

  // add start
  // 定期パターン増加対応
  /**
   * 西暦year年month月の第weekNum dow曜日の日を求める
   * 
   * @param year
   *          西暦
   * @param month
   *          月（Calendar.JANUARY～）
   * @param weekNum
   *          第何週または最終週
   * @param dow
   *          曜日（Calendar.SUNDAY～）
   * @return 西暦year年month月の第weekNum dow曜日の日
   */
  private static int getDayForWeekOfMonthAndDayOfWeek(int year, int month, String weekNum, int dow) {

    int day = 0;

    // 指定年月の初日を設定
    Calendar cal = Calendar.getInstance();
    cal.set(year, month, 1);

    if (ScheduleWeekNumber.LAST.getCode().equals(weekNum)) {
      // 最終週の場合
      // 指定年月の最終日を取得
      cal.set(year, month, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
      // 当月の最終日の曜日（wday）と、指定曜日（dow）を比較して処理分け
      int wday = cal.get(Calendar.DAY_OF_WEEK);
      int lastDay = cal.get(Calendar.DAY_OF_MONTH);
      day = wday >= dow ? lastDay - (wday - dow) : lastDay - 7 + (dow - wday);
    } else {
      // 最終週ではない場合
      // 当月の1日の曜日（wday）と、指定曜日（dow）を比較して処理分け
      int wday = cal.get(Calendar.DAY_OF_WEEK);
      int num = Integer.parseInt(weekNum);
      day = wday > dow ? (7 * num + 1) - (wday - dow) : (7 * (num - 1) + 1) + (dow - wday);
    }

    return day;
  }

  /**
   * 西暦year年month月の第countCode回 平日の日を求める。<br/>
   * 平日は月・火・水・木・金を示す。
   * 
   * @param year
   *          西暦
   * @param month
   *          月（Calendar.JANUARY～）
   * @param countCode
   *          第何回または最終
   * @return 西暦year年month月の第countCode回 平日の日
   */
  private static int getDayForWeekDay(int year, int month, String countCode) {

    int day = 0;

    // 指定年月の初日を設定
    Calendar cal = Calendar.getInstance();
    cal.set(year, month, 1);

    if (ScheduleWeekNumber.LAST.getCode().equals(countCode)) {
      // 最終の場合
      // 指定年月の最終日から1日ずつ平日をさかのぼる
      for (int i = cal.getActualMaximum(Calendar.DAY_OF_MONTH); i >= 1; i--) {
        cal.set(Calendar.DAY_OF_MONTH, i);
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        if (DayOfWeek.SUNDAY.getNumber() < dow && dow < DayOfWeek.SATURDAY.getNumber()) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          break;
        }
      }
    } else {
      // 最終ではない場合
      // 指定年月の初日から1日ずつ平日をcountCode数分進める
      int count = Integer.parseInt(countCode);
      int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
      int hitCount = 0;
      for (int i = 1; i <= lastDay; i++) {
        cal.set(Calendar.DAY_OF_MONTH, i);
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        if (DayOfWeek.SUNDAY.getNumber() < dow && dow < DayOfWeek.SATURDAY.getNumber()) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          hitCount++;
        }
        if (count == hitCount) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          break;
        }
      }
    }

    return day;
  }

  /**
   * 西暦year年month月の第countCode回 週末の日を求める。<br/>
   * 週末は土日を示す。
   * 
   * @param year
   *          西暦
   * @param month
   *          月（Calendar.JANUARY～）
   * @param countCode
   *          第何回または最終
   * @return 西暦year年month月の第countCode回 平日の日
   */
  private static int getDayForWeekEnd(int year, int month, String countCode) {

    int day = 0;

    // 指定年月の初日を設定
    Calendar cal = Calendar.getInstance();
    cal.set(year, month, 1);

    if (ScheduleWeekNumber.LAST.getCode().equals(countCode)) {
      // 最終の場合
      // 指定年月の最終日から1日ずつ週末をさかのぼる
      for (int i = cal.getActualMaximum(Calendar.DAY_OF_MONTH); i >= 1; i--) {
        cal.set(Calendar.DAY_OF_MONTH, i);
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        if (DayOfWeek.SUNDAY.getNumber() == dow || dow == DayOfWeek.SATURDAY.getNumber()) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          break;
        }
      }
    } else {
      // 最終ではない場合
      // 指定年月の初日から1日ずつ週末をcountCode数分進める
      int count = Integer.parseInt(countCode);
      int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
      int hitCount = 0;
      for (int i = 1; i <= lastDay; i++) {
        cal.set(Calendar.DAY_OF_MONTH, i);
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        if (DayOfWeek.SUNDAY.getNumber() == dow || dow == DayOfWeek.SATURDAY.getNumber()) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          hitCount++;
        }
        if (count == hitCount) {
          day = cal.get(Calendar.DAY_OF_MONTH);
          break;
        }
      }
    }

    return day;
  }

  /**
   * 月・週パターン用該当日付取得<br/>
   * 平日、週末、曜日別に日付を取得します。
   * 
   * @param year
   *          西暦
   * @param month
   *          月
   * @param weekNum
   *          第何回/週または最終回/週
   * @param dowCode
   *          曜日/平日/週末コード
   * @return 該当する日
   */
  private static int getDayForMonthlyWeekPattern(int year, int month, String weekNum, String dowCode) {
    month = month - 1;
    int day = 0;
    if (DayType.WEEKDAY.getCode().equals(dowCode)) {
      // 平日の場合
      day = getDayForWeekDay(year, month, weekNum);
    } else if (DayType.WEEKEND.getCode().equals(dowCode)) {
      // 週末の場合
      day = getDayForWeekEnd(year, month, weekNum);
    } else {
      // 曜日の場合
      day = getDayForWeekOfMonthAndDayOfWeek(year, month, weekNum, Integer.parseInt(dowCode));
    }
    return day;
  }

  // Cパターン
  /**
   * 判定日の月が、開始日の月間隔が示す月に該当するか判定します。
   * 
   * @param target
   *          判定日
   * @param startDate
   *          開始日
   * @param intervalMonth
   *          月間隔
   * @return 該当する場合true、そうでない場合false
   */
  private static boolean isApplicateMonth(Date target, Date startDate, int intervalMonth) {

    int diff = differenceMonth(target, startDate);

    if (diff % intervalMonth == 0) {
      return true;
    }
    return false;
  }

  /**
   * 2つの日付の月数の差を求めます。 java.util.Date 型の日付 date1 - date2 が何ヵ月かを整数で返します。
   * ※端数の日数は無視します。
   * 
   * @param date1
   *          日付1 java.util.Date
   * @param date2
   *          日付2 java.util.Date
   * @return 2つの日付の月数の差
   */
  // Cパターン
  private static int differenceMonth(Date date1, Date date2) {

    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(date1);
    cal1.set(Calendar.DATE, 1);
    cal1.set(Calendar.HOUR_OF_DAY, 0);
    cal1.set(Calendar.MINUTE, 0);
    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(date2);
    cal2.set(Calendar.DATE, 1);
    cal2.set(Calendar.HOUR_OF_DAY, 0);
    cal2.set(Calendar.MINUTE, 0);

    int count = 0;
    if (cal1.before(cal2)) {
      while (cal1.before(cal2)) {
        cal1.add(Calendar.MONTH, 1);
        count--;
      }
    } else {
      count--;
      while (!cal1.before(cal2)) {
        cal1.add(Calendar.MONTH, -1);
        count++;
      }
    }
    return count;
  }

  /**
   * targetDateが表示対象の日付かをチェックする。
   * 
   * For Aパターン
   * 
   * @return true:表示対象である false:表示対象でない
   * 
   */
  private static boolean isApplicateDayForA(Date targetDate, Date startDate, int interval) {

    if (interval == 0) {
      return false;
    }

    boolean result = true;

    int days = differenceDays(targetDate, startDate);

    if (days < 0) {
      return false;
    }

    if (days % interval != 0) {
      result = false;
    }

    return result;
  }

  // Aパターン

  /**
   * 日付の差を取得します（date1 - date2）。
   * 
   * @param date1
   *          引かれる日
   * @param date2
   *          引く日
   * @return 引かれる日-引く日の日数
   */
  // change start No.4 スケジュール印刷（週単位）
  // private static int differenceDays(Date date1, Date date2) {
  public static int differenceDays(Date date1, Date date2) {
    // change end No.4 スケジュール印刷（週単位）

    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    Date wDate1 = cal.getTime();

    cal.setTime(date2);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    Date wDate2 = cal.getTime();

    long datetime1 = wDate1.getTime();
    long datetime2 = wDate2.getTime();
    long one_date_time = 1000 * 60 * 60 * 24;
    long diffDays = (datetime1 - datetime2) / one_date_time;
    return (int) diffDays;
  }

  // add start No.4 スケジュール印刷（週単位）
  /**
   * 時間の差（分単位）を取得します（date2 - date1）。
   * 
   * @param date1
   *          引かれる日時
   * @param date2
   *          引く日時
   * @return 引かれる日時-引く日時の分数
   */
  public static int differenceMinutes(Date date1, Date date2) {

    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    Date wDate1 = cal.getTime();

    cal.setTime(date2);
    Date wDate2 = cal.getTime();

    long datetime1 = wDate1.getTime();
    long datetime2 = wDate2.getTime();
    long one_date_time = 1000 * 60;
    long diffMinutes = (datetime2 - datetime1) / one_date_time;
    return (int) diffMinutes;
  }

  // add end

  /**
   * targetDateが表示対象の日付かをチェックする。
   * 
   * For Bパターン BxxnnnnnnnL
   * 
   * @param targetDate
   *          判定日
   * @param startDate
   *          開始時間
   * @param ptn
   *          繰り返しパターン
   * @return true:表示対象である false:表示対象でない
   */
  private static boolean isApplicateWeek(Date targetDate, Date startDate, String ptn) {

    Calendar cal = Calendar.getInstance();
    cal.setTime(targetDate);
    int dow = cal.get(Calendar.DAY_OF_WEEK);
    boolean result = false;
    result = ptn.charAt(2 + dow) != '0';

    if (!result) {
      return result;
    }

    int interval = Integer.parseInt(String.valueOf(ptn.substring(1, 3)));
    if (interval == 0) {
      return false;
    }

    int weekNo = differenceWeeks(move2Sunday(targetDate), move2Sunday(startDate));

    if (weekNo % interval != 0) {
      result = false;
    }

    return result;
  }

  /**
   * 渡された日付（日曜日でアライメント済み）の週差を取得する。
   * 
   * For Bパターン
   * 
   * @param date1
   *          日付 java.util.Date
   * @param date2
   *          日付 java.util.Date
   * @return 2つの日付の差
   */
  private static int differenceWeeks(Date date1, Date date2) {

    Calendar cal = Calendar.getInstance();
    cal.setTime(date1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    date1 = cal.getTime();

    cal.setTime(date2);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    date2 = cal.getTime();

    long datetime1 = date1.getTime();
    long datetime2 = date2.getTime();
    long one_date_time = 1000 * 60 * 60 * 24;
    long diffDays = (datetime1 - datetime2) / one_date_time;
    return (int) diffDays / 7;
  }

  /**
   * 渡された日付の週の日曜日の日付を取得する。
   * 
   * For Bパターン
   * 
   */
  private static Date move2Sunday(Date src) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(src);
    int dow = cal1.get(Calendar.DAY_OF_WEEK);
    int diff = dow - Calendar.SUNDAY;
    cal1.add(Calendar.DAY_OF_MONTH, -diff);
    return cal1.getTime();
  }

  /**
   * ユーザー予定権限取得[AIPO_COM_001]
   * 
   * @param srcUser
   *          予定を照会する側のユーザーID
   * @param dstUser
   *          予定を照会される側のユーザーID
   * @return 本人/秘書/公開/不可
   * 
   */
  public static String getScheduleAcl(String srcUser, String dstUser) {
    if (srcUser.equals(dstUser)) {
      return ScheduleConst.SCHEDULE_ACL_MYSELF;
    }

    SelectQuery<AvzTScheduleAcl> query = Database.query(AvzTScheduleAcl.class);
    Expression exp1 = ExpressionFactory.matchExp(AvzTScheduleAcl.USER_ID_PROPERTY, dstUser);
    query.setQualifier(exp1);
    query.orderDesending(AvzTScheduleAcl.ACL_TYPE_PROPERTY);
    query.orderAscending(AvzTScheduleAcl.TARGET_TYPE_PROPERTY);

    List<AvzTScheduleAcl> list = query.fetchList();

    List<AvzTScheduleAcl> listPublic = new ArrayList<AvzTScheduleAcl>(0);

    if (list != null) {

      // <公開設定一覧>より<権限種類>=[編集]である<公開設定>を取得
      for (AvzTScheduleAcl acl : list) {
        if (ScheduleConst.SCHEDULEACL_ACL_UPDATE.equals(acl.getAclType()) && srcUser.equals(acl.getTargetId().toString())) {
          return ScheduleConst.SCHEDULE_ACL_SECRETARY;
        }
      }

      // <公開設定一覧>より<権限種類>=[参照]である<公開設定>を取得
      for (AvzTScheduleAcl acl : list) {
        if (ScheduleConst.SCHEDULEACL_ACL_REF.equals(acl.getAclType())) {
          listPublic.add(acl);
        }
      }

      // 公開設定が０件なら、「公開」扱いとする。
      if (listPublic.size() == 0) {
        return ScheduleConst.SCHEDULE_ACL_PUBLIC;
      }

      List<Integer> listPublicGroupSendId = new ArrayList<Integer>(0);
      for (AvzTScheduleAcl acl : listPublic) {
        if (ScheduleConst.SCHEDULEACL_TARGET_GROUP.equals(acl.getTargetType())) {
          listPublicGroupSendId.add(acl.getTargetId());
        }
      }

      if (listPublicGroupSendId.size() > 0) {
        // 照会ユーザーが公開先グループに含まれるか判定する。
        SelectQuery<AvzMUserGroupsend> query2 = Database.query(AvzMUserGroupsend.class);
        Expression exp2 = ExpressionFactory.inExp(AvzMUserGroupsend.GROUPSEND_ID_PROPERTY, listPublicGroupSendId);
        Expression exp3 = ExpressionFactory.matchExp(AvzMUserGroupsend.USER_ID_PROPERTY, srcUser);
        query2.setQualifier(exp2.andExp(exp3));

        AvzMUserGroupsend e = query2.fetchSingle();
        if (e != null) {
          return ScheduleConst.SCHEDULE_ACL_PUBLIC;
        }
      }
      // <ユーザー公開設定一覧>より<適用ID>が<照会ユーザーID>と一致するレコードを検索
      for (AvzTScheduleAcl acl : listPublic) {
        if (ScheduleConst.SCHEDULEACL_ACL_REF.equals(acl.getAclType()) && srcUser.equals(acl.getTargetId().toString())) {
          return ScheduleConst.SCHEDULE_ACL_PUBLIC;
        }
      }
    } else {
      // スケジュール制御レコードが１件も登録されていなければ「公開」
      return ScheduleConst.SCHEDULE_ACL_PUBLIC;
    }

    // 秘書・公開判定でいずれの条件にも合致しない場合は「不可」
    return ScheduleConst.SCHEDULE_ACL_REFUSAL;
  }

  /**
   * ユーザー情報でソートされた、スケジュールの参加メンバー（スケジュールマップ）一覧を取得[AIPO_COM_006]
   * 
   * @param scheduleId
   *          検索条件のスケジュールID
   * @return 参加メンバー（スケジュールマップ）一覧
   * @throws ALDBErrorException
   *           DBエラーが発生した場合
   */
  public static List<EipTScheduleMap> getEipTScheduleMapsByUserInfoSort(Integer scheduleId) throws ALDBErrorException {

    List<EipTScheduleMap> smList = null;

    try {
      final String memberSql =
        "SELECT " + " A.ID, A.SCHEDULE_ID, A.USER_ID, A.STATUS, A.TYPE, A.COMMON_CATEGORY_ID, A.REQUIRED, A.PRIORITY, A.DUMMY_NON_RESPONSE "
        // add start 要件No.26 スケジュール個別色換え
          + " , A.INDIVIDUAL_COLOR "
          // add end
          + " FROM EIP_T_SCHEDULE_MAP as A, TURBINE_USER as B, EIP_M_USER_POSITION as C "
          + " WHERE A.SCHEDULE_ID = #bind($scheduleId 'INTEGER') "
          + "   AND A.STATUS != '"
          + ScheduleConst.SCHEDULEMAP_STATUS_DUMMY
          + "' "
          + "   AND A.TYPE = '"
          + SCHEDULEMAP_TYPE_USER
          + "' "
          + "   AND A.USER_ID = B.USER_ID "
          + "   AND B.USER_ID = C.USER_ID "
          + " ORDER BY B.DISPLAY_NAME, C.POSITION ";
      SQLTemplate<EipTScheduleMap> smQuery = new SQLTemplate<EipTScheduleMap>(EipTScheduleMap.class, memberSql);
      smList = smQuery.param("scheduleId", scheduleId).fetchList();

    } catch (Exception ex) {
      logger.error("ユーザー情報でソートしたスケジュールマップの取得でDBエラーが発生しました。スケジュールID:" + scheduleId, ex);
      throw new ALDBErrorException();
    }

    return smList;

  }

  /**
   * スケジュール参加メンバー一覧取得
   * 
   * @param scheduleId
   *          scheduleId 検索条件のスケジュールID
   * @return スケジュール参加メンバー一覧
   * @throws ALDBErrorException
   *           DBエラーが発生した場合
   */
  public static List<ScheduleMemberUser> getScheduleMemberUsers(Integer scheduleId) throws ALDBErrorException {
    List<ScheduleMemberUser> smUserList = new ArrayList<ScheduleMemberUser>(0);
    List<EipTScheduleMap> smList = null;
    try {
      smList = getEipTScheduleMapsByUserInfoSort(scheduleId);
      for (EipTScheduleMap sm : smList) {
        ScheduleMemberUser smUser = new ScheduleMemberUser();
        TurbineUser tuser = Database.get(TurbineUser.class, sm.getUserId());
        smUser.initField();
        smUser.setUserId(tuser.getUserId().intValue());
        smUser.setName(tuser.getLoginName());
        smUser.setAliasName(tuser.getFirstName(), tuser.getLastName());
        smUser.setScheduleId(sm.getScheduleId());
        smUser.setStatus(sm.getStatus());
        smUser.setRequired(sm.getRequired());
        smUser.setPriority(sm.getPriority());
        smUser.setDummyNonResponse(sm.getDummyNonResponse());
        // add start 要件No.26 スケジュール個別色換え
        smUser.setIndividualColor(sm.getIndividualColor());
        // add end
        smUserList.add(smUser);
      }
    } catch (Exception e) {
      logger.error("スケジュール参加メンバーの取得でDBエラーが発生しました。スケジュールID:" + scheduleId, e);
      throw new ALDBErrorException();
    }
    return smUserList;
  }

  /**
   * 月間隔定型文字取得
   * 
   * @param month
   *          月間隔
   * @return 月間隔定型文字
   */
  public static String getMonthlyFixedText(String month) {
    String result = "";
    try {
      int num = Integer.parseInt(month);
      if (num == 1) {
        result = "毎月";
      } else {
        result = num + "か月毎";
      }
    } catch (NumberFormatException e) {
      // 変換できない場合は空文字を返す
    }
    return result;
  }

  /**
   * 日付定型文字取得
   * 
   * @param day
   *          日付（月の日）
   * @return 日付定型文字
   */
  public static String getDayFixedText(String day) {
    String result = "";
    try {
      if (ScheduleConst.SCHEDULE_REPEAT_PATTERN_LAST.equals(day)) {
        result = ScheduleConst.SCHEDULE_REPEAT_PATTERN_LAST_NAME;
      } else {
        result = Integer.parseInt(day) + "日";
      }
    } catch (NumberFormatException e) {
      // 変換できない場合は空文字を返す
    }
    return result;
  }

  /**
   * 第何週定型文字取得
   * 
   * @param weekNumber
   *          第何週（第1から最終）のコード
   * @return 第何週定型文字
   */
  public static String getWeekNumberFixedText(String weekNumber) {
    String result = "";
    for (ScheduleWeekNumber swn : ScheduleWeekNumber.values()) {
      if (swn.getCode().equals(weekNumber)) {
        result = swn.getName();
        break;
      }
    }
    return result;
  }

  /**
   * 曜日定型文字取得
   * 
   * @param dowCode
   *          曜日コード（1から7、A、B）
   * @return 曜日定型文字
   */
  public static String getDayOfWeekFixedText(String dowCode) {
    String result = "";
    try {
      int dowNum = Integer.parseInt(dowCode);
      // 数値の場合、曜日文字に変換
      for (DayOfWeek dow : DayOfWeek.values()) {
        if (dow.getNumber() == dowNum) {
          result = dow.getLongName();
          break;
        }
      }
    } catch (NumberFormatException e) {
      // 数値でない場合、日種類に変換
      for (DayType dt : DayType.values()) {
        if (dt.getCode().equals(dowCode)) {
          result = dt.getName();
          break;
        }
      }
    }
    return result;
  }

  /**
   * 年間月定型文字取得
   * 
   * @param month
   *          月
   * @return 年間月定型文字
   */
  public static String getYearlyMonthFixedText(String month) {
    String result = "";
    try {
      int num = Integer.parseInt(month);
      result = "毎年" + num + "月";
    } catch (NumberFormatException e) {
      // 変換できない場合は空文字を返す
    }
    return result;
  }

  /**
   * 繰り返し予定定型文取得
   * 
   * @param ptn
   *          繰り返しパターン
   * @return 繰り返し予定定型文。繰り返し予定以外の場合は空文字を返します。
   */
  public static String getRepeatScheduleFixedText(String ptn) {

    if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_ONEDAY)
      || ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_SPAN)
      || ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_DAYS)) {
      // 単発、期間、日またぎは空文字を返す
      return "";
    }

    StringBuffer fixedString = new StringBuffer();
    if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_DAILY)) {
      // 日パターン AxxxL
      int num = Integer.parseInt(ptn.substring(1, 4));
      if (num == 1) {
        fixedString.append("毎日");
      } else {
        fixedString.append(num + "日毎");
      }
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_WEEKLY)) {
      // 週パターン BxxnnnnnnnL
      final int dowStartIndex = 2;
      int num = Integer.parseInt(ptn.substring(1, 3));
      if (num == 1) {
        fixedString.append("毎週 ");
      } else {
        fixedString.append(num + "週毎 ");
      }
      // 曜日の数分、フラグを変換
      for (DayOfWeek dow : DayOfWeek.values()) {
        fixedString.append(ptn.charAt(dowStartIndex + dow.getNumber()) == '1' ? dow.getShortName() : "");
      }
      fixedString.append("曜日");
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_MONTHLY_DAY)) {
      // 月パターン日指定 xヶ月ごとの dd日に設定 CxxddL
      // 月間隔
      fixedString.append(getMonthlyFixedText(ptn.substring(1, 3)) + " ");
      // 日付
      fixedString.append(getDayFixedText(ptn.substring(3, 5)));
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_MONTHLY_WEEK)) {
      // 月パターン曜日指定 Xヶ月ごとの 第Y Z曜日に設定 ExxWyzL
      // 月間隔
      fixedString.append(getMonthlyFixedText(ptn.substring(1, 3)) + " ");
      // 週
      fixedString.append(getWeekNumberFixedText(ptn.substring(4, 5)) + " ");
      // 曜日
      fixedString.append(getDayOfWeekFixedText(ptn.substring(5, 6)));
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_YEARLY_DAY)) {
      // 年パターン月・日指定 X月Y日に設定 FmmddL
      // 月
      fixedString.append(getYearlyMonthFixedText(ptn.substring(1, 3)) + " ");
      // 日付
      fixedString.append(getDayFixedText(ptn.substring(3, 5)));
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_YEARLY_WEEK)) {
      // 年パターン月・曜日指定 X月第Y Z曜日に設定 GmmWyzL
      // 月
      fixedString.append(getYearlyMonthFixedText(ptn.substring(1, 3)) + " ");
      // 週
      fixedString.append(getWeekNumberFixedText(ptn.substring(4, 5)) + " ");
      // 曜日
      fixedString.append(getDayOfWeekFixedText(ptn.substring(5, 6)));
    }
    return fixedString.toString();
  }

  /**
   * 有効期限終了日の定型文取得
   * 
   * @param endDate
   *          終了日
   * @param format
   *          終了日表示時のフォーマット
   * @return 有効期限終了日の定型文
   */
  public static String getRepeatLimitEndDateFixedText(Date endDate, String format) {

    String result = "";
    SimpleDateFormat f = new SimpleDateFormat("yyyyMMdd");
    String chkDate = f.format(endDate);
    // 終了日未定日時か判定
    if (ScheduleConst.SCHEDULE_LIMIT_ENDDATE_NONEND.equals(chkDate)) {
      // 終了日未定表示
      result = ScheduleLimitPattern.NON_END.getName();
    } else {
      // 反復回数および終了日指定の場合、指定フォーマットで終了日表示
      f.applyPattern(format);
      result = f.format(endDate);
    }
    return result;
  }

  /**
   * 有効期限の定型文取得
   * 
   * @param startDate
   *          開始時間
   * @param endDate
   *          終了時間
   * @param dateFormat
   *          日付フォーマット
   * @param period
   *          期間文字
   * @return 有効期限の定型文（開始日+期間文字+有効期限終了日の定型文）
   */
  public static String getScheduleLimitDateFixedText(Date startDate, Date endDate, String dateFormat, String period) {
    String result = "";
    SimpleDateFormat f = new SimpleDateFormat(dateFormat);
    result = f.format(startDate) + period + getRepeatLimitEndDateFixedText(endDate, dateFormat);
    return result;
  }

  /**
   * 繰り返しパターン別のスケジュール時間帯定型文を返します。
   * 
   * @param ptn
   *          繰り返しパターン
   * @param startDate
   *          スケジュール.開始時間
   * @param endDate
   *          スケジュール.終了時間
   * @param dateFormat
   *          日付フォーマット
   * @param timeFormat
   *          時刻フォーマット
   * @param period
   *          期間文字
   * @return スケジュール時間帯定型文
   */
  public static String getScheduleDateTimeFixedText(String ptn, Date startDate, Date endDate, String dateFormat, String timeFormat, String period) {
    String result = "";
    SimpleDateFormat df = new SimpleDateFormat(dateFormat);
    SimpleDateFormat tf = new SimpleDateFormat(timeFormat);
    if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_ONEDAY)) {
      // 単発の場合[{開始日}+半角スペース+{開始時刻}+{期間文字}+{終了時刻}]
      result = df.format(startDate) + " " + tf.format(startDate) + period + tf.format(endDate);
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_SPAN)) {
      // 期間の場合[{開始日}+{期間文字}+{終了日}]
      result = df.format(startDate) + period + df.format(endDate);
    } else if (ptn.startsWith(ScheduleConst.SCHEDULE_PATTERN_DAYS)) {
      // 日またぎの場合[{開始日}+半角スペース+{開始時刻}+{期間文字}+{終了日}+半角スペース+{終了時刻}]
      result = df.format(startDate) + " " + tf.format(startDate) + period + df.format(endDate) + " " + tf.format(endDate);
    } else {
      // 繰り返しの場合[{開始時刻}+{期間文字}+{終了時刻}]
      result = tf.format(startDate) + period + tf.format(endDate);
    }
    return result;
  }

  /**
   * スケジュールポートレット用メール送信（削除以外）
   * 
   * @param sendToUserList
   *          メール送信先一覧
   * @param sendFromUserId
   *          メール送信元ID
   * @param sc
   *          送信情報にあたるスケジュール
   * @param reqMember
   *          スケジュールの必須参加メンバー
   * @param subMember
   *          スケジュールの任意参加メンバー
   * @param subjectActionText
   *          件名アクション文
   * @param actionText
   *          アクション文
   * @param rundata
   *          実行データ
   * @param comment
   *          返信コメント もしくは 削除理由
   * @param mode
   *          会議案内／回答メール／代理会議案内／代理回答メール
   * @return メール送信に成功した場合true、そうでない場合false
   */
  // change start No.1 スケジュール案内受信
  // public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList,
  // int sendFromUserId, EipTSchedule sc, List<? extends ALEipUser> reqMember,
  // List<? extends ALEipUser> subMember, String subjectActionText,
  // String actionText, RunData rundata) {
  public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList, int sendFromUserId, EipTSchedule sc, List<? extends ALEipUser> reqMember,
      List<? extends ALEipUser> subMember, String subjectActionText, String actionText, RunData rundata, String comment, int mode) {
    // change end
    // 「スケジュールポートレット用メール送信処理」本体を削除メール以外で実行
    return sendScheduleMail(sendToUserList, sendFromUserId, 0, sc, reqMember, subMember, subjectActionText, actionText, rundata, false,
    // add start No.1 スケジュール案内受信
      comment,
      mode
    // add end
    );
  }

  /**
   * スケジュールポートレット用メール送信（削除以外）
   * 
   * @param sendToUserList
   *          メール送信先一覧
   * @param sendFromUserId
   *          メール送信元ID
   * @param clientUserId
   *          秘書設定元ユーザーID（秘書が代理回答した以外は0）
   * @param sc
   *          送信情報にあたるスケジュール
   * @param reqMember
   *          スケジュールの必須参加メンバー
   * @param subMember
   *          スケジュールの任意参加メンバー
   * @param subjectActionText
   *          件名アクション文
   * @param actionText
   *          アクション文
   * @param rundata
   *          実行データ
   * @param comment
   *          返信コメント もしくは 削除理由
   * @param mode
   *          会議案内／回答メール／代理会議案内／代理回答メール
   * @return メール送信に成功した場合true、そうでない場合false
   */
  // change start No.1 スケジュール案内受信
  // public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList,
  // int sendFromUserId, int clientUserId, EipTSchedule sc,
  // List<? extends ALEipUser> reqMember, List<? extends ALEipUser> subMember,
  // String subjectActionText, String actionText, RunData rundata) {
  public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList, int sendFromUserId, int clientUserId, EipTSchedule sc,
      List<? extends ALEipUser> reqMember, List<? extends ALEipUser> subMember, String subjectActionText, String actionText, RunData rundata, String comment,
      int mode) {
    // 「スケジュールポートレット用メール送信処理」本体を削除メール以外で実行
    return sendScheduleMail(sendToUserList, sendFromUserId, clientUserId, sc, reqMember, subMember, subjectActionText, actionText, rundata, false,
    // add start No.1 スケジュール案内受信
      comment,
      mode
    // add end
    );
  }

  /**
   * スケジュールポートレット用メール送信
   * 
   * @param sendToUserList
   *          メール送信先一覧
   * @param sendFromUserId
   *          メール送信元ID
   * @param clientUserId
   *          秘書設定元ユーザーID（秘書が代理回答した以外は0）
   * @param sc
   *          送信情報にあたるスケジュール
   * @param reqMember
   *          スケジュールの必須参加メンバー
   * @param subMember
   *          スケジュールの任意参加メンバー
   * @param subjectActionText
   *          件名アクション文
   * @param actionText
   *          アクション文
   * @param rundata
   *          実行データ
   * @param isDelete
   *          削除メールの場合trueを設定（スケジュール詳細へのリンクを出力しない）
   * @param comment
   *          返信コメント もしくは 削除理由
   * @param mode
   *          会議案内／回答メール／代理会議案内／代理回答メール
   * @return メール送信に成功した場合true、そうでない場合false
   */
  // change start No.1 スケジュール案内受信
  // public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList,
  // int sendFromUserId, int clientUserId, EipTSchedule sc,
  // List<? extends ALEipUser> reqMember, List<? extends ALEipUser> subMember,
  // String subjectActionText, String actionText, RunData rundata,
  // boolean isDelete) {
  public static boolean sendScheduleMail(List<ALEipUserAddr> sendToUserList, int sendFromUserId, int clientUserId, EipTSchedule sc,
      List<? extends ALEipUser> reqMember, List<? extends ALEipUser> subMember, String subjectActionText, String actionText, RunData rundata, boolean isDelete,
      String comment, int mode) {
    // change end
    boolean result = true;
    StringBuffer subject = new StringBuffer();
    String orgId = Database.getDomainName();
    String body = "";
    String errMsgBody =
      "メールを送信できませんでした。ログインユーザー:" + ALEipUtils.getALEipUser(rundata).getName() + "/送信元ユーザーID:" + sendFromUserId + "/スケジュールID:" + sc.getScheduleId();
    try {
      // 日付・時間帯の出力定型文を作成
      String dateTimeText = "";
      String dateTime = getScheduleDateTimeFixedText(sc.getRepeatPattern(), sc.getStartDate(), sc.getEndDate(), "yyyy/M/d", "H:mm", "～");
      String repeatText = getRepeatScheduleFixedText(sc.getRepeatPattern());
      if ("".equals(repeatText)) {
        // 繰り返し文字が得られない場合は、[{時間帯}]のフォーマットにする
        dateTimeText = dateTime;
      } else {
        // 繰り返し文字が得られた場合は、[{繰り返し文字}+半角スペース+{時間帯}]のフォーマットにする
        dateTimeText = repeatText + " " + dateTime;
      }

      // 場所を作成
      String place = sc.getPlace() != null && !"".equals(sc.getPlace()) ? "（" + sc.getPlace() + "）" : "";

      // メール件名作成
      // subject.append("[" + ALOrgUtilsService.getAlias() + "]").append(
      // subjectActionText).append(" ").append(dateTimeText).append(" ").append(
      // sc.getName()).append(place);
      // change start 要件No.1 スケジュール案内受信
      // String subject_prefix = "会議案内";
      String subject_prefix = "会議";
      // change end
      // remove start 要件No.1 スケジュール案内受信 参加メンバーを削除して１名になると"予定"になってしまうため
      // if ((reqMember.size() + subMember.size()) == 1) {
      // subject_prefix = "予定";
      // }
      // remove end

      // change start 要件No.1 スケジュール案内受信
      // subject
      // .append("[" + subject_prefix + "]")
      // .append(subjectActionText)
      // .append(" ")
      // .append(dateTimeText)
      // .append(" ")
      // .append(sc.getName())
      // .append(place);
      if (mode == CREATE_MSG_MODE_REQ || mode == CREATE_MSG_MODE_SUBREQ) {
        subject.append("[" + subject_prefix + subjectActionText + "]").append(sc.getName()).append(" ").append(dateTimeText).append(" ").append(place);
      } else {
        subject.append("[" + subjectActionText + "]").append(" ").append(sc.getName()).append(" ").append(dateTimeText).append(" ").append(place);
      }
      // change end

      // メール本文作成
      body = createMsgForPc(sendFromUserId, clientUserId, sc, reqMember, subMember, actionText, subjectActionText, rundata, isDelete,
      // add start No.1 スケジュール案内受信
        comment,
        mode
      // add end
        );

      // 送信メール一覧を作成
      List<ALAdminMailMessage> messageList = new ArrayList<ALAdminMailMessage>();
      for (ALEipUserAddr sendToUser : sendToUserList) {
        ALAdminMailMessage message = new ALAdminMailMessage(sendToUser);
        message.setDisplayName(sendToUser.getDisplayName());
        message.setPcSubject(subject.toString());
        // change start 運用フェーズ課題・障害台帳No.135対応
        // message.setPcBody(String.format(body, sendToUser.getUserId()));
        String processBody = body;
        if (!isDelete) {
          // 会議削除案内の場合は詳細URLが無いためスキップする
          processBody = replaceLast(body, "%1$d", sendToUser.getUserId().toString());
          processBody = replaceLast(processBody, "%1$d", sendToUser.getUserId().toString());
        }
        message.setPcBody(processBody);
        // change end
        message.setCellularSubject(subject.toString());
        // change start 運用フェーズ課題・障害台帳No.135対応
        // message.setCellularBody(String.format(body, sendToUser.getUserId()));
        message.setCellularBody(processBody);
        // change end
        messageList.add(message);
      }

      // メール送信
      List<String> errorMsgList = sendMailFromAipoMailInfo(orgId, ALMailUtils.getSendDestType(ALMailUtils.KEY_MSGTYPE_SCHEDULE), sendFromUserId, messageList,
      // add start 要件No.1 スケジュール案内受信
        mode
      // add end
        );

      // メール送信処理戻り値のエラーメッセージが1件以上有る場合は、メール送信エラー扱いにする
      if (errorMsgList.size() > 0) {
        String mailErr = "/メール送信エラー詳細:";
        int i = 1;
        for (String errorMsg : errorMsgList) {
          if (i > 1) {
            mailErr += ",";
          }
          mailErr += errorMsg;
          i++;
        }
        logger.error(errMsgBody + mailErr);
        result = false;
      }

    } catch (Exception e) {
      logger.error(errMsgBody, e);
      result = false;
    }
    return result;
  }

  /**
   * Aipo全体のメール情報を使用してメールを送信します。
   * 
   * @param orgId
   *          データベースID
   * @param destType
   *          送信先タイプ
   * @param sendFromUserId
   *          送信元ユーザー
   * @param messageList
   *          メールメッセージ情報（送信先メールアドレス、件名、本文）一覧
   * @param mode
   *          会議案内／回答メール／代理会議案内／代理回答メール
   * @return エラーメッセージ一覧。エラーが無い場合は0件のリスト。
   */
  // change start 要件No.1 スケジュール案内受信
  // public static List<String> sendMailFromAipoMailInfo(String orgId,
  // int destType, int sendFromUserId, List<ALAdminMailMessage> messageList) {
  public static List<String> sendMailFromAipoMailInfo(String orgId, int destType, int sendFromUserId, List<ALAdminMailMessage> messageList, int mode) {
    // change end
    List<String> errMsgList = new ArrayList<String>(0);
    Integer sendToUserId = null;

    // メール送信先が0件の場合は正常終了する。
    if (messageList == null || messageList.size() == 0) {
      return errMsgList;
    }

    try {
      // メール送信元情報取得
      ALEipUserAddr sendFromUserAddr = ALMailUtils.getALEipUserAddrByUserId(sendFromUserId);

      // 実際の送信アカウント情報取得
      EipMMailAccount account = ALMailUtils.getEipMMailAccountForAdmin();
      if (null == account) {
        errMsgList.add("Aipo全体のメールアカウントが設定されていないため、メールを送信できませんでした。");
        return errMsgList;
      }
      // メール送信情報設定
      ALMailSenderContext scontext = ALMailUtils.getALSmtpMailSenderContext(orgId, account);
      if (null == scontext) {
        errMsgList.add("メール送信情報が取得できないため、メールを送信できませんでした。");
        return errMsgList;
      }

      // メール送信ハンドラ生成
      ALMailHandler handler = ALMailFactoryService.getInstance().getMailHandler();

      int result = ALSmtpMailSender.SEND_MSG_SUCCESS;

      // メール送信実行
      // パソコンへメールを送信
      if ((destType == ALMailUtils.VALUE_MSGTYPE_DEST_PC || destType == ALMailUtils.VALUE_MSGTYPE_DEST_PC_CELLULAR)) {
        for (ALAdminMailMessage message : messageList) {
          if (!ALEipUtils.isEnabledUser(message.getUserId())) {
            continue;
          }

          // add by motegi 2011.1122
          if (sendFromUserId == message.getUserId().intValue()) {
            continue;
          }
          // add end

          String emailAddr = message.getPcMailAddrWithName();
          if (emailAddr == null || emailAddr.equals("")) {
            continue;
          }
          String[] tos = new String[] { emailAddr };

          // PC用送信メッセージ情報
          // ALSmtpMailContext mailcontext =
          // ALMailUtils.getALSmtpMailContext(
          // tos,
          // null,
          // null,
          // sendFromUserAddr.getPcMailAddr(),
          // sendFromUserAddr.getDisplayName().trim(),
          // ALStringUtil.unsanitizing(message.getPcSubject()),
          // ALStringUtil.unsanitizing(message.getPcBody()),
          // null,
          // null);
          Map<String, String> map = new HashMap<String, String>();
          map.put("X-Aipo-Portlet", "Schedule");
          // add start 要件No.1 スケジュール案内受信
          String directLink = "false";
          if (mode == CREATE_MSG_MODE_REQ) {
            directLink = "true";
          }
          map.put("X-Aipo-Portlet-Schedule-DirectLink", directLink);
          // add end

          ALSmtpMailContext mailcontext =
            ALMailUtils.getALSmtpMailContext(tos, null, null, sendFromUserAddr.getPcMailAddr(), sendFromUserAddr.getDisplayName().trim(), ALStringUtil
              .unsanitizing(message.getPcSubject()), ALStringUtil.unsanitizing(message.getPcBody()), null, map);

          result = handler.send(scontext, mailcontext);

          if (result == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
            errMsgList.add("メールサイズが送信可能サイズよりも大きいため、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          } else if (result == ALSmtpMailSender.SEND_MSG_LOCK) {
            errMsgList.add("ロックがかかっていて、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
            errMsgList.add("Pop before SMTPの認証に失敗したため、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
            errMsgList.add("SMTP認証の認証に失敗したため、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
            errMsgList.add("Aipo全体のメールアカウントが正しく設定されていないため、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result != ALSmtpMailSender.SEND_MSG_SUCCESS) {
            errMsgList.add("メール送信に失敗したため、PCメールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          }
        }
      }

      // 携帯電話へメールを送信
      if ((destType == ALMailUtils.VALUE_MSGTYPE_DEST_CELLULAR || destType == ALMailUtils.VALUE_MSGTYPE_DEST_PC_CELLULAR)) {
        for (ALAdminMailMessage message : messageList) {
          sendToUserId = message.getUserId();
          if (!ALEipUtils.isEnabledUser(message.getUserId())) {
            continue;
          }
          String emailAddr = message.getCellMailAddr();
          if (emailAddr == null || emailAddr.equals("")) {
            continue;
          }
          String[] tos = new String[] { emailAddr };

          // 携帯用送信メッセージ情報
          ALSmtpMailContext mailcontext =
            ALMailUtils.getALSmtpMailContext(tos, null, null, sendFromUserAddr.getPcMailAddr(), sendFromUserAddr.getDisplayName().trim(), ALStringUtil
              .unsanitizing(message.getCellularSubject()), ALStringUtil.unsanitizing(message.getCellularBody()), null, null);

          result = handler.send(scontext, mailcontext);

          if (result == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
            errMsgList.add("メールサイズが送信可能サイズよりも大きいため、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          } else if (result == ALSmtpMailSender.SEND_MSG_LOCK) {
            errMsgList.add("ロックがかかっていて、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
            errMsgList.add("Pop before SMTPの認証に失敗したため、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
            errMsgList.add("SMTP認証の認証に失敗したため、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
            errMsgList.add("Aipo全体のメールアカウントが正しく設定されていないため、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
            // 送信元起因のため、処理終了
            break;
          } else if (result != ALSmtpMailSender.SEND_MSG_SUCCESS) {
            errMsgList.add("メール送信に失敗したため、携帯メールアドレスにメールを送信できませんでした。メールアドレス：" + emailAddr);
          }
        }
      }
    } catch (ALDBErrorException e) {
      int errSendToUserId = 0;
      if (null == sendToUserId) {
        errSendToUserId = 0;
      } else {
        errSendToUserId = sendToUserId.intValue();
      }
      logger.error("送信元ユーザー または 送信先ユーザーの情報取得でエラーが発生しました。送信元ユーザーID:" + sendFromUserId + "/送信先ユーザーID:" + errSendToUserId, e);
      errMsgList.add("送信元ユーザー または 送信先ユーザーの情報取得でエラーが発生しました。");
    } catch (Exception e) {
      logger.error("予期せぬエラーが発生しました。送信元ユーザーID:" + sendFromUserId, e);
      errMsgList.add("予期せぬエラーが発生しました。");
    }

    return errMsgList;
  }

  // add end

  // add start 受入障害対応No.197対応
  /**
   * 送信可能memberListを返却します
   * 
   * @param memberList
   *          参加必須、任意メンバー一覧
   * @param scheduleMaps
   *          スケジュールマップ
   * @return 送信可能メンバー一覧
   */
  public static List<ALEipUser> checkMemberList(List<ALEipUser> memberList, List<EipTScheduleMap> scheduleMaps) {

    // memberListの各ユーザーの「状態」を判定し、削除、辞退のユーザーについては
    // memberListから除外
    List<ALEipUser> sendMemberList = new ArrayList<ALEipUser>();
    // List<EipTScheduleMap> scheduleMapss = scheduleMaps;
    for (ALEipUser user : memberList) {
      int userIdOfMemberList = (int) user.getUserId().getValue();
      // TODO add start 運用フェーズ課題・障害台帳No.151
      boolean found = false;
      // add end 運用フェーズ課題・障害台帳No.151
      for (EipTScheduleMap scheduleMap : scheduleMaps) {
        int userIdOfScheduleMap = scheduleMap.getUserId();
        if (userIdOfScheduleMap == userIdOfMemberList) {
          // add start 運用フェーズ課題・障害台帳No.151
          found = true;
          // add end
          String status = scheduleMap.getStatus();
          String dummyNonResponse = scheduleMap.getDummyNonResponse();
          if (!(ScheduleConst.SCHEDULEMAP_STATUS_REMOVE.equals(status) || ScheduleConst.SCHEDULEMAP_STATUS_VETO.equals(status) || ScheduleConst.SCHEDULEMAP_DUMMY_NON_RES_T
            .equals(dummyNonResponse))) {
            sendMemberList.add(user);
          }
        }
      }
      // add start 運用フェーズ課題・障害台帳No.151
      if (!found) {
        // 新規追加メンバー
        sendMemberList.add(user);
      }
      // add end
    }
    return sendMemberList;
  }

  // add end

  // add start 要件No.16 スケジュール画面（月単位／週単位／日単位）右クリックメニュー
  /**
   * スケジュールが共有かチェックする。
   * 
   * @param schedule
   *          スケジュール
   * @return true:共有スケジュール、false:個人スケジュール
   */
  public static boolean isShareSchedule(EipTSchedule schedule) {
    SelectQuery<EipTScheduleMap> mapquery = Database.query(EipTScheduleMap.class);
    Expression mapexp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, schedule.getScheduleId());
    mapquery.setQualifier(mapexp1);
    if (mapquery.getCount() > 1) {
      return true;
    }
    return false;
  }

  // add end

  // add start 要件No.8 スケジュール表示（日単位）
  /**
   * スケジュールポートレット用ユーザー情報Beanを取得します。
   * 
   * @param loginUserId
   *          ログインユーザー（使用ユーザー）のユーザーID
   * @param userId
   *          ユーザーID
   * @return ユーザーIDに該当するスケジュールポートレット用ユーザー情報Bean
   */
  public static ScheduleUserBean getScheduleUserBean(String loginUserId, String userId) {
    ScheduleUserBean bean = null;
    try {
      TurbineUser entity = ALEipUtils.getTurbineUser(Integer.parseInt(userId));
      bean = new ScheduleUserBean();
      bean.setUsetId(entity.getUserId().longValue());
      bean.setLoginName(entity.getLoginName());
      bean.setFirstName(entity.getFirstName());
      bean.setLastName(entity.getLastName());
      bean.setFirstNameKana(entity.getFirstNameKana());
      bean.setLastNameKana(entity.getLastNameKana());
      bean.setCategory(entity.getCategory());
      bean.setDisplayName(entity.getDisplayName());
      try {
        bean.setAccessCtrl(getScheduleAcl(loginUserId, userId));
      } catch (Exception ex) {
        logger.error("閲覧メンバー表示可否判定に失敗しました。ログインユーザーID:" + loginUserId, ex);
      }
    } catch (Exception e) {
      logger.error("スケジュール用ユーザー情報の取得に失敗しました。ログインユーザーID:" + loginUserId + "/ユーザーID:" + userId, e);
    }
    return bean;
  }

  // add end

  // add start 要件No.18 会議案内ファイル添付
  /**
   * 添付ファイル登録処理
   * 
   * @param rundata
   *          JetSpeedランデータ
   * @param context
   *          JetSpeedコンテキスト
   * @param schedule
   *          スケジュール
   * @param fileuploadList
   *          ファイルリスト
   * @param folderName
   *          フォルダー名
   * @param msgList
   *          エラーメッセージリスト
   * @return 追加／削除発生フラグ（発生した：true、発生しない：false）
   * @throws Exception
   */
  public static boolean insertFileDataDelegate(RunData rundata, Context context, EipTSchedule schedule, List<FileuploadLiteBean> fileuploadList,
      String folderName, List<String> msgList) throws Exception {

    boolean causeChange = false;

    if (fileuploadList == null || fileuploadList.size() <= 0) {
      fileuploadList = new ArrayList<FileuploadLiteBean>();
    }

    int uid = schedule.getOwnerId();
    String orgId = Database.getDomainName();

    // 既に登録済みの添付ファイルリストを作成する。
    List<Integer> hadfileids = new ArrayList<Integer>();
    for (FileuploadLiteBean file : fileuploadList) {
      if (!file.isNewFile()) {
        hadfileids.add(file.getFileId());
      }
    }

    // 既に登録済みの添付ファイルから、画面上削除されたものを削除対象リストへ格納する。
    SelectQuery<AvzTScheduleFile> dbquery = Database.query(AvzTScheduleFile.class);
    dbquery.andQualifier(ExpressionFactory.matchDbExp(AvzTScheduleFile.TO_EIP_TSCHEDULE_PROPERTY, schedule.getScheduleId()));
    List<AvzTScheduleFile> existsFiles = dbquery.fetchList();
    List<AvzTScheduleFile> delFiles = new ArrayList<AvzTScheduleFile>();
    for (AvzTScheduleFile file : existsFiles) {
      if (!hadfileids.contains(file.getFileId())) {
        delFiles.add(file);
      }
    }

    // ローカルファイルに保存されているファイルを削除する．
    if (delFiles.size() > 0) {
      int delsize = delFiles.size();
      for (int i = 0; i < delsize; i++) {
        ALStorageService.deleteFile(getSaveDirPath(orgId, uid) + (delFiles.get(i)).getFilePath());
      }
      // データベースから添付ファイルのデータ削除
      Database.deleteAll(delFiles);

      causeChange = true;
    }

    // ファイル追加処理
    try {
      for (FileuploadLiteBean filebean : fileuploadList) {
        if (!filebean.isNewFile()) {
          continue;
        }

        String filename = "0_" + String.valueOf(System.nanoTime());

        // 新規オブジェクトモデル
        AvzTScheduleFile file = Database.create(AvzTScheduleFile.class);
        // 所有者
        file.setOwnerId(Integer.valueOf(uid));
        // トピックID
        file.setToEipTSchedule(schedule);
        // ファイル名
        file.setFileName(filebean.getFileName());
        // ファイルパス
        file.setFilePath(getRelativePath(filename));
        // 作成日
        file.setCreateDate(Calendar.getInstance().getTime());
        // 更新日
        file.setUpdateDate(Calendar.getInstance().getTime());

        // ファイルの移動
        ALStorageService.copyTmpFile(uid, folderName, String.valueOf(filebean.getFileId()), FOLDER_FILEDIR_SCHEDULE, CATEGORY_KEY
          + ALStorageService.separator()
          + uid, filename);

        causeChange = true;
      }

      // 添付ファイル保存先のフォルダを削除
      ALStorageService.deleteTmpFolder(uid, folderName);
    } catch (Exception e) {
      logger.error("添付ファイル処理でエラーが発生しました。", e);
      throw e;
    }
    return causeChange;
  }

  /**
   * ユーザ毎のルート保存先（絶対パス）を取得します。
   * 
   * @param orgId
   *          データベース名
   * @param uid
   *          ユーザーID
   * @return ルート保存先（絶対パス）
   */
  public static String getSaveDirPath(String orgId, int uid) {
    return ALStorageService.getDocumentPath(FOLDER_FILEDIR_SCHEDULE, CATEGORY_KEY + ALStorageService.separator() + uid);
  }

  /**
   * ユーザ毎の保存先（相対パス）を取得します。
   * 
   * @param fileName
   *          ファイル名
   * @return 保存先（相対パス）
   */
  public static String getRelativePath(String fileName) {
    return new StringBuffer().append("/").append(fileName).toString();
  }

  /**
   * 添付ファイル一時保存先のユーザのルートフォルダ
   * 
   * @param orgId
   *          データベース名
   * @param uid
   *          ユーザーID
   * @return フォルダオブジェクト
   */
  public static File getRootFolder(String org_id, int userId) {
    String rootPath = FileuploadUtils.FOLDER_TMP_FOR_ATTACHMENT_FILES + File.separator + org_id + File.separator + userId + File.separator;
    File folder = new File(rootPath);
    if (!folder.exists()) {
      if (!folder.mkdirs()) {
        return null;
      }
    }
    return folder;
  }

  /**
   * 添付ファイルを取得します。
   * 
   * @param rundata
   *          JetSpeedランデータ
   * @return 添付ファイルリスト
   */
  public static ArrayList<FileuploadLiteBean> getFileuploadList(RunData rundata) {
    String[] fileids = rundata.getParameters().getStrings(FileuploadUtils.KEY_FILEUPLOAD_ID_LIST);
    if (fileids == null) {
      return null;
    }

    ArrayList<String> hadfileids = new ArrayList<String>();
    ArrayList<String> newfileids = new ArrayList<String>();

    for (int j = 0; j < fileids.length; j++) {
      if (fileids[j].trim().startsWith("s")) {
        hadfileids.add(fileids[j].trim().substring(1));
      } else {
        newfileids.add(fileids[j].trim());
      }
    }

    ArrayList<FileuploadLiteBean> fileNameList = new ArrayList<FileuploadLiteBean>();
    FileuploadLiteBean filebean = null;

    // 新規にアップロードされたファイルの処理
    if (newfileids.size() > 0) {
      String folderName = rundata.getParameters().getString(FileuploadUtils.KEY_FILEUPLOAD_FODLER_NAME);
      if (folderName == null || folderName.equals("")) {
        return null;
      }

      for (String newfileid : newfileids) {
        if ("".equals(newfileid)) {
          continue;
        }
        int fileid = 0;
        try {
          fileid = Integer.parseInt(newfileid);
        } catch (Exception e) {
          continue;
        }

        if (fileid == 0) {
          filebean = new FileuploadLiteBean();
          filebean.initField();
          filebean.setFolderName("photo");
          filebean.setFileName("以前の写真ファイル");
          fileNameList.add(filebean);
        } else {
          BufferedReader reader = null;
          try {
            reader =
              new BufferedReader(new InputStreamReader(ALStorageService.getFile(FileuploadUtils.FOLDER_TMP_FOR_ATTACHMENT_FILES, ALEipUtils.getUserId(rundata)
                + ALStorageService.separator()
                + folderName, fileid + FileuploadUtils.EXT_FILENAME), FILE_ENCODING));
            String line = reader.readLine();
            if (line == null || line.length() <= 0) {
              continue;
            }
            filebean = new FileuploadLiteBean();
            filebean.initField();
            filebean.setFolderName(newfileid);
            filebean.setFileId(fileid);
            filebean.setFileName(line);
            fileNameList.add(filebean);
          } catch (Exception e) {
            logger.error("Exception", e);
          } finally {
            try {
              reader.close();
            } catch (Exception e) {
              logger.error("Exception", e);
            }
          }
        }
      }
    }

    // すでにあるファイルの処理
    if (hadfileids.size() > 0) {
      ArrayList<Integer> hadfileidsValue = new ArrayList<Integer>();
      for (String hadfileid : hadfileids) {
        int fileid = 0;
        try {
          fileid = Integer.parseInt(hadfileid);
          hadfileidsValue.add(fileid);
        } catch (Exception e) {
          continue;
        }
      }

      try {
        SelectQuery<AvzTScheduleFile> reqquery = Database.query(AvzTScheduleFile.class);
        Expression reqexp1 = ExpressionFactory.inDbExp(AvzTScheduleFile.FILE_ID_PK_COLUMN, hadfileidsValue);
        reqquery.setQualifier(reqexp1);
        List<AvzTScheduleFile> requests = reqquery.fetchList();
        for (AvzTScheduleFile file : requests) {
          filebean = new FileuploadBean();
          filebean.initField();
          filebean.setFileId(file.getFileId());
          filebean.setFileName(file.getFileName());
          filebean.setFlagNewFile(false);
          fileNameList.add(filebean);
        }
      } catch (Exception ex) {
        logger.error("[BlogUtils] Exception.", ex);
      }
    }
    return fileNameList;
  }

  /**
   * ファイルオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   *          JetSpeedランデータ
   * @return ファイルオブジェクトモデル
   */
  public static AvzTScheduleFile getAvzTScheduleFile(RunData rundata) throws ALPageNotFoundException, ALDBErrorException {
    try {
      int attachmentIndex = rundata.getParameters().getInt("attachmentIndex", -1);
      if (attachmentIndex < 0) {
        // ID が空の場合
        logger.debug("[ScheduleUtils] Empty ID...");
        throw new ALPageNotFoundException();

      }

      SelectQuery<AvzTScheduleFile> query = Database.query(AvzTScheduleFile.class);
      Expression exp = ExpressionFactory.matchDbExp(AvzTScheduleFile.FILE_ID_PK_COLUMN, Integer.valueOf(attachmentIndex));
      query.andQualifier(exp);

      List<AvzTScheduleFile> files = query.fetchList();
      if (files == null || files.size() == 0) {
        // 指定した ID のレコードが見つからない場合
        logger.debug("[ScheduleUtils] Not found ID...");
        throw new ALPageNotFoundException();
      }
      return files.get(0);
    } catch (Exception ex) {
      logger.error("[ScheduleUtils]", ex);
      throw new ALDBErrorException();
    }
  }

  /**
   * 一時保存先のファイル名を保存するファイルを作成します（例 s1.txt）
   * 
   * @param dest_file_path
   *          ファイル名
   * @param file
   *          添付ファイルオブジェクト
   * @throws UnsupportedEncodingException
   * @throws FileNotFoundException
   */
  public static void createTempNameFile(String dest_file_path, AvzTScheduleFile file) throws UnsupportedEncodingException, FileNotFoundException {
    PrintWriter writer = null;
    try {
      // 一時添付ファイル名の保存
      writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(dest_file_path + FileuploadUtils.EXT_FILENAME), FileuploadUtils.FILE_ENCODING));
      writer.println(file.getFileName());
      writer.flush();
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
      throw e;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      throw e;
    } finally {
      if (writer != null) {
        writer.close();
      }
    }
  }

  /**
   * ファイルをコピーします。<br />
   * from "c:\\abc.txt"<br />
   * to "c:\\tmp\\abc.txt"
   * 
   * @param from
   *          コピー元
   * @param to
   *          コピー先
   * @return 処理成否
   */
  public static boolean copyFile(File from, File to) {
    boolean res = true;
    FileChannel srcChannel = null;
    FileChannel destChannel = null;

    try {
      srcChannel = new FileInputStream(from).getChannel();
      destChannel = new FileOutputStream(to).getChannel();
      destChannel.transferFrom(srcChannel, 0, srcChannel.size());
    } catch (Exception ex) {
      logger.error("Exception", ex);
      res = false;
    } finally {
      if (destChannel != null) {
        try {
          destChannel.close();
        } catch (IOException ex) {
          logger.error("Exception", ex);
          res = false;
        }
      }
      if (srcChannel != null) {
        try {
          srcChannel.close();
        } catch (IOException ex) {
          logger.error("Exception", ex);
          res = false;
        }
      }
    }

    return res;
  }

  /**
   * 添付ファイル有無チェック
   * 
   * @param schedule
   *          スケジュール
   * @return 添付ファイル有無（true:有り、false:無し）
   */
  public static boolean hasAttachmentFiles(EipTSchedule schedule) {
    String sql =
      "select 1 from eip_t_schedule as t0 "
        + "where exists ( select 1 from avz_t_schedule_file as t1 "
        + "               where t0.schedule_id = t1.schedule_id and t0.schedule_id = #bind($id))";

    List<EipTSchedule> list = Database.sql(EipTSchedule.class, sql).param("id", schedule.getScheduleId()).fetchList();
    if (list == null || list.size() == 0) {
      return false;
    }
    return true;
  }

  /**
   * スケジュール添付ファイルを旧レコードから新レコードへコピーします(DB)。
   * 
   * @param newSchedule
   *          新スケジュール
   * @param srcSchedule
   *          元スケジュール
   * @param newFilesMap
   *          元⇒新の添付ファイルコピー用情報＜元ファイルパス、新ファイルパス＞※先頭にスラッシュ有り
   */
  public static void copyAvzTScheduleFile(EipTSchedule newSchedule, EipTSchedule srcSchedule, Map<String, String> newFilesMap) {

    SelectQuery<AvzTScheduleFile> dbquery = Database.query(AvzTScheduleFile.class);
    dbquery.andQualifier(ExpressionFactory.matchDbExp(AvzTScheduleFile.TO_EIP_TSCHEDULE_PROPERTY, srcSchedule.getScheduleId()));
    dbquery.orderAscending(AvzTScheduleFile.UPDATE_DATE_PROPERTY);
    List<AvzTScheduleFile> files = dbquery.fetchList();

    Date now = new Date();
    for (AvzTScheduleFile oldScFile : files) {
      AvzTScheduleFile newScFile = Database.create(AvzTScheduleFile.class);
      // String orgFile = ScheduleUtils.getSaveDirPath(Database.getDomainName(),
      // oldScFile.getOwnerId().intValue()) + oldScFile.getFilePath();
      String filename = ScheduleUtils.getRelativePath("0_" + String.valueOf(System.nanoTime()));
      // String newFile = ScheduleUtils.getSaveDirPath(Database.getDomainName(),
      // oldScFile.getOwnerId().intValue()) + filename;

      newScFile.setToEipTSchedule(newSchedule);
      newScFile.setOwnerId(oldScFile.getOwnerId());
      newScFile.setFileName(oldScFile.getFileName());
      newScFile.setFilePath(filename);
      newScFile.setCreateDate(now);
      newScFile.setUpdateDate(now);

      // ファイルを物理コピーする。
      // ScheduleUtils.copyFile(new File(orgFile), new File(newFile));

      // 元ファイルパスと新ファイルパスを保存する。
      newFilesMap.put(oldScFile.getFilePath(), newScFile.getFilePath());
    }
  }

  /**
   * スケジュール添付ファイルを旧レコードから新レコードへコピーします(物理ファイル)。
   * 
   * @param ownerid
   *          スケジュールのオーナーID
   * @param newFilesMap
   *          コピー対象のファイル情報（元ファイルパス、新ファイルパス）
   */
  public static void copyFiles(int ownerid, Map<String, String> newFilesMap) {
    for (Map.Entry<String, String> entry : newFilesMap.entrySet()) {
      String orgFile = ScheduleUtils.getSaveDirPath(Database.getDomainName(), ownerid) + entry.getKey();
      String newFile = ScheduleUtils.getSaveDirPath(Database.getDomainName(), ownerid) + entry.getValue();
      ScheduleUtils.copyFile(new File(orgFile), new File(newFile));
    }
  }

  /**
   * 添付ファイル登録処理（ファイル追加削除は行なわない）
   * 
   * @param rundata
   *          JetSpeedランデータ
   * @param context
   *          JetSpeedコンテキスト
   * @param schedule
   *          スケジュール
   * @param fileuploadList
   *          ファイルリスト
   * @param folderName
   *          フォルダー名
   * @param delFiles
   *          削除対象のファイルパスリスト
   * @param newFilesMap
   *          追加対象のファイル情報リスト
   * @param msgList
   *          エラーメッセージリスト
   * @return 追加／削除発生フラグ（発生した：true、発生しない：false）
   * @throws Exception
   */
  public static boolean insertFileDataDelegate(RunData rundata, Context context, EipTSchedule schedule, List<FileuploadLiteBean> fileuploadList,
      String folderName, List<String> delFilePathList, Map<String, String> newFilesMap, List<String> msgList) throws Exception {

    boolean causeChange = false;

    if (fileuploadList == null || fileuploadList.size() <= 0) {
      fileuploadList = new ArrayList<FileuploadLiteBean>();
    }

    int uid = schedule.getOwnerId();
    String orgId = Database.getDomainName();

    // 既に登録済みの添付ファイルリストを作成する。
    List<Integer> hadfileids = new ArrayList<Integer>();
    for (FileuploadLiteBean file : fileuploadList) {
      if (!file.isNewFile()) {
        hadfileids.add(file.getFileId());
      }
    }

    // 既に登録済みの添付ファイルから、画面上削除されたものを削除対象リストへ格納する。
    SelectQuery<AvzTScheduleFile> dbquery = Database.query(AvzTScheduleFile.class);
    dbquery.andQualifier(ExpressionFactory.matchDbExp(AvzTScheduleFile.TO_EIP_TSCHEDULE_PROPERTY, schedule.getScheduleId()));
    List<AvzTScheduleFile> existsFiles = dbquery.fetchList();
    List<AvzTScheduleFile> delFiles = new ArrayList<AvzTScheduleFile>();
    for (AvzTScheduleFile file : existsFiles) {
      if (!hadfileids.contains(file.getFileId())) {
        delFiles.add(file);
      }
    }

    // ローカルファイルに保存されているファイルを削除する．
    if (delFiles.size() > 0) {
      int delsize = delFiles.size();
      for (int i = 0; i < delsize; i++) {
        delFilePathList.add((delFiles.get(i)).getFilePath());
      }
      // データベースから添付ファイルのデータ削除
      Database.deleteAll(delFiles);

      causeChange = true;
    }

    // ファイル追加処理
    try {
      for (FileuploadLiteBean filebean : fileuploadList) {
        if (!filebean.isNewFile()) {
          continue;
        }

        String filename = "0_" + String.valueOf(System.nanoTime());

        // 新規オブジェクトモデル
        AvzTScheduleFile file = Database.create(AvzTScheduleFile.class);
        // 所有者
        file.setOwnerId(Integer.valueOf(uid));
        // トピックID
        file.setToEipTSchedule(schedule);
        // ファイル名
        file.setFileName(filebean.getFileName());
        // ファイルパス
        file.setFilePath(getRelativePath(filename));
        // 作成日
        file.setCreateDate(Calendar.getInstance().getTime());
        // 更新日
        file.setUpdateDate(Calendar.getInstance().getTime());

        // ファイルの移動
        // ALStorageService.copyTmpFile(uid, folderName, String.valueOf(filebean
        // .getFileId()), FOLDER_FILEDIR_SCHEDULE, CATEGORY_KEY
        // + ALStorageService.separator()
        // + uid, filename);

        newFilesMap.put(String.valueOf(filebean.getFileId()), file.getFilePath());

        causeChange = true;
      }

      // 添付ファイル保存先のフォルダを削除
      // ALStorageService.deleteTmpFolder(uid, folderName);

    } catch (Exception e) {
      logger.error("添付ファイル処理でエラーが発生しました。", e);
      throw e;
    }
    return causeChange;
  }

  /**
   * 添付ファイル登録処理
   * 
   * @param folderName
   *          フォルダー名
   * @param loginuserid
   *          ログインユーザーID
   * @param ownerid
   *          スケジュールのオーナーID
   * @param delFiles
   *          削除対象のファイルパスリスト
   * @param newFilesMap
   *          追加対象のファイル情報リスト(ファイルID、ファイルパス）
   * @param msgList
   *          エラーメッセージリスト
   * @throws Exception
   */
  public static void syncFile(String folderName, int loginuserid, int ownerid, List<String> delFiles, Map<String, String> newFilesMap, List<String> msgList)
      throws Exception {

    try {
      // ローカルファイルに保存されているファイルを削除する．
      for (String delpath : delFiles) {
        String f = ScheduleUtils.getSaveDirPath(Database.getDomainName(), ownerid) + delpath;
        ALStorageService.deleteFile(f);
      }

      for (Map.Entry<String, String> entry : newFilesMap.entrySet()) {
        String fileid = entry.getKey();
        // ファイルパスの頭のスラッシュを除く
        String filename = entry.getValue().substring(1);

        // ファイルの移動
        ALStorageService.copyTmpFile(loginuserid, folderName, fileid, FOLDER_FILEDIR_SCHEDULE, CATEGORY_KEY + ALStorageService.separator() + ownerid, filename);

      }
      // 添付ファイル保存先のフォルダを削除
      ALStorageService.deleteTmpFolder(loginuserid, folderName);

    } catch (Exception e) {
      logger.error("添付ファイル処理でエラーが発生しました。", e);
      throw e;
    }
    return;
  }

  /**
   * 添付ファイルを物理削除する。
   * 
   * @param ownerid
   *          スケジュールのオーナーID
   * @param newFilesMap
   *          削除対象のファイル情報リスト(ファイルID or ファイルパス、ファイルパス） 使用するのはVALUEの方のみ
   */
  public static void rollbackFiles(int ownerid, Map<String, String> newFilesMap) {
    // ローカルファイルに保存されているファイルを削除する．
    try {
      if (newFilesMap != null) {
        for (Map.Entry<String, String> entry : newFilesMap.entrySet()) {
          String filename = entry.getValue();
          String f = ScheduleUtils.getSaveDirPath(Database.getDomainName(), ownerid) + filename;
          ALStorageService.deleteFile(f);
        }
      }
    } catch (Exception e) {
      logger.warn("スケジュールの添付ファイルのロールバックに失敗しました。", e);
    }
  }

  // add end

  // add start 運用フェーズ課題・障害台帳No.135対応
  /**
   * 後方から探索して初めにパターンにマッチした文字列を置換する。
   * 
   * @param string
   *          元文字列
   * @param toReplace
   *          置換対象
   * @param toReplace
   *          置換文字列
   * 
   * @return 処理後文字列
   */
  public static String replaceLast(String string, String toReplace, String replacement) {
    if (string == null) {
      return string;
    }
    int pos = string.lastIndexOf(toReplace);
    if (pos > -1) {
      return string.substring(0, pos) + replacement + string.substring(pos + toReplace.length(), string.length());
    } else {
      return string;
    }
  }

  // add end

  // add start No.4 スケジュール印刷（週単位）
  /**
   * アクセスしてきたユーザが利用するブラウザがIE9であるかを判定する．
   * 
   * @param rundata
   * @return IE9 の場合は，true．
   */
  public static boolean isIE9(RunData rundata) {

    // User-Agent の取得
    String userAgent = rundata.getRequest().getHeader("User-Agent").toLowerCase();
    if (userAgent == null || userAgent.equals("")) {
      return false;
    }

    if (userAgent.indexOf("msie 9.") > 0) {
      return true;
    }
    return false;
  }
  // add end
}
