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

package com.aimluck.eip.schedule;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

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.ALCellStringField;
import com.aimluck.eip.cayenne.om.portlet.EipTSchedule;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipGroup;
import com.aimluck.eip.common.ALEipManager;
import com.aimluck.eip.common.ALEipPost;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.schedule.ScheduleConst.DayOfWeek;
import com.aimluck.eip.schedule.ScheduleConst.DayType;
import com.aimluck.eip.schedule.ScheduleConst.ScheduleWeekNumber;
import com.aimluck.eip.schedule.beans.CellScheduleFormBean;
import com.aimluck.eip.schedule.util.CellScheduleUtils;
import com.aimluck.eip.schedule.util.ScheduleUtils;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.user.beans.UserGroupLiteBean;
import com.aimluck.eip.user.util.UserUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * スケジュールのフォームデータを管理するクラスです。
 * 
 */
public abstract class AbstractCellScheduleFormData extends ALAbstractFormData {

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

  /** <code>FLAG_EDIT_REPEAT_DEF</code> デフォルト値（繰り返し編集範囲） */
  public static final int FLAG_EDIT_REPEAT_DEF = -1;

  /** <code>FLAG_EDIT_REPEAT_ALL</code> 個別日程を編集（繰り返し編集範囲） */
  public static final int FLAG_EDIT_REPEAT_ALL = 0;

  /** <code>FLAG_EDIT_SCHEDULE_ONE</code> 全日程を編集（繰り返し編集範囲） */
  public static final int FLAG_EDIT_REPEAT_ONE = 1;

  /** パラメータで持ち回すデータ */
  public CellScheduleFormBean form_data;

  /** <code>is_repeat</code> スケジュールタイプ */
  private ALCellStringField schedule_type;

  /** <code>login_user</code> ログインユーザー */
  private ALEipUser login_user;

  /** <code>selectData</code> 編集するスケジュールの1日の情報 */
  private ScheduleOnedayGroupSelectData selectData;

  /** <code>groups</code> グループ */
  private List<ALEipGroup> groups;

  /** <code>isOwner</code> 所有者かどうか */
  private boolean is_owner;

  private String tmpStart;

  private String tmpEnd;

  private String tmpView;

  protected String entity_id;

  private String aclPortletFeature;

  private boolean is_first;

  // add start
  /** 部署1情報を格納するリスト */
  public List<UserGroupLiteBean> post1_list;

  /** 選択中部署1名 */
  public String current_parent_group_name;

  // add end
  /**
   * 
   * @param action
   * @param rundata
   * @param context
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  @Override
  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    login_user = ALEipUtils.getALEipUser(rundata);

    is_owner = true;

    groups = ALEipUtils.getMyGroups(rundata);

    entity_id = ALEipUtils.getTemp(rundata, context, ALEipConstants.ENTITY_ID);

    aclPortletFeature = ALAccessControlConstants.POERTLET_FEATURE_SCHEDULE_SELF;

    is_first = !("".equals(rundata.getParameters().getString("is_first", "")));

    // add start
    // 部署1リスト
    post1_list = UserUtils.getUserParentGroupLiteBeans(rundata, "all");

    // 選択中部署1名
    current_parent_group_name =
      rundata
        .getParameters()
        .getString(ScheduleConst.CURRENT_PARENT_GROUP_NAME);
    // add end
    super.init(action, rundata, context);
  }

  /**
   * パラメータを読み込みます。
   * 
   * @param rundata
   * @param context
   */
  public void loadParameters(RunData rundata, Context context) {
    ScheduleUtils.loadParametersDelegate(
      rundata,
      context,
      tmpStart,
      tmpEnd,
      tmpView);
    tmpView = ALEipUtils.getTemp(rundata, context, "tmpView");

    ALEipUtils.setTemp(rundata, context, "tmpStart", tmpView + "-00-00");
    ALEipUtils.setTemp(rundata, context, "tmpEnd", tmpView + "-00-00");
    tmpStart = ALEipUtils.getTemp(rundata, context, "tmpStart");
    tmpEnd = ALEipUtils.getTemp(rundata, context, "tmpEnd");
  }

  /*
   *
   */
  public void initField() {
    form_data = new CellScheduleFormBean();
    form_data.initField(tmpStart, tmpEnd, tmpView);

    schedule_type = new ALCellStringField();
  }

  /*
   *
   */
  @Override
  protected void setValidator() {
    // remove start
    // getMonthDay()メソッド未使用のため削除
    // form_data.getMonthDay().setNotNull(true);
    // remove end
    form_data.getLimitStartDate().setNotNull(true);
    form_data.getLimitEndDate().setNotNull(true);

  }

