/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * http://aipo.com/
 *
 * Copyright(C) 2012 avanza Co.,Ltd. All rights reserved.
 * http://www.avnz.co.jp/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.schedule;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

import com.aimluck.commons.field.ALDateTimeField;
import com.aimluck.eip.cayenne.om.portlet.EipTSchedule;
import com.aimluck.eip.cayenne.om.portlet.EipTScheduleMap;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.schedule.util.ScheduleUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * 1日スケジュールの検索結果を管理する
 * 
 */
public class AjaxScheduleOneDayBaseContainer {

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

  /** 前の日 */
  private ALDateTimeField prevDate;

  /** 次の日 */
  private ALDateTimeField nextDate;

  /** 前の週 */
  private ALDateTimeField prevWeek;

  /** 次の週 */
  private ALDateTimeField nextWeek;

  /** 今日 */
  private ALDateTimeField today;

  /** 前の月 */
  private ALDateTimeField prevMonth;

  /** 次の月 */
  private ALDateTimeField nextMonth;

  /** 表示開始日時 */
  private ALDateTimeField viewStart;

  /** 表示終了日時 */
  private ALDateTimeField viewEnd;

  /** 閲覧メンバー別日単位予定コンテナ */
  private AjaxScheduleUserOneDayContainer userCon;

  /** 閲覧メンバー別期間予定コンテナマップの一覧（１レコードは上詰めした１行） */
  private List<AjaxSpanScheduleUserOneDayContainer> userTermDayConMapList;

  /** 閲覧権限表 */
  private Map<String, String> scheduleAclMap;

  /** 全閲覧メンバー一覧 */
  private List<Integer> memberList;

  /** 閲覧可メンバー一覧 */
  private List<Integer> approvalMemberList;

  /** 閲覧不可メンバー一覧 */
  private List<Integer> disapprovalMemberList;

  /** ログインユーザーID */
  private long loginUserId;

  /** ログインユーザー名 */
  private String loginUserName;

  /**
   * 予定を検索し、ユーザー別１日別の各種コンテナに格納します
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   */
  public void doSearchScheduleToUserOneDayContainer(RunData rundata, Context context) {

    try {

      init(rundata, context);

      ResultList<EipTScheduleMap> resultList = selectList(rundata, context);
      if (resultList != null) {
        for (EipTScheduleMap row : resultList) {
          toAjaxScheduleResultDataIntoContainer(row);
        }
      }
    } catch (ALPageNotFoundException e) {
      logger.error("ページエラー", e);
    } catch (ALDBErrorException e) {
      logger.error("DBエラー", e);
    }
  }

