/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2008 Aimluck,Inc.
 * http://aipostyle.com/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.aimluck.eip.timecard;

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

import org.apache.cayenne.DataRow;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.SelectQuery;
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.ALDateField;
import com.aimluck.commons.field.ALDateTimeField;
import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.cayenne.om.portlet.EipTTimecard;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.DatabaseOrmService;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.timecard.util.TimecardUtils;
import com.aimluck.eip.util.ALEipUtils;

/**
 * タイムカードのフォームデータを管理するクラスです。 <BR>
 * 
 */
public class TimecardFormData extends ALAbstractFormData {

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

  /** ToDo名 */

  private ALNumberField timecard_id;

  private ALNumberField user_id;

  private ALStringField work_flag;

  private ALDateTimeField work_date;

  private ALStringField reason;

  private ALDateField create_date;

  private ALDateField update_date;

  private int entity_id;

  private int login_uid;

  private DataContext dataContext;

  /**
   * 
   * @param action
   * @param rundata
   * @param context
   * @see com.aimluck.eip.common.ALAbstractFormData#init(com.aimluck.eip.modules.actions.common.ALAction,
   *      org.apache.turbine.util.RunData, org.apache.velocity.context.Context)
   */
  public void init(ALAction action, RunData rundata, Context context)
      throws ALPageNotFoundException, ALDBErrorException {
    super.init(action, rundata, context);

    login_uid = ALEipUtils.getUserId(rundata);

    dataContext = DatabaseOrmService.getInstance().getDataContext();
  }

  /**
   * 各フィールドを初期化します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
    timecard_id = new ALNumberField();

    user_id = new ALNumberField();

    work_flag = new ALStringField();
    work_flag.setValue("0");

    work_date = new ALDateTimeField();
    work_date.setValue(new Date());
    work_date.setFieldName("勤怠時間");

    reason = new ALStringField();
    reason.setFieldName("修正理由");

    create_date = new ALDateField();
    create_date.setValue(new Date());

    update_date = new ALDateField();
    update_date.setValue(new Date());
  }

  /**
   * タイムカードの各フィールドに対する制約条件を設定します。 <BR>
   * 
   * @see com.aimluck.eip.common.ALAbstractFormData#setValidator()
   */
  protected void setValidator() {
    reason.setNotNull(true);
    reason.limitMaxLength(1000);

    work_date.setNotNull(true);
  }