  /**
   * 
   * @param msgList
   * @return
   * @throws ALDBErrorException
   * @throws ALPageNotFoundException
   */
  @Override
  protected boolean validate(List<String> msgList) throws ALDBErrorException,
      ALPageNotFoundException {
    return form_data.validateDelegate(
      msgList,
      getLoginUser(),
      entity_id,
      schedule_type.getValue());
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  @Override
  protected boolean loadFormData(RunData rundata, Context context,
      List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {
    try {
      // オブジェクトモデルを取得
      EipTSchedule record =
        ScheduleUtils.getEipTSchedule(rundata, context, false);
      if (record == null) {
        return false;
      }

      is_owner =
        (record.getOwnerId().longValue() == login_user.getUserId().getValue())
          ? true
          : false;

      schedule_type.setValue(CellScheduleUtils.getScheduleType(record));

      form_data.setResultData(record);

      loadCustomFormData(record);

      setFormData(rundata, context, msgList);

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

    }
    return true;
  }

  protected abstract void loadCustomFormData(EipTSchedule record);

  /**
   * 入力データを検証する．
   * 
   * @param action
   * @param rundata
   * @param context
   * @return TRUE 成功 FALSE 失敗
   */
  public boolean doCheck(ALAction action, RunData rundata, Context context) {
    try {
      init(action, rundata, context);
      // action.setMode(ALEipConstants.MODE_INSERT);
      List<String> msgList = new ArrayList<String>();
      setValidator();
      boolean res =
        (setFormData(rundata, context, msgList) && validate(msgList));
      if (!res) {
        action.setMode(ALEipConstants.MODE_NEW_FORM);
      }
      action.setResultData(this);
      action.addErrorMessages(msgList);
      action.putData(rundata, context);
      return res;
    } catch (ALPageNotFoundException e) {
      ALEipUtils.redirectPageNotFound(rundata);
      return false;
    } catch (ALDBErrorException e) {
      ALEipUtils.redirectDBError(rundata);
      return false;
    }
  }

  /**
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return
   * @throws ALPageNotFoundException
   * @throws ALDBErrorException
   */
  @Override
  protected boolean setFormData(RunData rundata, Context context,
      List<String> msgList) throws ALPageNotFoundException, ALDBErrorException {

    String st = rundata.getParameters().get("schedule_type");
    if (st != null) {
      schedule_type.setValue(st);
    }

    Field[] fields = form_data.getClass().getDeclaredFields();

    if (!is_first) {
      // add start
      // 参加ユーザー(必須)のリストを設定
      // add end
      form_data.getMemberList().clear();
      form_data.getMemberList().addAll(
        CellScheduleUtils.getShareUserMemberList(rundata));
      // add start
      // 参加ユーザー(任意)のリストを設定
      form_data.getSubMemberList().clear();
      form_data.getSubMemberList().addAll(
        CellScheduleUtils.getShareUserSubMemberList(rundata));
      // add end
    }

    // add start
    if (rundata.getParameters().containsKey("to_form_note")) {
      if ((!ScheduleUtils.isContains(form_data.getMemberList(), login_user))
        && (!ScheduleUtils.isContains(form_data.getSubMemberList(), login_user))) {
        msgList.add("『 参加メンバー 』に主催者を入れて下さい。");
      }
      if (isDuplication(form_data.getMemberList(), form_data.getSubMemberList())) {
        msgList.add("『 任意参加メンバー 』と『 必須参加メンバー 』で重複ユーザーがいます。");
      }
    }
    // add end
    @SuppressWarnings("unused")
    boolean res =
      ScheduleUtils.setFormDataDelegate(
        rundata,
        context,
        form_data,
        fields,
        msgList);

    if (msgList.size() >= 1) {
      return false;
    }

    if (!isSpan() && !isCrossOver()) {
      Calendar startDate = Calendar.getInstance();
      startDate.setTime(form_data.getStartDate().getValue());

      Calendar endDate = Calendar.getInstance();
      endDate.setTime(form_data.getEndDate().getValue());
      endDate.set(Calendar.YEAR, startDate.get(Calendar.YEAR));
      endDate.set(Calendar.MONTH, startDate.get(Calendar.MONTH));
      endDate.set(Calendar.DATE, startDate.get(Calendar.DATE));
      form_data.getEndDate().setValue(endDate.getTime());

      // remove start
      // 共有施設設定は未使用のため削除
      // if (!is_first) {
      // form_data.getFacilityMemberList().clear();
      // form_data.getFacilityMemberList().addAll(
      // CellScheduleUtils.getShareFacilityMemberList(rundata));
      // }
      // remove end
    }
    return true;
  }

  /**
   * 指定したグループ名のユーザーを取得します。
   * 
   * @param groupname
   * @return
   */
  public List<ALEipUser> getUsers(String groupname) {
    return ALEipUtils.getUsers(groupname);
  }

  /**
   * 部署マップを取得します。
   * 
   * @return
   */
  public Map<Integer, ALEipPost> getPostMap() {
    return ALEipManager.getInstance().getPostMap();
  }

  // add start
  /**
   * 部署1マップを取得します。
   * 
   * @return
   */
  public List<UserGroupLiteBean> getPost1Map() {
    return post1_list;
  }

  /**
   * 遷移元画面で選択された部署1名に紐づく 部署2リストを取得するメソッドです。
   * 
   * @return 部署2データ
   */
  public List<UserGroupLiteBean> getPost2Map() {
    if (current_parent_group_name != null
      && current_parent_group_name.length() > 0) {
      return UserUtils.getPost2LiteBeans(current_parent_group_name);
    }
    return new ArrayList<UserGroupLiteBean>(0);
  }

  /**
   * 第何週列挙体を返します。
   * 
   * @return 第何週列挙体の配列
   */
  public ScheduleWeekNumber[] getWeekNums() {
    return ScheduleWeekNumber.values();
  }

  /**
   * 曜日列挙体を返します。
   * 
   * @return 曜日列挙体の配列
   */
  public DayOfWeek[] getDoWs() {
    return DayOfWeek.values();
  }

  /**
   * 日種類列挙体を返します。
   * 
   * @return 日種類列挙体の配列
   */
  public DayType[] getDayTypes() {
    return DayType.values();
  }

  // add end

  /**
   * フォームデータを取得します。
   * 
   * @return
   */
  public CellScheduleFormBean getFormData() {
    return form_data;
  }

  /**
   * 
   * @return
   */
  public boolean isOwner() {
    return is_owner;
  }

  public boolean isFirst() {
    return is_first;
  }

  public boolean isOneday() {
    return CellScheduleUtils.SCHEDULE_TYPE_ONEDAY.equals(schedule_type
      .getValue());
  }

  public boolean isSpan() {
    return CellScheduleUtils.SCHEDULE_TYPE_SPAN
      .equals(schedule_type.getValue());
  }

  public boolean isRepeat() {
    return CellScheduleUtils.SCHEDULE_TYPE_REPEAT.equals(schedule_type
      .getValue());
  }

  public boolean isCrossOver() {
    return CellScheduleUtils.SCHEDULE_TYPE_CROSS_OVER.equals(schedule_type
      .getValue());
  }

  /**
   * ログインユーザを取得します。
   * 
   * @return
   */
  public ALEipUser getLoginUser() {
    return login_user;
  }

  /**
   * 編集するスケジュールの1日の情報を取得します。
   * 
   * @return
   */
  public ScheduleOnedayGroupSelectData getSelectData() {
    return selectData;
  }

  /**
   * スケジュールタイプを取得します。
   * 
   * @return
   */
  public ALCellStringField getScheduleType() {
    return schedule_type;
  }

  /**
   * グループリストを取得します。
   * 
   * @return
   */
  public List<ALEipGroup> getGroupList() {
    return groups;
  }

  public int getInt(long num) {
    return (int) num;
  }

  @Override
  public String getEntityId() {
    return entity_id;
  }

  @Override
  public String getAclPortletFeature() {
    return aclPortletFeature;
  }

  /**
   * 「日指定」日間隔を数値型で取得します。
   * 
   * @return
   */
  public int getDayIntervalbyInt() {
    return (int) form_data.getDayInterval().getValue();
  }

  /**
   * 「週指定」日間隔を数値型で取得します。
   * 
   * @return
   */
  public int getWeekIntervalbyInt() {
    return (int) form_data.getWeekInterval().getValue();
  }

  /**
   * 「年日指定」月間隔を数値型で取得します。
   * 
   * @return
   */
  public int getMdMonthIntervalbyInt() {
    return (int) form_data.getMdMonthInterval().getValue();
  }

  /**
   * 「年週指定」月間隔を数値型で取得します。
   * 
   * @return
   */
  public int getMwMonthIntervalbyInt() {
    return (int) form_data.getMwMonthInterval().getValue();
  }

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