  /**
   * 予定検索初期処理
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  public void init(RunData rundata, Context context) throws ALPageNotFoundException, ALDBErrorException {

    // 各種パラメータの取得
    // ユーザーID
    loginUserId = ALEipUtils.getUserId(rundata);
    // ログインユーザー名の取得
    loginUserName = ALEipUtils.getUserFullName((int) loginUserId);
    // 前の日
    prevDate = new ALDateTimeField("yyyy-MM-dd");
    // 次の日
    nextDate = new ALDateTimeField("yyyy-MM-dd");
    // 前の週
    prevWeek = new ALDateTimeField("yyyy-MM-dd");
    // 次の週
    nextWeek = new ALDateTimeField("yyyy-MM-dd");
    // 前の月
    prevMonth = new ALDateTimeField("yyyy-MM-dd");
    // 次の月
    nextMonth = new ALDateTimeField("yyyy-MM-dd");
    // 表示開始日時
    viewStart = new ALDateTimeField("yyyy-MM-dd");
    viewStart.setNotNull(true);
    // 表示終了日時
    viewEnd = new ALDateTimeField("yyyy-MM-dd");
    // 今日
    today = new ALDateTimeField("yyyy-MM-dd");
    Calendar workToday = Calendar.getInstance();
    workToday.set(Calendar.HOUR_OF_DAY, 0);
    workToday.set(Calendar.MINUTE, 0);
    workToday.set(Calendar.SECOND, 0);
    workToday.set(Calendar.MILLISECOND, 0);
    today.setValue(workToday.getTime());

    // パラーメータ名：表示開始日
    final String PARAM_VIEW_START = "view_start";

    // ///////////////////////////////////////////////////////
    // 表示対象日の取得
    // 優先順位の高いほうを優先する。
    // 1)リクエストパラメータ 2)セッション 3)システム日付
    // ///////////////////////////////////////////////////////
    // リクエストパラメータから対象日を取得
    String pViewStart = rundata.getParameters().getString(PARAM_VIEW_START);
    if (pViewStart != null && !"".equals(pViewStart)) {
      // 有効である場合は、「リクエストパラメータ」を表示対象日とする
      viewStart.setValue(pViewStart);
      // 日付として正しくない場合はエラー
      if (!viewStart.validate(new ArrayList<String>())) {
        throw new ALPageNotFoundException();
      }
      // 遷移元が月スケジュールでない場合のみ、セッションへ格納
      if (!"FromMonthly".equals(ALEipUtils.getTemp(rundata, context, "FROM_PORTLET"))) {
        ALEipUtils.setTemp(rundata, context, PARAM_VIEW_START, pViewStart);
      }
    } else {
      // セッションから対象日を取得
      String sViewStart = ALEipUtils.getTemp(rundata, context, PARAM_VIEW_START);
      if (sViewStart != null && !"".equals(sViewStart)) {
        // 有効である場合は、「セッション」を表示対象日とする
        viewStart.setValue(sViewStart);
        // 日付として正しくない場合はエラー
        if (!viewStart.validate(new ArrayList<String>())) {
          ALEipUtils.removeTemp(rundata, context, PARAM_VIEW_START);
          throw new ALPageNotFoundException();
        }
      } else {
        // リクエストパラメータ/セッション共に無効の場合、「システム日付」を表示対象日とする
        viewStart.setValue(workToday.getTime());
      }
    }

    // 翌日
    Calendar cal = Calendar.getInstance();
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.DATE, 1);
    nextDate.setValue(viewStart.getValue());

    // 翌週
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.DATE, 7);
    nextWeek.setValue(cal.getTime());

    // 前日
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.DATE, -1);
    prevDate.setValue(cal.getTime());

    // 前週
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.DATE, -7);
    prevWeek.setValue(cal.getTime());

    // 表示終了日時
    cal.setTime(viewStart.getValue());
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    viewEnd.setValue(cal.getTime());

    // 前月
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.MONTH, -1);
    prevMonth.setValue(cal.getTime());

    // 前月
    cal.setTime(viewStart.getValue());
    cal.add(Calendar.MONTH, 1);
    nextMonth.setValue(cal.getTime());

    // エンティティIDを初期化する
    if (ALEipUtils.isMatch(rundata, context)) {
      // 自ポートレット遷移の場合、パラメータ値でセッション値を更新する
      if (rundata.getParameters().containsKey(ALEipConstants.ENTITY_ID)) {
        ALEipUtils.setTemp(rundata, context, ALEipConstants.ENTITY_ID, rundata.getParameters().getString(ALEipConstants.ENTITY_ID));
      }
    }

    // 閲覧メンバー情報の初期化
    initMemberList(rundata);

    // 予定コンテナの初期化
    // 日単位
    userCon = new AjaxScheduleUserOneDayContainer(viewStart, memberList);
    // 期間の一覧
    userTermDayConMapList = new ArrayList<AjaxSpanScheduleUserOneDayContainer>(0);

  }

  /**
   * 閲覧メンバー情報初期化
   * 
   * @param rundata
   *            実行データ
   */
  private void initMemberList(RunData rundata) {

    // 全閲覧メンバー、閲覧可メンバー一覧、閲覧不可メンバー一覧、閲覧権限表の初期化
    memberList = new ArrayList<Integer>(0);
    disapprovalMemberList = new ArrayList<Integer>(0);
    approvalMemberList = new ArrayList<Integer>(0);
    scheduleAclMap = new HashMap<String, String>(0);

    // リクエストパラメータから閲覧メンバーを取得
    String[] paramMemberList = new String[0];
    String mId = rundata.getParameters().getString("m_id");
    if (mId != null) {
      paramMemberList = mId.split(",");
    }

    // 閲覧メンバーのユーザーIDを数値型に変換
    for (String pm : paramMemberList) {
      memberList.add(new Integer(pm));
    }
    // 閲覧メンバーが存在しない場合は、ログインユーザーのみ対象とする
    if (memberList.size() == 0) {
      memberList.add((int) loginUserId);
      return;
    }

    // ///////////////////////////////////////////////////////////////////
    // ログインユーザーから閲覧メンバーを参照する際の閲覧権限表を作成する
    // ///////////////////////////////////////////////////////////////////
    // 閲覧権限を取得し閲覧可否を決定する
    for (Integer memberUserId : memberList) {
      // 閲覧メンバー表示可否判定処理
      String scheduleAcl = ScheduleUtils.getScheduleAcl(Long.toString(loginUserId), memberUserId.toString());
      // 閲覧権限表作成
      scheduleAclMap.put(memberUserId.toString(), scheduleAcl);
      if (ScheduleConst.SCHEDULE_ACL_REFUSAL.equals(scheduleAcl)) {
        // 閲覧権限＝不可の場合<閲覧メンバー不可リストに登録>
        disapprovalMemberList.add(memberUserId);
      } else {
        // 閲覧権限≠不可の場合<閲覧メンバー可リストに登録>
        approvalMemberList.add(memberUserId);
      }
    }
  }