  /**
   * タイムカードのフォームに入力されたデータの妥当性検証を行います。 <BR>
   * 
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#validate(java.util.ArrayList)
   */
  protected boolean validate(ArrayList msgList) {
    try {
      if (getMode() == ALEipConstants.MODE_INSERT) {
        SelectQuery workflg_query = new SelectQuery(EipTTimecard.class);
        Expression workflg_exp = ExpressionFactory.matchExp(
            EipTTimecard.USER_ID_PROPERTY, Integer.valueOf(login_uid));
        workflg_query.setQualifier(workflg_exp);
        workflg_query.addOrdering(EipTTimecard.WORK_DATE_PROPERTY, false);
        workflg_query.setFetchingDataRows(true);
        List workflg_list = dataContext.performQuery(workflg_query);
        if (workflg_list != null && workflg_list.size() > 0) {
          DataRow dataRow = (DataRow) workflg_list.get(0);

          if (((String) ALEipUtils.getObjFromDataRow(dataRow,
              EipTTimecard.WORK_FLAG_COLUMN)).equals(work_flag.getValue())) {
            return false;
          } else {
            return true;
          }
        } else {
          return true;
        }
      }

      Calendar cal = Calendar.getInstance();

      if (cal.getTime().before(work_date.getValue())) {
        // 未来時刻へは変更不可とする
        msgList
            .add("『 <span class='em'>勤怠時間</span> 』は『 <span class='em'>現在の時刻</span> 』以前で指定してください。");

        return false;
      }

      cal.setTime(work_date.getValue());
      cal.set(Calendar.DAY_OF_MONTH, 1);
      cal.set(Calendar.HOUR_OF_DAY, 0);
      cal.set(Calendar.MINUTE, 0);
      cal.set(Calendar.MILLISECOND, 0);

      SelectQuery query = new SelectQuery(EipTTimecard.class);
      Expression exp11 = ExpressionFactory.greaterOrEqualExp(
          EipTTimecard.WORK_DATE_PROPERTY, cal.getTime());
      cal.add(Calendar.MONTH, +1);
      Expression exp12 = ExpressionFactory.lessExp(
          EipTTimecard.WORK_DATE_PROPERTY, cal.getTime());
      query.setQualifier(exp11.andExp(exp12));
      Expression exp21 = ExpressionFactory.matchExp(
          EipTTimecard.USER_ID_PROPERTY, Integer.valueOf(login_uid));
      query.andQualifier(exp21);
      query.addOrdering(EipTTimecard.WORK_DATE_PROPERTY, true);
      List list = dataContext.performQuery(query);

      if (list == null || list.size() <= 0) {

      } else {
        EipTTimecard timecard0 = getNearlyAboveRecord(list, entity_id);
        EipTTimecard timecard1 = getNearlyBelowRecord(list, entity_id);

        // int id0 = 0;
        // int id1 = 0;
        // if (timecard0 != null) {
        // id0 = timecard0.getTimecardId().intValue();
        // }
        // if (timecard1 != null) {
        // id1 = timecard1.getTimecardId().intValue();
        // }

        if (timecard1 != null) {
          if (compareToDate(timecard1.getWorkDate(), work_date.getValue()) == 2) {
            if (timecard0 != null) {
              if (compareToDate(timecard0.getWorkDate(), work_date.getValue()) == 1) {

              } else {
                msgList
                    .add("『 <span class='em'>勤怠時間</span> 』は『 <span class='em'>前の勤怠時間</span> 』以降で指定してください。");
              }
            }
          } else {
            msgList
                .add("『 <span class='em'>勤怠時間</span> 』は『 <span class='em'>後の勤怠時間</span> 』以前で指定してください。");
          }
        } else {
          if (timecard0 != null) {
            if (compareToDate(timecard0.getWorkDate(), work_date.getValue()) == 1) {

            } else {
              msgList
                  .add("『 <span class='em'>勤怠時間</span> 』は『 <span class='em'>前の勤怠時間</span> 』以降で指定してください。");
            }
          }
        }
      }
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }

    reason.validate(msgList);
    work_date.validate(msgList);

    return (msgList.size() == 0);
  }

  private EipTTimecard getNearlyAboveRecord(List list, int timecard_id) {
    EipTTimecard result = null;
    EipTTimecard record = null;
    int size = list.size();
    for (int i = 0; i < size; i++) {
      record = (EipTTimecard) list.get(i);
      if (record.getTimecardId().intValue() >= timecard_id) {
        return result;
      } else {
        result = record;
      }
    }

    return null;
  }

  private EipTTimecard getNearlyBelowRecord(List list, int timecard_id) {
    EipTTimecard record = null;
    int size = list.size();
    for (int i = 0; i < size; i++) {
      record = (EipTTimecard) list.get(i);
      if (record.getTimecardId().intValue() > timecard_id) {
        return record;
      }
    }

    return null;
  }

  protected boolean setFormData(RunData rundata, Context context,
      ArrayList msgList) throws ALPageNotFoundException, ALDBErrorException {
    boolean res = super.setFormData(rundata, context, msgList);

    if (res) {
      if (getMode() == ALEipConstants.MODE_UPDATE) {
        try {
          entity_id = Integer.parseInt(ALEipUtils.getTemp(rundata, context,
              ALEipConstants.ENTITY_ID));
        } catch (Exception e) {

        }
      }
    }

    return res;
  }

  /**
   * タイムカードをデータベースから読み出します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#loadFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context)
   */
  protected boolean loadFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      // オブジェクトモデルを取得
      EipTTimecard timecard = TimecardUtils.getEipTTimecard(rundata, context);
      if (timecard == null)
        return false;
      // ToDo名
      timecard_id.setValue(timecard.getTimecardId().longValue());
      user_id.setValue(timecard.getUserId().intValue());
      work_flag.setValue(timecard.getWorkFlag());
      work_date.setValue(timecard.getWorkDate());

      reason.setValue(timecard.getReason());
      create_date.setValue(timecard.getCreateDate());
      update_date.setValue(timecard.getUpdateDate());

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

