/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * http://aipostyle.com/
 * 
 * Copyright(C) 2011 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.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Map.Entry;
import java.util.jar.Attributes;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.Ordering;
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.account.EipMUserPosition;
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.ALDBErrorException;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.schedule.data.ScheduleMemberUser;
import com.aimluck.eip.schedule.util.ScheduleUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * 日時調整画面の予定データを管理するクラスです。
 * 
 */
public class ScheduleReferOnedayGroupSelectData extends ScheduleOnedaySelectData {

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

  /** <code>termmap</code> 期間スケジュールマップ */
  private Map<Integer, List<ScheduleReferOnedayResultData>> termmap;

  /** <code>map</code> 一時通常スケジュールMap */
  private Map<Integer, ScheduleReferOnedayWorkingContainer> tmpMap;

  /** <code>map</code> 表示用通常スケジュールMap */
  private Map<Integer, ScheduleReferOnedayContainer> normalMap;

  /** <code>members</code> 閲覧メンバー（必須） */
  private List<ScheduleMemberUser> members;

  /** 閲覧メンバーのユーザーIDリスト（必須） */
  private List<Integer> userIdList;

  /** <code>map</code> 閲覧権限表 */
  private Map<Integer, String> aclMap;

  /** <code>userid</code> ログインユーザーID */
  private int userid;

  /** <code>rows</code> rows */
  private int rows[];

  /** <code>max</code> max */
  private int max;

  /** <code>is_hasspan</code> 期間スケジュールがあるかどうか */
  private boolean is_hasspan;

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

    termmap = new LinkedHashMap<Integer, List<ScheduleReferOnedayResultData>>();
    tmpMap = new LinkedHashMap<Integer, ScheduleReferOnedayWorkingContainer>();
    normalMap = new LinkedHashMap<Integer, ScheduleReferOnedayContainer>();
    aclMap = new LinkedHashMap<Integer, String>();