  /**
   * DBに対して予定検索を実行する
   * 
   * @param rundata
   *            実行データ
   * @param context
   *            Velocityコンテキスト
   * @return DB検索結果
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  protected ResultList<EipTScheduleMap> selectList(RunData rundata, Context context) throws ALPageNotFoundException, ALDBErrorException {
    try {

      List<EipTScheduleMap> list = new ArrayList<EipTScheduleMap>(0);

      // 閲覧可メンバーがいない場合は処理終了
      if (approvalMemberList.size() < 1) {
        return new ResultList<EipTScheduleMap>(list);
      }

      // 検索条件作成
      SelectQuery<EipTScheduleMap> query = Database.query(EipTScheduleMap.class);

      // 条件：スケジュールマップ.種別＝ユーザー
      Expression exp20 = ExpressionFactory.matchExp(EipTScheduleMap.TYPE_PROPERTY, ScheduleUtils.SCHEDULEMAP_TYPE_USER);

      query.setQualifier(exp20);

      // 条件：スケジュールマップ.ユーザID が <閲覧可メンバー一覧>の<閲覧可メンバー.ユーザーID> の何れかと一致する
      Expression exp21 = ExpressionFactory.inExp(EipTScheduleMap.USER_ID_PROPERTY, approvalMemberList);

      query.andQualifier(exp21);

      // 条件：終了時間≧基準日
      Expression exp11 =
        ExpressionFactory.greaterOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY, viewStart.getValue());
      // 条件：開始時間≦基準日
      Expression exp12 = ExpressionFactory.lessOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY, viewEnd.getValue());
      query.andQualifier(exp11.andExp(exp12));
      // 開始時間の（昇順）
      query.orderAscending(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY);
      // 終了日時（昇順）
      query.orderAscending(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY);
      // スケジュールID（昇順）
      query.orderAscending(EipTScheduleMap.SCHEDULE_ID_PROPERTY);

      // 重複除去
      query.distinct(true);

      // 検索実行
      list.addAll(query.fetchList());

      return new ResultList<EipTScheduleMap>(ScheduleUtils.sortByDummySchedule(list));

    } catch (Exception e) {
      logger.error("予定一覧画面の表示に失敗しました。ログインユーザー:" + loginUserName, e);
      throw new ALDBErrorException();

    }
  }

  /**
   * Ajaxスケジュール画面用結果データに変換し、コンテナに格納する
   * 
   * @param record
   *            DB検索結果
   * @return Ajaxスケジュール画面用結果データ
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  protected void toAjaxScheduleResultDataIntoContainer(EipTScheduleMap record) throws ALPageNotFoundException, ALDBErrorException {
    AjaxScheduleResultData rd = new AjaxScheduleResultData();
    rd.initField();
    try {
      EipTSchedule schedule = record.getEipTSchedule();
      // スケジュールが棄却されている場合はコンテナに格納しない
      if ("R".equals(record.getStatus())) {
        return;
      }

      // is_memberのチェック
      SelectQuery<EipTScheduleMap> mapquery = Database.query(EipTScheduleMap.class);
      Expression mapexp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, schedule.getScheduleId());
      mapquery.setQualifier(mapexp1);

      try {
        List<String> recordMemberList = new ArrayList<String>();
        List<EipTScheduleMap> tmpList = mapquery.fetchList();
        int tmpSize = tmpList.size();
        EipTScheduleMap tmpMap;
        for (int i = 0; i < tmpSize; i++) {
          tmpMap = tmpList.get(i);
          int memberId = tmpMap.getUserId().intValue();
          if (!("R".equals(tmpMap.getStatus()))) {
            recordMemberList.add(Integer.toString(memberId));
          }
        }
        if (recordMemberList != null && recordMemberList.size() > 0) {
          rd.setMemberList(recordMemberList);
        }
      } catch (Exception e) {
        logger.error("予定一覧画面の表示に失敗しました。ログインユーザー:" + loginUserName, e);
        return;
      }

      Expression mapexp2 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, new Long(loginUserId));
      mapquery.andQualifier(mapexp2);

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

      if (!"D".equals(record.getStatus())
        && "P".equals(schedule.getPublicFlag())
        && !is_member
        && (isPublicOfScheduleAcl(record.getUserId().toString()) || isSecretaryImpossible(record.getUserId().toString(), schedule.getCreateUserId().toString()))) {
        // ダミー予定でない
        // かつ
        // 公開フラグ=[完全に非公開]
        // かつ
        // ログインユーザーが参加ユーザーでない
        // かつ
        // ( ログインユーザーが対象ユーザーに対し[公開]
        // または
        // (ログインユーザーが対象ユーザーに対し[秘書]
        // かつ対象ユーザー = 作成ユーザーID
        // かつ ログインユーザーが参加ユーザーでない)
        // )
        // に該当する場合

        // 検索結果予定をコンテナにはセットしない
        return;
      }

      // ID
      rd.setScheduleId(schedule.getScheduleId().intValue());
      // 親スケジュール ID
      rd.setParentId(schedule.getParentId().intValue());
      // 対象ユーザーID（スケジュールマップのユーザーID）
      rd.setUserId(record.getUserId());
      // 名前
      rd.setName(schedule.getName());
      // 場所
      rd.setPlace(schedule.getPlace());
      // 開始日時
      rd.setStartDate(schedule.getStartDate());
      // 終了日時
      rd.setEndDate(schedule.getEndDate());
      // 仮スケジュールかどうか
      rd.setTmpreserve("T".equals(record.getStatus()));
      // 公開するかどうか
      rd.setPublic("O".equals(schedule.getPublicFlag()));
      // 非表示にするかどうか
      rd.setHidden("P".equals(schedule.getPublicFlag()));
      // ダミーか
      rd.setDummy("D".equals(record.getStatus()));
      // ログインユーザかどうか
      // ログインユーザー=対象者の場合 および
      // ログインユーザーが対象者に対して[秘書]の場合、ログインユーザーの予定扱いにする
      rd.setLoginuser(record.getUserId().intValue() == (int) loginUserId || isSecretaryOfScheduleAcl(record.getUserId().toString()));
      // オーナーかどうか
      // ログインユーザー=主催者の場合 および
      // ログインユーザーが対象者に対して[秘書] かつ 対象者が主催者の場合、オーナー扱いにする
      rd.setOwner(schedule.getOwnerId().intValue() == (int) loginUserId
        || (isSecretaryOfScheduleAcl(record.getUserId().toString()) && schedule.getOwnerId().intValue() == record.getUserId().intValue()
        // ただし、[秘書]の場合で主催者が作成した非公開スケジュールは対象外とする
        && !(!rd.isPublic() && isSecretaryImpossible(record.getUserId().toString(), schedule.getCreateUserId().toString()) && !is_member)));

      // add start 結合試験障害16-01対応
      if (schedule.getOwnerId().intValue() == record.getUserId().intValue()
        && (isMyselfOfScheduleAcl(record.getUserId().toString()) || isSecretaryOfScheduleAcl(record.getUserId().toString()))) {
        rd.setOrganizer(true);
      } else {
        rd.setOrganizer(false);
      }
      // add end

      // 施設かどうか
      rd.setType(record.getType());
      // 共有メンバーかどうか
      rd.setMember(is_member);
      // 繰り返しパターン
      rd.setPattern(schedule.getRepeatPattern());
      // 共有メンバーによる編集／削除フラグ
      rd.setEditFlag("T".equals(schedule.getEditFlag()));

      // 状態
      rd.setStatus(record.getStatus());
      // 必須フラグ
      rd.setRequired(record.getRequired());
      // 重要フラグ
      rd.setPriority(record.getPriority());
      // 作成ユーザーID
      rd.setCreateUserId(String.valueOf(schedule.getCreateUserId()));

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

      // add start 要件No.18 会議案内ファイル添付
      rd.setFiles(ScheduleUtils.hasAttachmentFiles(schedule));
      // add end

      // 個別色
      rd.setIndividualColor(record.getIndividualColor());

      // スケジュールのパターン別で格納先コンテナを変更
      if (rd.getPattern().equals("S")) {
        // 期間スケジュールの場合
        // rowspanを設定
        // 必ず1日分である
        rd.setRowspan(1);
        addSpanScheduleToUserOneDayContainer(userTermDayConMapList, viewStart.getValue(), record.getUserId(), rd);
      } else {
        userCon.addResultData(record.getUserId(), rd);
      }

    } catch (Exception e) {
      logger.error("予定一覧画面の表示に失敗しました。ログインユーザー:" + loginUserName, e);
    }
    return;
  }

  /**
   * 期間予定をコンテナへ追加
   * 
   * @param userConList
   *            ユーザー別1日スケジュール用期間予定コンテナ（行）一覧
   * @param targetDate
   *            表示対象日
   * @param userId
   *            対象ユーザーID
   * @param rd
   *            表示対象の結果データ
   */
  private void addSpanScheduleToUserOneDayContainer(List<AjaxSpanScheduleUserOneDayContainer> userConList, Date targetDate, Integer userId,
      AjaxScheduleResultData rd) {
    try {
      boolean success = false;
      for (AjaxSpanScheduleUserOneDayContainer userConRow : userConList) {
        success = userConRow.canAddSpan(userId);
        if (success) {
          // 期間行がある かつ その行に対象ユーザー予定がない場合
          // 対象期間行
          userConRow.addSpanResultData(userId, rd);
          break;
        }
      }

      if (!success) {
        // 期間行が無い または その行に対象ユーザー予定が既にある場合
        // 新規期間行を追加する
        ALDateTimeField df = new ALDateTimeField();
        df.setValue(targetDate);
        AjaxSpanScheduleUserOneDayContainer userConRow = new AjaxSpanScheduleUserOneDayContainer(df, memberList);
        userConRow.addSpanResultData(userId, rd);
        userConList.add(userConRow);
      }

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

  /**
   * 表示開始日時を取得します。
   * 
   * @return
   */
  public ALDateTimeField getViewStart() {
    return viewStart;
  }

  /**
   * 表示終了日時を取得します。
   * 
   * @return
   */
  public ALDateTimeField getViewEnd() {
    return viewEnd;
  }

  /**
   * 前の日を取得します。
   * 
   * @return
   */
  public ALDateTimeField getPrevDate() {
    return prevDate;
  }

  /**
   * 前の週を取得します。
   * 
   * @return
   */
  public ALDateTimeField getPrevWeek() {
    return prevWeek;
  }

  /**
   * 次の日を取得します。
   * 
   * @return
   */
  public ALDateTimeField getNextDate() {
    return nextDate;
  }

  /**
   * 次の週を取得します。
   * 
   * @return
   */
  public ALDateTimeField getNextWeek() {
    return nextWeek;
  }

  /**
   * 今日を取得します。
   * 
   * @return
   */
  public ALDateTimeField getToday() {
    return today;
  }

  /**
   * 先月を取得する．
   * 
   * @return
   */
  public ALDateTimeField getPrevMonth() {
    return prevMonth;
  }

  /**
   * 来月を取得する．
   * 
   * @return
   */
  public ALDateTimeField getNextMonth() {
    return nextMonth;
  }

  /**
   * ユーザー別日単位予定コンテナを取得します。
   * 
   * @return
   */
  public AjaxScheduleUserOneDayContainer getContainer() {
    return userCon;
  }

  /**
   * ユーザー別期間予定コンテナの一覧を取得します。
   * 
   * @return 「閲覧メンバー分の期間予定コンテナ」の一覧
   */
  public List<AjaxSpanScheduleUserOneDayContainer> getUserSpanContainerList() {
    return userTermDayConMapList;
  }

  /**
   * 閲覧メンバーのユーザーID一覧を取得します。
   * 
   * @return 閲覧メンバーのユーザーID一覧
   */
  public List<Integer> getViewMemberUserIdList() {
    return memberList;
  }

  /**
   * ログインユーザーが対象のユーザーに対し、閲覧権限が[秘書]であるかの判定を行います。
   * 
   * @param uid
   *            対象ユーザーのユーザーID
   * @return 秘書の場合：true、そうでない場合：false
   */
  public boolean isSecretaryOfScheduleAcl(String uid) {
    String scheduleAcl = scheduleAclMap.get(uid);
    if (ScheduleConst.SCHEDULE_ACL_SECRETARY.equals(scheduleAcl)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * ログインユーザーが対象のユーザーに対し、閲覧権限が[公開]であるかの判定を行います。
   * 
   * @param uid
   *            対象ユーザーのユーザーID
   * @return 公開の場合：true、そうでない場合：false
   */
  public boolean isPublicOfScheduleAcl(String uid) {
    String scheduleAcl = scheduleAclMap.get(uid);
    if (ScheduleConst.SCHEDULE_ACL_PUBLIC.equals(scheduleAcl)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * ログインユーザーが主催者に対し[秘書]であるが、操作対象外のスケジュールか判定します。<br/> 次の条件をすべて満たす場合が該当します。<br/>
   * <ul>
   * <li>ログインユーザーが対象者に対し[秘書]である。</li>
   * <li>対象者がスケジュールを作成している。</li>
   * </ul>
   * 
   * @param userId
   *            対象ユーザーID
   * @param createUserId
   *            作成者ユーザーID
   * @param isMember
   *            ログインユーザーが参加メンバーの場合true
   * @return 該当する場合：true、該当しない場合：false
   */
  public boolean isSecretaryImpossible(String userId, String createUserId) {
    if (isSecretaryOfScheduleAcl(userId) && userId.equals(createUserId)) {
      return true;
    }
    return false;
  }

  /**
   * 照会エラーメッセージ作成
   * 
   * @return 照会エラーメッセージ
   * @throws ALDBErrorException
   *             ユーザー情報検索時にDBエラー
   */
  public String getReferenceErrMessage() throws ALDBErrorException {
    String errMsg = "";
    int count = 0;
    // <閲覧不可メンバー一覧>が1件以上存在する場合、照会エラーメッセージ表示領域へ設定する。
    for (Integer disapprovalMember : disapprovalMemberList) {
      ALEipUser user = ALEipUtils.getALEipUser(disapprovalMember.intValue());
      errMsg += ("[" + user.getAliasName() + "さん]");
      count++;
    }
    if (0 < count) {
      errMsg += "の予定を見る権限がありません。";
    }
    return errMsg;
  }

  // add start 要件No.16 スケジュール画面（月単位／週単位／日単位）右クリックメニュー
  /**
   * ログインユーザーが対象のユーザーに対し、閲覧権限が[本人]であるかの判定を行います。
   * 
   * @param uid
   *            対象ユーザーのユーザーID
   * @return 本人の場合：true、そうでない場合：false
   */
  public boolean isMyselfOfScheduleAcl(String uid) {
    String scheduleAcl = scheduleAclMap.get(uid);
    if (ScheduleConst.SCHEDULE_ACL_MYSELF.equals(scheduleAcl)) {
      return true;
    } else {
      return false;
    }
  }
  // add end

}