  /**
   * タイムカードをデータベースから削除します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#deleteFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context)
   */
  protected boolean deleteFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      // オブジェクトモデルを取得
      EipTTimecard timecard = TimecardUtils.getEipTTimecard(rundata, context);
      if (timecard == null)
        return false;
      // 打刻情報を削除
      dataContext.deleteObject(timecard);
      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
          timecard.getTimecardId(), ALEventlogConstants.PORTLET_TYPE_TIMECARD,
          reason.getValue());

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

  /**
   * タイムカードをデータベースに格納します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#insertFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean insertFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {

      // 新規オブジェクトモデル
      EipTTimecard timecard = (EipTTimecard) dataContext
          .createAndRegisterNewObject(EipTTimecard.class);
      // ユーザーID
      timecard.setUserId(Integer.valueOf(ALEipUtils.getUserId(rundata)));

      timecard.setWorkFlag(work_flag.getValue());
      timecard.setWorkDate(Calendar.getInstance().getTime());
      timecard.setReason(reason.getValue());

      // 作成日
      timecard.setCreateDate(Calendar.getInstance().getTime());
      // 更新日
      timecard.setUpdateDate(Calendar.getInstance().getTime());
      // タイムカードを登録
      dataContext.commitChanges();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
          timecard.getTimecardId(), ALEventlogConstants.PORTLET_TYPE_TIMECARD,
          null);

    } catch (Exception ex) {

      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  /**
   * データベースに格納されているタイムカードを更新します。 <BR>
   * 
   * @param rundata
   * @param context
   * @param msgList
   * @return TRUE 成功 FALSE 失敗
   * @see com.aimluck.eip.common.ALAbstractFormData#updateFormData(org.apache.turbine.util.RunData,
   *      org.apache.velocity.context.Context, java.util.ArrayList)
   */
  protected boolean updateFormData(RunData rundata, Context context,
      ArrayList msgList) {
    try {
      // オブジェクトモデルを取得
      EipTTimecard timecard = TimecardUtils.getEipTTimecard(rundata, context);
      if (timecard == null) {
        return false;
      }

      timecard.setWorkDate(work_date.getValue());

      timecard.setReason(reason.getValue());

      // 更新日
      timecard.setUpdateDate(Calendar.getInstance().getTime());
      // タイムカードを更新
      dataContext.commitChanges();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
          timecard.getTimecardId(), ALEventlogConstants.PORTLET_TYPE_TIMECARD,
          reason.getValue());

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

  /**
   * 
   * @return
   */
  public void setWorkFlag(String str) {
    work_flag.setValue(str);
  }

  public ALDateTimeField getWorkDate() {
    return work_date;
  }

  public ALStringField getReason() {
    return reason;
  }

  /**
   * 指定した2つの日付を比較する．
   * 
   * @param date1
   * @param date2
   * @param checkTime
   *            時間まで比較する場合，true．
   * @return 等しい場合，0. date1>date2の場合, 1. date1 <date2の場合, 2.
   */
  private int compareToDate(Date date1, Date date2) {
    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.setTime(date1);
    cal2.setTime(date2);

    int date1Year = cal1.get(Calendar.YEAR);
    int date1Month = cal1.get(Calendar.MONTH) + 1;
    int date1Day = cal1.get(Calendar.DATE);
    int date1Hour = cal1.get(Calendar.HOUR);
    int date1Minute = cal1.get(Calendar.MINUTE);
    int date1Second = cal1.get(Calendar.SECOND);
    int date2Year = cal2.get(Calendar.YEAR);
    int date2Month = cal2.get(Calendar.MONTH) + 1;
    int date2Day = cal2.get(Calendar.DATE);
    int date2Hour = cal2.get(Calendar.HOUR);
    int date2Minute = cal2.get(Calendar.MINUTE);
    int date2Second = cal2.get(Calendar.SECOND);

    if (date1Year == date2Year && date1Month == date2Month
        && date1Day == date2Day && date1Hour == date2Hour
        && date1Minute == date2Minute && date1Second == date2Second) {
      return 0;
    }
    if (cal1.after(cal2)) {
      return 2;
    } else {
      return 1;
    }
  }

  /**
   * アクセス権限チェック用メソッド。<br />
   * アクセス権限の機能名を返します。
   * 
   * @return
   */
  public String getAclPortletFeature() {
    return ALAccessControlConstants.POERTLET_FEATURE_TIMECARD_TIMECARD_SELF;
  }
}