    userid = ALEipUtils.getUserId(rundata);
    rows = new int[(endHour - startHour) * 4 + 1];
    int size = rows.length;
    for (int i = 0; i < size; i++) {
      rows[i] = 1;
    }

  }

  /**
   * 一覧データを取得します。 <BR>
   * 
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return 結果リスト
   * @see com.aimluck.eip.common.ALAbstractListData#selectData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context)
   * @throws ALPageNotFoundException,
   *             ALDBErrorException
   */
  @Override
  protected ResultList<EipTScheduleMap> selectList(RunData rundata, Context context) throws ALPageNotFoundException, ALDBErrorException {
    try {

      // リクエストパラメータからユーザー情報を種痘
      loadUserIds(rundata, context);

      // 閲覧権限表を作成する。
      for (ScheduleMemberUser e : members) {
        String acl = ScheduleUtils.getScheduleAcl(String.valueOf(userid), e.getUserId().toString());
        aclMap.put((int) e.getUserId().getValue(), acl);
      }

      // add start 2012.5.21
      if (members == null || members.size() < 1) {
        ResultList<EipTScheduleMap> list = new ResultList<EipTScheduleMap>();
        return list;
      }
      // add end 2012.5.21

      List<EipTScheduleMap> resultBaseList = getSelectQuery(rundata, context).fetchList();
      List<EipTScheduleMap> resultList = ScheduleUtils.sortByDummySchedule(resultBaseList);

      List<EipTScheduleMap> list = new ArrayList<EipTScheduleMap>();
      List<EipTScheduleMap> delList = new ArrayList<EipTScheduleMap>();
      int delSize = 0;
      int resultSize = resultList.size();
      int size = 0;
      boolean canAdd = true;
      for (int i = 0; i < resultSize; i++) {
        EipTScheduleMap record = resultList.get(i);
        EipTSchedule schedule = (record.getEipTSchedule());
        delList.clear();
        canAdd = true;
        size = list.size();
        for (int j = 0; j < size; j++) {
          EipTScheduleMap record2 = list.get(j);
          EipTSchedule schedule2 = (record2.getEipTSchedule());
          if (!schedule.getRepeatPattern().equals("N")
            && "D".equals(record2.getStatus())
            && schedule.getScheduleId().intValue() == schedule2.getParentId().intValue()) {
            canAdd = false;
            break;
          }
          if (!schedule2.getRepeatPattern().equals("N")
            && "D".equals(record.getStatus())
            && schedule2.getScheduleId().intValue() == schedule.getParentId().intValue()) {
            // [繰り返しスケジュール] 親の ID を検索
            if (!delList.contains(record2)) {
              delList.add(record2);
            }
            canAdd = true;
          }
        }
        delSize = delList.size();
        for (int k = 0; k < delSize; k++) {
          list.remove(delList.get(k));
        }

        if (canAdd) {
          list.add(record);
        }
      }

      // ダミーを削除する．
      delList.clear();
      size = list.size();
      for (int i = 0; i < size; i++) {
        EipTScheduleMap record = list.get(i);
        if ("D".equals(record.getStatus())) {
          delList.add(record);
        }
      }
      delSize = delList.size();
      for (int i = 0; i < delSize; i++) {
        list.remove(delList.get(i));
      }

      // // ソート
      // Collections.sort(list, new Comparator<EipTScheduleMap>() {
      //
      // public int compare(EipTScheduleMap a, EipTScheduleMap b) {
      // Calendar cal = Calendar.getInstance();
      // Calendar cal2 = Calendar.getInstance();
      // EipTSchedule p1 = null;
      // EipTSchedule p2 = null;
      // try {
      // p1 = (a).getEipTSchedule();
      // p2 = (b).getEipTSchedule();
      //
      // } catch (Exception e) {
      // logger.error("Exception", e);
      // }
      // cal.setTime(p1.getStartDate());
      // cal.set(0, 0, 0);
      // cal2.setTime(p2.getStartDate());
      // cal2.set(0, 0, 0);
      // if ((cal.getTime()).compareTo(cal2.getTime()) != 0) {
      // return (cal.getTime()).compareTo(cal2.getTime());
      // } else {
      // cal.setTime(p1.getEndDate());
      // cal.set(0, 0, 0);
      // cal2.setTime(p2.getEndDate());
      // cal2.set(0, 0, 0);
      //
      // return (cal.getTime()).compareTo(cal2.getTime());
      // }
      // }
      // });
      //
      // if (viewToDo == 1) {
      // // ToDo の読み込み
      // loadToDo(rundata, context);
      // }

      return new ResultList<EipTScheduleMap>(list);
    } catch (Exception e) {
      logger.error("スケジュール日時調整の表示に失敗しました[" + ALEipUtils.getBaseUser(userid).getUserName() + "]", e);
      return null;
    }
  }

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

    // 終了日時
    Expression exp11 =
      ExpressionFactory.greaterOrEqualExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY, getViewDate().getValue());

    // 日付を1日ずつずらす
    Calendar cal = Calendar.getInstance();
    cal.setTime(getViewDate().getValue());
    cal.add(Calendar.DATE, 1);
    ALDateTimeField field = new ALDateTimeField();
    field.setValue(cal.getTime());
    // 開始日時
    Expression exp12 = ExpressionFactory.lessExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY, field.getValue());
    // 通常スケジュール
    Expression exp13 = ExpressionFactory.noMatchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "N");
    // 期間スケジュール
    Expression exp14 = ExpressionFactory.noMatchExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY, "S");

    query.setQualifier((exp11.andExp(exp12)).orExp(exp13.andExp(exp14)));

    // 開始日時でソート
    List<Ordering> orders = new ArrayList<Ordering>();
    orders.add(new Ordering(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY, true));
    orders.add(new Ordering(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY, true));
    query.getQuery().addOrderings(orders);

    return buildSelectQueryForFilter(query, rundata, context);
  }

  /**
   * 閲覧対象のユーザーIDリストを取得 <BR>
   * 
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return 閲覧対象のユーザーIDリスト
   * @throws Exception
   */
  private List<Integer> loadUserIds(RunData rundata, Context context) throws Exception {

    List<Integer> list = new ArrayList<Integer>();

    // add start 2012.5.21
    if (rundata.getParameters().containsKey("init_load_user_id")) {
      ALEipUtils.removeTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_MEMBER");
      ALEipUtils.removeTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_SELFISH_MEMBER");
    }
    // add end 2012.5.21

    // 必須指定ユーザー
    String memberNames[] = rundata.getParameters().getStrings("member_to");
    if (memberNames != null && memberNames.length > 0) {

      String member__to_str = implode(",", memberNames);

      // セッションに保存
      ALEipUtils.setTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_MEMBER", member__to_str);

    } else {
      // 前日、次日ボタンなどをクリックされた場合、セッションの値を取得
      String member__to_str = ALEipUtils.getTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_MEMBER");
      if (member__to_str != null && member__to_str.length() != 0) {
        memberNames = explode(",", member__to_str);
      }
    }

    // 任意指定ユーザー
    String selfishMemberNames[] = rundata.getParameters().getStrings("selfish_member_to");
    if (selfishMemberNames != null && selfishMemberNames.length > 0) {

      String member__to_str = implode(",", selfishMemberNames);

      // セッションに保存
      ALEipUtils.setTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_SELFISH_MEMBER", member__to_str);

    } else {
      // 前日、次日ボタンなどをクリックされた場合、セッションの値を取得
      String member__to_str = ALEipUtils.getTemp(rundata, context, ScheduleReferOnedayGroupSelectData.class.getName() + "_SELFISH_MEMBER");
      if (member__to_str != null && member__to_str.length() != 0) {
        selfishMemberNames = explode(",", member__to_str);
      }

    }

    // ログイン名からユーザー情報を取得 表示名->表示順位でソート
    members = getUsersFromSelectQuery(memberNames, selfishMemberNames);

    // ユーザーIDリストを取得
    userIdList = new ArrayList<Integer>();
    if (members != null) {
      for (ALEipUser al : members) {
        userIdList.add((int) al.getUserId().getValue());
      }
    }
    return list;
  }

  /**
   * 必須/任意ユーザー情報を取得します。
   * 
   * @param requiredArray
   *            必須指定ユーザーのログイン名の配列
   * @param selfishArray
   *            任意指定ユーザーのログイン名の配列
   * @throws Exception
   */
  private List<ScheduleMemberUser> getUsersFromSelectQuery(String[] requiredArray, String[] selfishArray) throws Exception {
    List<ScheduleMemberUser> list = new ArrayList<ScheduleMemberUser>();
    try {

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

      List<String> requiredList = new ArrayList<String>(0);
      if (requiredArray != null) {
        requiredList = java.util.Arrays.asList(requiredArray);
        login_names.addAll(requiredList);
      }

      List<String> selfishList = new ArrayList<String>(0);
      if (selfishArray != null) {
        selfishList = java.util.Arrays.asList(selfishArray);
        login_names.addAll(selfishList);
      }

      if (requiredList.size() == 0 && selfishList.size() == 0) {
        return new ArrayList<ScheduleMemberUser>(0);
      }

      SelectQuery<TurbineUser> query = Database.query(TurbineUser.class);
      Expression exp = ExpressionFactory.inExp(TurbineUser.LOGIN_NAME_PROPERTY, login_names);
      query.setQualifier(exp);

      // ユーザー情報のソートを表示名>表示順位に変更
      query.orderAscending(TurbineUser.DISPLAY_NAME_PROPERTY);
      query.orderAscending(TurbineUser.EIP_MUSER_POSITION_PROPERTY + "." + EipMUserPosition.POSITION_PROPERTY);
      List<TurbineUser> ulist = query.fetchList();
      for (TurbineUser record : ulist) {
        ScheduleMemberUser user = new ScheduleMemberUser();
        user.initField();
        user.setUserId(record.getUserId().intValue());
        user.setName(record.getLoginName());
        user.setAliasName(record.getFirstName(), record.getLastName());
        if (requiredList.contains(record.getLoginName())) {
          user.setRequired(ScheduleConst.SCHEDULEMAP_REQUIRED_T);
        } else {
          user.setRequired(ScheduleConst.SCHEDULEMAP_REQUIRED_F);
        }

        list.add(user);
      }
    } catch (Exception e) {
      throw e;
    }
    return list;
  }

  /**
   * スケジュールデータ取得用のSQLにユーザーID条件を付与します。 <BR>
   * 
   * @param query
   *            SQLクエリ
   * @param rundata
   *            JetSpeedランデータ
   * @param context
   *            JetSpeedコンテキスト
   * @return 処理済みSQLクエリ
   * @throws Exception
   * @throws Exception
   */
  @Override
  protected SelectQuery<EipTScheduleMap> buildSelectQueryForFilter(SelectQuery<EipTScheduleMap> query, RunData rundata, Context context) {

    List<Integer> ulist = userIdList;
    if (ulist != null) {
      int size = ulist.size();
      for (int i = 0; i < size; i++) {
        Integer id = ulist.get(i);
        ScheduleReferOnedayContainer con = new ScheduleReferOnedayContainer();
        con.initField();
        con.initHour(startHour, endHour);
        this.termmap.put(id, new ArrayList<ScheduleReferOnedayResultData>());
        this.tmpMap.put(id, new ScheduleReferOnedayWorkingContainer());
        this.normalMap.put(id, con);
      }
    }

    Expression exp11 = ExpressionFactory.matchExp(EipTScheduleMap.TYPE_PROPERTY, ScheduleUtils.SCHEDULEMAP_TYPE_USER);
    Expression exp12 = ExpressionFactory.inExp(EipTScheduleMap.USER_ID_PROPERTY, ulist);

    query.andQualifier((exp11.andExp(exp12)));

    ScheduleMemberUser eipUser = null;
    int memberSize = members.size();
    for (int i = 0; i < memberSize; i++) {
      eipUser = members.get(i);
      if (eipUser.getUserId().getValue() == userid) {
        // ログインユーザーを先頭に移動する。
        members.remove(i);
        members.add(0, eipUser);
      }
    }
    return query;
  }

  /**
   * ResultData に値を格納して返します。（一覧データ） <BR>
   * 
   * @param obj
   *            DBから取得したスケジュールマップ
   * @return 画面表示用データ
   * @see com.aimluck.eip.common.ALAbstractSelectData#getListData(java.lang.Object)
   */
  @Override
  protected Object getResultData(EipTScheduleMap record) throws ALPageNotFoundException, ALDBErrorException {
    ScheduleReferOnedayResultData rd = new ScheduleReferOnedayResultData();
    rd.initField();
    try {
      EipTSchedule schedule = record.getEipTSchedule();
      if ("R".equals(record.getStatus())) {
        return rd;
      }

      // if (!ScheduleUtils.isView(
      // getViewDate(),
      // schedule.getRepeatPattern(),
      // schedule.getStartDate(),
      // schedule.getEndDate())) {
      // return rd;
      // }

      SelectQuery<EipTScheduleMap> mapquery = Database.query(EipTScheduleMap.class);
      Expression mapexp1 = ExpressionFactory.matchExp(EipTScheduleMap.SCHEDULE_ID_PROPERTY, schedule.getScheduleId());
      mapquery.setQualifier(mapexp1);
      Expression mapexp2 = ExpressionFactory.matchExp(EipTScheduleMap.USER_ID_PROPERTY, Integer.valueOf(userid));
      mapquery.andQualifier(mapexp2);

      List<EipTScheduleMap> schedulemaps = mapquery.fetchList();

      // 共有スケジュールに対してログインユーザーがメンバーか？
      boolean is_member = (schedulemaps != null && schedulemaps.size() > 0) ? true : false;

      // change by motegi start
      // Dummy スケジュールではない
      // 完全に隠す
      // 自ユーザー以外
      // 共有メンバーではない
      // オーナーではない
      // if ((!"D".equals(record.getStatus()))
      // && "P".equals(schedule.getPublicFlag())
      // && (userid != record.getUserId().intValue())
      // && (userid != schedule.getOwnerId().intValue())
      // && !is_member) {
      // return rd;
      // }

      // 処理対象のMAPのユーザーに対する閲覧権限を取得する。
      String scheduleAcl = aclMap.get(record.getUserId());
      if ((ScheduleConst.SCHEDULE_ACL_PUBLIC.equals(scheduleAcl) || ScheduleConst.SCHEDULE_ACL_REFUSAL.equals(scheduleAcl))
        && !"D".equals(record.getStatus())
        && "P".equals(schedule.getPublicFlag())
        && !is_member) {
        // 完全に非公開(コンテナに格納しません）
        return rd;
      }

      if (ScheduleConst.SCHEDULE_ACL_SECRETARY.equals(scheduleAcl)
        && !"D".equals(record.getStatus())
        && "P".equals(schedule.getPublicFlag())
        && (schedule.getCreateUserId().intValue() == record.getUserId().intValue())
        && !is_member) {
        // 秘書設定元ユーザーが作成者で完全に非公開(コンテナに格納しません）
        return rd;
      }
      // change end

      // change start
      // if ("C".equals(schedule.getPublicFlag())
      // && (userid != record.getUserId().intValue())
      // && (userid != schedule.getOwnerId().intValue())
      // && !is_member) {
      if (("C".equals(schedule.getPublicFlag())
        && (ScheduleConst.SCHEDULE_ACL_PUBLIC.equals(scheduleAcl) || (ScheduleConst.SCHEDULE_ACL_SECRETARY.equals(scheduleAcl) && schedule
          .getOwnerId()
          .intValue() == record.getUserId().intValue())) && !is_member)
        || (ScheduleConst.SCHEDULE_ACL_REFUSAL.equals(scheduleAcl))) {
        // change end
        rd.setName("非公開");
        // 仮スケジュールかどうか
        rd.setTmpreserve(false);

        // add start
        // 状態
        rd.setStatus("");
        // 重要フラグ
        rd.setPriority("F");

        // add end
      } else {
        rd.setName(schedule.getName());
        // 仮スケジュールかどうか
        rd.setTmpreserve("T".equals(record.getStatus()));

        rd.setStatus(record.getStatus());
        // 重要フラグ
        rd.setPriority(record.getPriority());
      }

      // ID
      rd.setScheduleId(schedule.getScheduleId().intValue());
      // 親スケジュール ID
      rd.setParentId(schedule.getParentId().intValue());
      // 開始日時
      rd.setStartDate(schedule.getStartDate());
      // 終了日時
      rd.setEndDate(schedule.getEndDate());
      // 公開するかどうか
      rd.setPublic("O".equals(schedule.getPublicFlag()));
      // 非表示にするかどうか
      rd.setHidden("P".equals(schedule.getPublicFlag()));
      // ダミーか
      rd.setDummy("D".equals(record.getStatus()));
      // ログインユーザかどうか
      rd.setLoginuser(record.getUserId().intValue() == userid);
      // オーナーかどうか
      rd.setOwner(schedule.getOwnerId().intValue() == userid);
      // 共有メンバーかどうか
      rd.setMember(is_member);
      // 繰り返しパターン
      rd.setPattern(schedule.getRepeatPattern());

      // ユーザもしくは設備のコンテナを取得する．
      // ScheduleReferOnedayContainer con = normalMap.get(record.getUserId());
      ScheduleReferOnedayWorkingContainer con = tmpMap.get(record.getUserId());

      // 期間スケジュールの場合
      if (rd.getPattern().equals("S")) {
        is_hasspan = true;
        List<ScheduleReferOnedayResultData> terms = termmap.get(record.getUserId());
        if (terms != null) {
          // 期間スケジュールを格納
          terms.add(rd);
        }

        return rd;
      }

      if (rd.getPattern().equals(ScheduleConst.SCHEDULE_PATTERN_DAYS)) {
        // 日またぎ
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(getViewDate().getValue());
        cal1.set(Calendar.HOUR_OF_DAY, 0);
        cal1.set(Calendar.MINUTE, 0);
        Date tmpTargetDate = cal1.getTime();

        Calendar calStart = Calendar.getInstance();
        calStart.setTime(rd.getStartDate().getValue());
        calStart.set(Calendar.HOUR_OF_DAY, 0);
        calStart.set(Calendar.MINUTE, 0);
        Date tmpStartDate = calStart.getTime();

        Calendar calEnd = Calendar.getInstance();
        calEnd.setTime(rd.getEndDate().getValue());
        calEnd.set(Calendar.HOUR_OF_DAY, 0);
        calEnd.set(Calendar.MINUTE, 0);
        Date tmpEndDate = calEnd.getTime();

        Calendar temp = Calendar.getInstance();
        Calendar temp2 = Calendar.getInstance();
        if (tmpTargetDate.compareTo(tmpStartDate) == 0) {
          // 対象日が日またぎの開始日
          temp.setTime(rd.getStartDate().getValue());
          temp2.setTime(rd.getStartDate().getValue());
          temp2.set(Calendar.HOUR_OF_DAY, 23);
          temp2.set(Calendar.MINUTE, 59);
          temp2.set(Calendar.SECOND, 0);

          rd.setStartDate(temp.getTime());
          rd.setEndDate(temp2.getTime());
        } else if (tmpTargetDate.after(tmpStartDate) && tmpTargetDate.before(tmpEndDate)) {
          // 対象日が開始日より後、かつ対象日が終了日の前
          temp.setTime(getViewDate().getValue());
          temp.set(Calendar.HOUR_OF_DAY, 0);
          temp.set(Calendar.MINUTE, 0);
          temp.set(Calendar.SECOND, 0);
          temp2.setTime(getViewDate().getValue());
          temp2.set(Calendar.HOUR_OF_DAY, 23);
          temp2.set(Calendar.MINUTE, 59);
          temp2.set(Calendar.SECOND, 0);

          rd.setStartDate(temp.getTime());
          rd.setEndDate(temp2.getTime());
        } else if (tmpTargetDate.compareTo(tmpEndDate) == 0) {
          // 対象日が日またぎの終了日
          temp.setTime(rd.getEndDate().getValue());
          temp.set(Calendar.HOUR_OF_DAY, 0);
          temp.set(Calendar.MINUTE, 0);
          temp.set(Calendar.SECOND, 0);
          temp2.setTime(rd.getEndDate().getValue());

          rd.setStartDate(temp.getTime());
          rd.setEndDate(temp2.getTime());
        } else {
          // add start 運用フェーズ障害 No.9 2012.4.25
          // いずれの条件にも合致しなければ処理対象外
          return rd;
          // add end
        }

      } else if (!rd.getPattern().equals("N")) {
        // 繰り返しスケジュール
        if (!ScheduleUtils.isView(getViewDate(), rd.getPattern(), rd.getStartDate().getValue(), rd.getEndDate().getValue())) {
          return rd;
        }
        Calendar temp = Calendar.getInstance();
        temp.setTime(getViewDate().getValue());
        temp.set(Calendar.HOUR, Integer.parseInt(rd.getStartDate().getHour()));
        temp.set(Calendar.MINUTE, Integer.parseInt(rd.getStartDate().getMinute()));
        temp.set(Calendar.SECOND, 0);
        temp.set(Calendar.MILLISECOND, 0);
        Calendar temp2 = Calendar.getInstance();
        temp2.setTime(getViewDate().getValue());
        temp2.set(Calendar.HOUR, Integer.parseInt(rd.getEndDate().getHour()));
        temp2.set(Calendar.MINUTE, Integer.parseInt(rd.getEndDate().getMinute()));
        temp2.set(Calendar.SECOND, 0);
        temp2.set(Calendar.MILLISECOND, 0);
        rd.setStartDate(temp.getTime());
        rd.setEndDate(temp2.getTime());
        rd.setRepeat(true);
      }
      // con.addResultData(rd, startHour, endHour, getViewDate());
      // グルーピングを行なった後に、そしてdoViewList呼び出し後にまとめて行ないましょう。
      con.addResultData(rd);
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return rd;
  }

  /**
   * 
   * @param action
   * @param rundata
   * @param context
   * @return
   */
  @Override
  public boolean doViewList(ALAction action, RunData rundata, Context context) {
    boolean res = super.doViewList(action, rundata, context);
    // 後処理
    postDoList();
    return res;
  }

  /**
   * スケジュールの一日コンテナの各rows値の中で、最大値を取得します。
   * 
   * @param list
   */
  private int[] getMaxRowsFromContainer(Collection<ScheduleReferOnedayContainer> list) {

    int nowRows[] = new int[rows.length];
    for (ScheduleReferOnedayContainer container : list) {
      container.last(startHour, endHour, getViewDate());
      // if (container.isDuplicate()) {
      // is_duplicate = true;
      // }

      int size = rows.length;
      int[] tmpRows = container.getRows();
      for (int i = 0; i < size; i++) {
        if (tmpRows[i] > nowRows[i]) {
          nowRows[i] = tmpRows[i];
        }
      }
    }
    return nowRows;
  }

  /**
   * 検索後の処理を行います。
   * 
   */
  private void postDoList() {

    for (Entry<Integer, ScheduleReferOnedayWorkingContainer> entry : tmpMap.entrySet()) {
      ScheduleReferOnedayWorkingContainer tmpCon = entry.getValue();
      tmpCon.grouping();

      List<ScheduleReferOnedayResultData> list = tmpCon.getSchedule();
      ScheduleReferOnedayContainer con = normalMap.get(entry.getKey());
      for (ScheduleReferOnedayResultData rd : list) {
        con.addResultData(rd, startHour, endHour, getViewDate());
      }

    }

    int userRows[] = getMaxRowsFromContainer(normalMap.values());
    int size = rows.length;
    for (int i = 0; i < size; i++) {
      rows[i] = Math.max(rows[i], userRows[i]);
      max += rows[i];
    }
  }

  /**
   * ※未使用
   */
  @Override
  protected Attributes getColumnMap() {
    Attributes map = new Attributes();
    return map;
  }

  /**
   * 指定した時間のcolspanを取得します。
   * 
   * @param hour
   *            時間
   * @return colspan
   */
  public int getColspan(int hour) {
    return rows[(hour - startHour) * 4] + rows[(hour - startHour) * 4 + 1] + rows[(hour - startHour) * 4 + 2] + rows[(hour - startHour) * 4 + 3];
  }

  /**
   * 指定したスケジュールのcolspanを取得します。
   * 
   * @param rd
   * @param rows_
   * @return 指定したスケジュールのcolspan
   */
  public int getScheduleColspan(ScheduleReferOnedayResultData rd, int[] rows_) {
    int st = rd.getStartRow();
    int ed = rd.getEndRow();
    int span = 0;
    if (st == ed) {
      if (rows_[st] == rd.getIndex()) {
        span = rows[st] - rows_[st] + 1;
      } else {
        span = 1;
      }
    } else {
      for (int i = st; i < ed; i++) {
        span += rows[i];
      }
      span += 1 - rows_[st];
    }
    return span;
  }

  /**
   * 期間スケジュールを取得します。
   * 
   * @param id
   *            ユーザーID
   * @return 期間スケジュール
   */
  public ScheduleReferOnedayResultData getSpanSchedule(long id) {
    Integer userid = Integer.valueOf((int) id);
    return normalMap.get(userid).getSpanResultData();
  }

  /**
   * 指定したユーザーのスケジュールリストを取得します。
   * 
   * @param id
   *            ユーザーID
   * @return 通常スケジュールリスト
   */
  public List<ScheduleReferOnedayResultData> getScheduleList(long id) {
    Integer userid = Integer.valueOf((int) id);
    return normalMap.get(userid).getSchedule();
  }

  /**
   * 指定したユーザーのrowsを取得します。
   * 
   * @param id
   *            ユーザーID
   * @return
   */
  public int[] getRows(long id) {
    Integer userid = Integer.valueOf((int) id);
    return normalMap.get(userid).getRows();
  }

  // /**
  // * 指定したユーザーの重複スケジュールリストを取得します。
  // *
  // * @param id
  // * @return
  // */
  // public List<ScheduleReferOnedayResultData> getDuplicateScheduleList(long
  // id) {
  // Integer userid = Integer.valueOf((int) id);
  // return normalMap.get(userid).getDuplicateSchedule();
  // }

  /**
   * 閲覧メンバーを取得します。
   * 
   * @return
   */
  public List<ScheduleMemberUser> getMemberList() {
    return members;
  }

  /**
   * 指定したユーザーが自ユーザーかどうかを返します。
   * 
   * @param id
   * @return
   */
  public boolean isMatch(long id) {
    return userid == (int) id;
  }

  /**
   * colspanの最大値を返します。
   * 
   * @return
   */
  public int getMax() {
    return max - 1;
  }

  /**
   * 期間スケジュールがあるかどうかを返します。
   * 
   * @return
   */
  public boolean isHasspan() {
    return is_hasspan;
  }

  /**
   * 期間スケジュールリストを取得する.
   * 
   * @param id
   * @return
   */
  public List<ScheduleReferOnedayResultData> getTermResultDataList(long id) {
    return termmap.get(Integer.valueOf((int) id));
  }

  /**
   * ※未使用
   */
  @Override
  public String getAclPortletFeature() {
    // return ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_OTHER;
    return "";
  }

  /**
   * ※未使用
   */
  // @Override
  // public boolean hasAuthoritySelfInsert() {
  // // return hasAuthoritySelfInsert;
  // return true;
  // }
  // public boolean hasAuthorityFacilityInsert() {
  // return hasAuthorityFacilityInsert;
  // }
  /**
   * ログインユーザーID取得
   * 
   * @return ログインユーザーID
   */
  public int getLoginUserId() {
    return userid;
  }

  // /**
  // * 指定されたグループに所属するユーザーを取得します。
  // *
  // * @param groupname
  // * グループ名
  // * @return ALEipUser の List
  // */
  // public static List<ALEipUser> getUsers(List<Integer> userIds) {
  // List<ALEipUser> list = new ArrayList<ALEipUser>();
  //
  // // 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 (" + implode(",", userIds) + ") ");
  // statement.append("ORDER BY D.POSITION");
  //
  // String query = statement.toString();
  //
  // try {
  // List<TurbineUser> list2 =
  // Database.sql(TurbineUser.class, query).fetchList();
  //
  // ALEipUser user;
  // for (TurbineUser tuser : list2) {
  // user = new ALEipUser();
  // user.initField();
  // user.setUserId(tuser.getUserId());
  // user.setName(tuser.getLoginName());
  // user.setAliasName(tuser.getFirstName(), tuser.getLastName());
  // list.add(user);
  // }
  // } catch (Throwable t) {
  // logger.error(t);
  // }
  //
  // return list;
  // }

  // /**
  // * リストを指定された区切り文字列で連結した文字列に変換する
  // *
  // * @param glue
  // * 区切り文字列
  // * @param pieces
  // * 数字リスト
  // * @return 変換後文字列
  // */
  // private static String implode(String glue, List<Integer> pieces) {
  // StringBuffer buf = new StringBuffer();
  // for (int i = 0;; i++) {
  // buf.append(pieces.get(i));
  // if (i == pieces.size() - 1) {
  // break;
  // }
  // buf.append(glue);
  // }
  // return buf.toString();
  // }

  /**
   * リストを指定された区切り文字列で連結した文字列に変換する
   * 
   * @param glue
   *            区切り文字列
   * @param pieces
   *            数字リスト
   * @return 変換後文字列
   */
  private static String implode(String glue, String[] pieces) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0;; i++) {
      buf.append(pieces[i]);
      if (i == pieces.length - 1) {
        break;
      }
      buf.append(glue);
    }
    return buf.toString();
  }

  /**
   * 文字列を指定された区切り文字で区切ってリストにして取得する
   * 
   * @param glue
   *            区切り文字列
   * @param src
   *            文字列
   * @return リスト
   */
  private static String[] explode(String glue, String src) {
    List<String> list = new ArrayList<String>();
    StringTokenizer token = new StringTokenizer(src, glue);
    while (token.hasMoreTokens()) {
      list.add(token.nextToken());
    }
    return list.toArray(new String[list.size()]);
  }
}
