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

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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.SQLTemplate;
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.eip.cayenne.om.portlet.EipTExtTimecard;
import com.aimluck.eip.cayenne.om.portlet.EipTExtTimecardSystem;
import com.aimluck.eip.cayenne.om.portlet.ImwTDutyStatus;
import com.aimluck.eip.cayenne.om.portlet.ImwTExtTimecardDetail;
import com.aimluck.eip.cayenne.om.portlet.ImwTExtTimecardSystemDetail;
import com.aimluck.eip.cayenne.om.portlet.ImwTOffice;
import com.aimluck.eip.cayenne.om.portlet.ImwTOfficeCalendar;
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.ALEipHolidaysManager;
import com.aimluck.eip.exttimecard.util.ExtTimecardUtils;
import jp.co.imtt.businesssystem.util.BusinessSystemUtils;
import com.aimluck.eip.orm.DatabaseOrmService;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.common.ALEipUser;

/**
 * タイムカードのResultDataです。 <BR>
 * 
 * 追記：（青柳）
 *　カレンダーの一日に対応したデータなので、タイムカードのレコードと必ずしも一致していない。
 *　タイムカードの打刻が無いデータとしてもリストに存在しているデータです。
 *
 */
public class ExtTimecardListResultData implements ALData {

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

  private ALDateField date = null;

  private ExtTimecardResultData rd;

  /** 土曜日かどうか */
  private boolean is_saturday;

  /** 日曜日かどうか */
  private boolean is_sunday;

  private List list = null;

  /** タイムカードの設定 */
  private EipTExtTimecardSystem timecard_system;

  /** 計算済み就業時間 */
  private float calculated_work_hour = NO_DATA;

  /** 計算済み残業時間 */
  private float calculated_overtime_hour = NO_DATA;

  /** 時間データがないことを示す数値 */
  public static final float NO_DATA = -1f;

  /** 特定の日付より前から後かを示す変数 */
  private int beforeafter;

  /**
   *
   * @see com.aimluck.eip.common.ALData#initField()
   */
  public void initField() {
    date = new ALDateField();
    date.setValue(new Date());
    list = new ArrayList();
    beforeafter = 0;
  }

  /**
   * 日付を設定します。
   *
   * @param resultdata
   */
  public void setDate(Date date) {
    this.date.setValue(date);
  }

  /**
   * 現在設定されている日付を取得します。
   *
   * @return
   */
  public String getDate() {
    return date.getValue().toString();
  }

  /**
   * タイムカードのResultDataを設定します。
   *
   * @param resultdata
   */
  public void setRd(ExtTimecardResultData resultdata) {
    rd = resultdata;
  }

  /**
   * タイムカードのResultDataを取得します。
   *
   * @param
   */
  public ExtTimecardResultData getRd() {
    return rd;
  }

  /**
   * ResultDataがあるかどうか
   *
   * @param
   */
  public boolean getIsResultData() {
    return (rd != null);
  }

  /**
   * 日付が今日より前であるかどうか
   *
   * @param
   */
  public int getIsBeforeOrAfterToday() {
    try {
      Date today = new Date();
      Date now = date.getValue().getDate();
      if (ExtTimecardUtils.sameDay(now, today)) {
        return 0;
      }
      return now.compareTo(today);
    } catch (Exception e) {
      return 0;
    }
  }

  /**
   * 日付が今日より前であるかどうか、日付変更時間を考慮する
   */
  public int getIsBeforeOrafterTodayAlter() {

    try {

      int change_time = timecard_system.getChangeHour().intValue();
      Date today = new Date();
      long time = today.getTime() - Long.valueOf(Integer.toString(change_time * 60 * 60 * 1000));
      today.setTime(time);

      Date now = date.getValue().getDate();

      logger.debug(today.toString());
      logger.error(now.toString());

      if (ExtTimecardUtils.sameDay(now, today)) {
        return 0;
      }
      return now.compareTo(today);
    } catch (Exception e) {
      return 0;
    }

  }

 
  /**
   * 曜日が土曜日であるか、日曜日であるか、休日であるか取得
   *
   * @return int 0 ... 平日 1 ... 土曜日 2 ... 日曜日 3 ... 休日
   */
  public int getIsSaturdayOrSundayOrHolidayDefault() {
     try {
      Date now = date.getValue().getDate();
      ALEipHolidaysManager holidaysManager = ALEipHolidaysManager.getInstance();
      if (holidaysManager.isHoliday(now) != null) {
        return 3;
      }
      Calendar cal = Calendar.getInstance();
      cal.setTime(now);
      if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
        return 1;
      }
      if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
        return 2;
      }
      return 0;
    } catch (Exception e) {
      return -1;
    }
  }

  /**
   * 出勤時間が空かどうか
   *
   * @return
   */
  public boolean getIsNotNullClockInTime() {
    if (rd == null)
      return false;
    if (rd.getIsNullClockInTime())
      return false;
    return true;
  }

  /**
   * 退勤時間が空かどうか
   *
   * @return
   */
  public boolean getIsNotNullClockOutTime() {
    if (rd == null)
      return false;
    if (rd.getIsNullClockOutTime())
      return false;
    return true;
  }

  /**
   * 外出／復帰の回数を得ます。
   *
   * @return
   */
  public int getOutgoingComebackTimes() {
    if (rd == null)
      return 1;
    return Math.max(Math.max(rd.getAllOutgoingTime().size(), rd
        .getAllComebackTime().size()), 1);
  }

  /**
   * 外出／復帰の配列を得ます。
   *
   * @return
   */
  public ArrayList getOutgoingComeback() {
    ArrayList result_list = new ArrayList();

    Map dummymap = new HashMap();
    dummymap.put("outgoing", "");
    dummymap.put("comeback", "");
    if (rd == null) {
      result_list.add(dummymap);
    } else {
      ArrayList<ALDateTimeField> out = rd.getAllOutgoingTime();
      ArrayList<ALDateTimeField> come = rd.getAllComebackTime();
      // ALDateTimeField out[] = rd.getAllOutgoingTime();
      // ALDateTimeField come[] = rd.getAllComebackTime();
      for (int i = 0; i < EipTExtTimecard.OUTGOING_COMEBACK_PER_DAY; i++) {
        boolean isnullout = out.get(i).isNullHour();
        boolean isnullcome = come.get(i).isNullHour();
        if (isnullout && isnullcome) {
          break;
        }
        Map map = new HashMap();
        map.put("outgoing", isnullout ? "" : out.get(i).getHour() + "時"
            + out.get(i).getMinute() + "分");
        map.put("comeback", isnullcome ? "" : come.get(i).getHour() + "時"
            + come.get(i).getMinute() + "分");
        result_list.add(map);
      }
      if (result_list.size() == 0) {
        result_list.add(dummymap);
      }
    }
    return result_list;
  }

  /**
   * 外出／復帰の配列を得ます。
   *
   * @return
   */
  public ArrayList getOutgoingComeback_xls() {
    ArrayList result_list = new ArrayList();

    Map dummymap = new HashMap();
    dummymap.put("outgoing", "");
    dummymap.put("comeback", "");
    if (rd == null) {
      result_list.add(dummymap);
    } else {
      ArrayList<ALDateTimeField> out = rd.getAllOutgoingTime();
      ArrayList<ALDateTimeField> come = rd.getAllComebackTime();
      SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
      for (int i = 0; i < EipTExtTimecard.OUTGOING_COMEBACK_PER_DAY; i++) {
        boolean isnullout = out.get(i).isNullHour();
        boolean isnullcome = come.get(i).isNullHour();
        if (isnullout && isnullcome) {
          // break;
        }
        String out_str = "", come_str = "";
        try {
          if (!isnullout) {
            out_str = sdf.format(out.get(i).getValue());
          }
          if (!isnullcome) {
            come_str = sdf.format(come.get(i).getValue());
          }
        } catch (Exception e) {
          out_str = "";
          come_str = "";
        }
        Map map = new HashMap();
        map.put("outgoing", out_str);
        map.put("comeback", come_str);
        result_list.add(map);
      }
      if (result_list.size() == 0) {
        result_list.add(dummymap);
      }
    }
    return result_list;
  }

  private String changeMinute(String minute) {
    if (Integer.parseInt(minute) >= 0 && Integer.parseInt(minute) <= 9)
      return minute = "0" + minute;
    return minute;
  }

  /**
   * 就業時間を計算します。
   *
   * @return float
   */
  public float getWorkHour() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return NO_DATA;
    } else if (calculated_work_hour != NO_DATA) {
      return calculated_work_hour;
    } else {
      float time = 0f;
      time += rd.getClockOutTime().getValue().getTime()
      - rd.getClockInTime().getValue().getTime();
      time /= 1000.0 * 60.0 * 60.0;

      /** 外出時間を就業時間に含めない場合 */
      if (timecard_system.getOutgoingAddFlag().equals("F")) {
        float outgoing_time = getOutgoingTime(rd.getClockInTime().getValue(),
            rd.getClockOutTime().getValue());
        if (outgoing_time != NO_DATA) {
          time -= outgoing_time;
        } else {
          return NO_DATA;
        }
      }
      calculated_work_hour = time;
      return time;
    }
  }

  /**
   * 就業時間を計算します。
   *
   * @return float
   */
  public float getInworkHour() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return -1f;
    } else {
      float time = 0f;
      time += (rd.getClockOutTime().getValue().getTime() - rd.getClockInTime()
          .getValue().getTime())
          / (1000.0 * 60.0 * 60.0);

      /** 外出時間を就業時間に含めない場合 */
      if (timecard_system.getOutgoingAddFlag().equals("F")) {
        float outgoing_time = getOutgoingTime(getStartDate(), getEndDate());
        if (outgoing_time != NO_DATA) {
          time -= outgoing_time;
        } else {
          return NO_DATA;
        }
      }
      return time;
    }
  }

  /**
   * 残業時間を計算します。
   *
   * @return float
   */
  public float getOutworkHour() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return -1f;
    } else {
      float time = 0f;
      if (getIsSaturdayOrSundayOrHoliday() == 0) {
        long start_time, end_time;
        int start_hour = timecard_system.getStartHour(), start_minute = timecard_system
            .getStartMinute();
        int end_hour = timecard_system.getEndHour(), end_minute = timecard_system
            .getEndMinute();

        Calendar cal = Calendar.getInstance();

        try {
          cal.setTime(date.getValue().getDate());
        } catch (Exception e) {
        }

        cal.set(Calendar.HOUR_OF_DAY, start_hour);
        cal.set(Calendar.MINUTE, start_minute);
        start_time = cal.getTime().getTime();

        cal.set(Calendar.HOUR_OF_DAY, end_hour);
        cal.set(Calendar.MINUTE, end_minute);
        end_time = cal.getTime().getTime();

        if (start_hour >= 0 && start_hour < timecard_system.getChangeHour()) {
          start_time += 1000 * 60 * 60 * 24;
          end_time += 1000 * 60 * 60 * 24;
        } else if (end_hour >= 0 && end_hour < timecard_system.getChangeHour()) {
          end_time += 1000 * 60 * 60 * 24;
        }

        /** 早出残業 */
        if (rd.getClockInTime().getValue().getTime() < start_time) {
          time += start_time - rd.getClockInTime().getValue().getTime();
        }

        /** 残業 */
        if (end_time < rd.getClockOutTime().getValue().getTime()) {
          time += rd.getClockOutTime().getValue().getTime() - end_time;
        }
        time /= (1000.0 * 60.0 * 60.0);
      }
      return time;
    }
  }

  /**
   * 休出時間を計算します。
   *
   * @return float
   */
  public float getOffWorkHour() {
    if (getIsSaturdayOrSundayOrHoliday() != 0) {
      return getWorkHour();
    }
    return -1f;
  }

  /**
   * 休憩時間を差し引いた就業時間を計算します。
   *
   * @return float
   */
  public float getWorkHourWithoutRestHour() {
    return getWorkHourWithoutRestHour(false);
  }

  public float getWorkHourWithoutRestHour(boolean round) {
    float time = NO_DATA;
    if (calculated_work_hour != NO_DATA) {
      time = calculated_work_hour;
    } else {
      time = getWorkHour();
    }
    time -= getRestHour();
    if (round) {
      time = ExtTimecardUtils.roundHour(time);
    }
    return time;
  }

  /**
   * 残業時間を計算します。
   *
   * @return float
   */
  public float getOvertimeHour() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return NO_DATA;
    } else if (calculated_overtime_hour != NO_DATA) {
      return calculated_overtime_hour;
    } else {
      float time = 0f;
      if (getIsSaturdayOrSundayOrHoliday() == 0) {
        Date start_date = getStartDate(), end_date = getEndDate();
        long start_time = start_date.getTime(), end_time = end_date.getTime();

        /** 早出残業 */
        if (rd.getClockInTime().getValue().getTime() < start_time) {
          time += start_time - rd.getClockInTime().getValue().getTime();
          if (rd.getClockOutTime().getValue().getTime() < start_time) {
            time -= start_time - rd.getClockOutTime().getValue().getTime();
          }
        }

        /** 残業 */
        if (end_time < rd.getClockOutTime().getValue().getTime()) {
          time += rd.getClockOutTime().getValue().getTime() - end_time;
          if (end_time < rd.getClockInTime().getValue().getTime()) {
            time -= rd.getClockInTime().getValue().getTime() - end_time;
          }
        }
        time /= (1000.0 * 60.0 * 60.0);

        /** 外出時間を就業時間に含めない場合 */
        if (timecard_system.getOutgoingAddFlag().equals("F")) {
          float outgoing_time;
          outgoing_time = getOutgoingTime(rd.getClockInTime().getValue(),
              start_date);
          if (outgoing_time != NO_DATA) {
            time -= outgoing_time;
          } else {
            return NO_DATA;
          }
          outgoing_time = getOutgoingTime(end_date, rd.getClockOutTime()
              .getValue());
          if (outgoing_time != NO_DATA) {
            time -= outgoing_time;
          } else {
            return NO_DATA;
          }
        }
      }
      calculated_overtime_hour = time;
      return time;
    }
  }

  /**
   * 休憩時間を差し引いた残業時間を計算します。
   *
   * @return float
   */
  public float getOvertimeHourWithoutRestHour() {
    return getOvertimeHourWithoutRestHour(false);
  }

  public float getOvertimeHourWithoutRestHour(boolean round) {
    float time = NO_DATA;
    if (calculated_overtime_hour != NO_DATA) {
      time = calculated_overtime_hour;
    } else {
      time = getOvertimeHour();
    }
    time -= getOvertimeRestHour();
    if (round) {
      time = ExtTimecardUtils.roundHour(time);
    }
    return time;
  }

  /**
   * 休出時間を計算します。
   *
   * @return float
   */
  public float getOffHour() {
    return getOffHour(false);
  }

  public float getOffHour(boolean round) {
    if (getIsSaturdayOrSundayOrHoliday() != 0) {
      return getWorkHourWithoutRestHour(round);
    }
    return NO_DATA;
  }

  /**
   * 休憩時間を計算します。
   *
   * @return float
   */
  public float getRestHour() {
    float time = 0f, work, overtime;
    if (getWorkHour() != NO_DATA && getOvertimeHour() != NO_DATA) {
      work = getWorkHour() - getOvertimeHour();
      overtime = getOvertimeHour();
      int rest_work_num = 0, rest_overtime_num = 0;
      int rest_work_extra = 0, rest_overtime_extra = 0;
      if (work > 0) {
        rest_work_num = (int) (work * 60 / (timecard_system.getWorktimeIn() + timecard_system
            .getResttimeIn()));
        rest_work_extra = (int) (work
            * 60
            - rest_work_num
            * (timecard_system.getWorktimeIn() + timecard_system
                .getResttimeIn()) - timecard_system.getWorktimeIn());
        if (rest_work_extra < 0) {
          rest_work_extra = 0;
        }
      }
      if (overtime > 0) {
        rest_overtime_num = (int) (overtime * 60 / (timecard_system
            .getWorktimeOut() + timecard_system.getResttimeOut()));
        rest_overtime_extra = (int) (overtime
            * 60
            - rest_overtime_num
            * (timecard_system.getWorktimeOut() + timecard_system
                .getResttimeOut()) - timecard_system.getWorktimeOut());
        if (rest_overtime_extra < 0) {
          rest_overtime_extra = 0;
        }
      }
      time = rest_work_num * timecard_system.getResttimeIn()
          + rest_overtime_num * timecard_system.getResttimeOut()
          + rest_work_extra + rest_overtime_extra;
      time /= 60;
      return time;
    } else {
      return NO_DATA;
    }
  }

  /**
   * 残業時間中の休憩時間を計算します。
   *
   * @return float
   */
  public float getOvertimeRestHour() {
    float time = 0f, overtime;
    overtime = getOvertimeHour();
    if (overtime != NO_DATA) {
      int rest_overtime_num, rest_overtime_extra;
      rest_overtime_num = (int) (overtime * 60 / (timecard_system
          .getWorktimeOut() + timecard_system.getResttimeOut()));
      rest_overtime_extra = (int) (overtime
          * 60
          - rest_overtime_num
          * (timecard_system.getWorktimeOut() + timecard_system
              .getResttimeOut()) - timecard_system.getWorktimeOut());
      if (rest_overtime_extra < 0) {
        rest_overtime_extra = 0;
      }
      time = rest_overtime_num * timecard_system.getResttimeOut()
          + rest_overtime_extra;
      time /= 60;
      return time;
    } else {
      return NO_DATA;
    }
  }

  /**
   * その日遅刻したかどうか
   *
   * @return boolean
   */
  public boolean isLateComing() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return false;
    }
    Date start_date = getStartDate();
    if (rd.getClockInTime().getValue().after(start_date)) {
      return true;
    }
    return false;
  }

  /**
   * その日早退したかどうか
   *
   * @return boolean
   */
  public boolean isEarlyLeaving() {
    if (!getIsNotNullClockInTime() || !getIsNotNullClockOutTime()) {
      return false;
    }
    Date end_date = getEndDate();
    if (rd.getClockOutTime().getValue().before(end_date)) {
      return true;
    }
    return false;
  }

  /**
   * その日欠勤したかどうか
   *
   * @return boolean
   */
  public boolean isAbsent() {
    return false;
  }

  /**
   *
   *
   */
  public String getHourToString(float time) {
    if (time == NO_DATA) {
      return "";
    }
    return time + "h";
  }

  /**
   * 日付をURLパラメータ形式で取得します。
   *
   * @return
   */
  public String getDateParamstring() {
    try {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      return sdf.format(date.getValue().getDate());
    } catch (Exception e) {
      return "";
    }
  }
  
  /**
   * 日付を取得します。
   *
   * @return
   */
  public String getDateStr() {
    try {
      SimpleDateFormat sdf = new SimpleDateFormat("dd （EE）");
      return sdf.format(date.getValue().getDate());
    } catch (Exception e) {
      return "";
    }
  }

  /**
   * 日付を取得します。
   *
   * @return
   */
  public String getDateStr(String str) {
    try {
      if (str == null || "".equals(str)) {
        str = "yyyy年MM月dd日（EE）";
      }
      SimpleDateFormat sdf = new SimpleDateFormat(str);
      return sdf.format(date.getValue().getDate());
    } catch (Exception e) {
      return "";
    }
  }

  /**
   * タイムカードの設定を取得します。
   *
   * @return
   */
  public EipTExtTimecardSystem getTimecardSystem() {
    return timecard_system;
  }

  /**
   * タイムカードの設定を読み込みます。
   *
   * @return
   */
  public void setTimecardSystem(EipTExtTimecardSystem system) {
    timecard_system = system;
  }

  public Date getClockInDate() {
    return rd.getClockInTime().getValue();
  }

  public List getList() {
    return list;
  }

  public List getViewList() {
    ArrayList viewlist = new ArrayList();

    //ExtTimecardResultData rd = null;

    //int size = list.size();
    //for (int i = 0; i < size; i++) {
      //rd = (ExtTimecardResultData) list.get(i);
      /*
       * if
       * (!ExtTimecardUtils.WORK_FLG_DUMMY.equals(rd.getWorkFlag().getValue()))
       * { viewlist.add(rd); }
       */
    //}
    return viewlist;
  }

  public void addExtTimecardResultData(ExtTimecardResultData rd) {
    list.add(rd);
  }

  public String getSummayTimes() {
    double millisecond = 0;
    Date workOnDate = null;
    Date workOffDate = null;
    ExtTimecardResultData rd = null;
    int size = list.size();

    if (size < 1) {
      return "0";
    }
    return "0";

    /*
     * if (size == 1) { rd = (ExtTimecardResultData) list.get(size - 1); if
     * (ExtTimecardUtils.WORK_FLG_ON.equals(rd.getWorkFlag().getValue())) {
     * workOnDate = rd.getWorkDate().getValue(); Calendar cal =
     * Calendar.getInstance(); millisecond += cal.getTime().getTime() -
     * workOnDate.getTime(); } else { workOffDate = rd.getWorkDate().getValue();
     * // 退勤から始まる場合 Calendar cal = Calendar.getInstance();
     * cal.setTime(workOffDate); cal.set(Calendar.HOUR_OF_DAY, 0);
     * cal.set(Calendar.MINUTE, 0); millisecond += workOffDate.getTime() -
     * cal.getTime().getTime(); } } else { for (int i = 0; i < size; i++) { rd =
     * (ExtTimecardResultData) list.get(i); if
     * (ExtTimecardUtils.WORK_FLG_ON.equals(rd.getWorkFlag().getValue())) {
     * workOnDate = rd.getWorkDate().getValue(); } else { workOffDate =
     * rd.getWorkDate().getValue(); if (workOnDate == null) { // 前日の最後が『出勤』の場合
     * Calendar cal = Calendar.getInstance(); cal.setTime(workOffDate);
     * cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0);
     * millisecond += workOffDate.getTime() - cal.getTime().getTime(); } else {
     * millisecond += workOffDate.getTime() - workOnDate.getTime(); } } } }
     * BigDecimal decimal = new BigDecimal(millisecond / 1000 / 60 / 60);
     * DecimalFormat dformat = new DecimalFormat("##.#"); return
     * dformat.format(decimal.setScale(1, BigDecimal.ROUND_FLOOR)
     * .doubleValue());
     */
  }

  /**
   * 始業時間を取得します。
   *
   * @return
   */
  private Date getStartDate() {
    int start_hour = timecard_system.getStartHour(), start_minute = timecard_system
        .getStartMinute();
    Calendar cal = Calendar.getInstance();
    try {
      cal.setTime(rd.getPunchDate().getValue());
    } catch (Exception e) {
    }
    cal.set(Calendar.HOUR_OF_DAY, start_hour);
    cal.set(Calendar.MINUTE, start_minute);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    if (start_hour >= 0 && start_hour < timecard_system.getChangeHour()) {
      cal.add(Calendar.DAY_OF_MONTH, 1);
    }
    return cal.getTime();
  }

  /**
   * 就業時間を取得します。
   *
   * @return
   */
  private Date getEndDate() {
    int end_hour = timecard_system.getEndHour(), end_minute = timecard_system
        .getEndMinute();
    Calendar cal = Calendar.getInstance();
    try {
      cal.setTime(rd.getPunchDate().getValue());
    } catch (Exception e) {
    }
    cal.set(Calendar.HOUR_OF_DAY, end_hour);
    cal.set(Calendar.MINUTE, end_minute);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    if (end_hour >= 0 && end_hour < timecard_system.getChangeHour()) {
      cal.add(Calendar.DAY_OF_MONTH, 1);
    }
    return cal.getTime();
  }

  /**
   * 特定の時間中に含まれる外出時間を計算します。
   *
   * @param from_date
   * @param to_date
   * @return
   */
  private float getOutgoingTime(Date from_date, Date to_date) {
    long outgoing_time = 0;
    int comeback_num = 0, outgoing_num = 0, from_num = -1, to_num = -1;
    if (from_date.getTime() > to_date.getTime()) {
      return 0.0f;
    }
    for (ALDateTimeField field : rd.getAllComebackTime()) {
      if (field.isNullHour())
        break;
      comeback_num++;
      /** 勤務時間より前だった場合は無視。はじめて勤務時間より後になった番号を記録する */
      if (field.getValue().getTime() < from_date.getTime()) {
        continue;
      } else if (from_num == -1) {
        from_num = comeback_num;
      }
      /** 勤務時間より後だった場合は番号を記録し打ち切る */
      if (field.getValue().getTime() > to_date.getTime()) {
        to_num = comeback_num;
        outgoing_time += to_date.getTime();
        break;
      }
      outgoing_time += field.getValue().getTime();
    }

    /** 外出時間がすべて勤務時間より前だった場合は、外出時間は0とする */
    if (from_num != -1) {
      for (ALDateTimeField field : rd.getAllOutgoingTime()) {
        if (field.isNullHour())
          break;
        outgoing_num++;
        if (outgoing_num < from_num) {
          continue;
        }
        if (outgoing_num == from_num) {
          if (field.getValue().getTime() < from_date.getTime()) {
            outgoing_time -= from_date.getTime();
            continue;
          }
        }
        outgoing_time -= field.getValue().getTime();
        if (outgoing_num == to_num) {
          break;
        }
      }
      if (comeback_num == outgoing_num) {
        return (float) outgoing_time / (1000 * 60 * 60);
      } else {
        /** 外出／復帰が対応しないため計算できない */
        return NO_DATA;
      }
    }
    return 0.0f;
  }

  public void setBeforeAfter() {
    try {
      
      if (timecard_system==null){
        //勤務形態が未設定の場合は、ゼロ
        beforeafter = 0;
        return;
      }
      int change_time = timecard_system.getChangeHour().intValue();
      Date today = new Date();
      long time = today.getTime() - Long.valueOf(Integer.toString(change_time * 60 * 60 * 1000));
      today.setTime(time);

      Date now = date.getValue().getDate();

      if (ExtTimecardUtils.sameDay(now, today)) {
        beforeafter = 0;
        return;
      }
      beforeafter = now.compareTo(today);
    } catch (Exception e) {
      beforeafter = 0;
      logger.error("error", e);
    }
  }

  
  public int getBeforeAfter() {
    return beforeafter;
  }

  /********
   * 以下、算出退勤時刻を考慮した計算に必要なコード
   */

  /**
   * 算出退勤時刻を文字で返します
   *
   * @return
   */
  public String getComputedClockOutTime() {
    if (rd == null)
      return "";
    if (rd.getIsNullClockOutTime())
      return "";
    return String.format("%1$Tk時", rd.getComputedClockOutTime())
          + rd.getComputedClockOutTime().getTime().getMinutes() + "分";
  }
  /**
   * 算出退勤時刻をシンプルな文字で返します
   *
   * @return
   */
  public String getComputedClockOutTimeSimple() {
    if (rd == null)
      return "";
    if (rd.getIsNullClockOutTime())
      return "";
    return String.format("%1$Tk:%1$TM", rd.getComputedClockOutTime());
  }
  
  /**
   * 算出退勤時刻が退勤時刻よりも大きいかどうか
   *
   * @return
   */
  public boolean getIsErrorComputedClockOutTime() {
    if (rd == null || rd.getComputedClockOutTime() == null) return false;
    if (rd.getClockOutTime() == null
        || ! rd.getClockOutTime().isNotNullValue()
       ) return true;
    
    return rd.getComputedClockOutTime().getTime().after(rd.getClockOutTime().getValue());
  }
  
  
  private int computedTotal = 0;
  /**
   * 計算後のトータル作業時間
   * 時間単位は時です。
   */
  public String getComputedTotal(){
    if(computedTotal == 0) return "";
    return String.format("%2.2f", (double)computedTotal / 60f);
  }
  
  
  private int computedSagyo = 0;
  /**
   * 計算後の作業時間
   * 時間単位は時です。
   */
  public String getComputedSagyo(){
    if(computedSagyo == 0) return "";
    return String.format("%2.2f", (double)computedSagyo / 60f);
  }
  

  private int computedOvertime = 0;
  /**
   * 計算後の残業時間
   * 時間単位は時です。
   */
  public String getComputedOvertime(){
    if(computedOvertime == 0) return "";
    return String.format("%2.2f", (double)computedOvertime / 60f);
  }
  

  private int computedNightOvertime = 0;
  /**
   * 計算後の深夜残業時間
   * 時間単位は時です。
   */
  public String getComputedNightOvertime(){
    if(computedNightOvertime == 0) return "";
    return String.format("%2.2f", (double)computedNightOvertime / 60f);
  }

  private int computedHolidayOvertime = 0;
  /**
   * 計算後の休日残業時間
   * 時間単位は時です。
   */
  public String getComputedHolidayOvertime(){
    if(computedHolidayOvertime == 0) return "";
    return String.format("%2.2f", (double)computedHolidayOvertime / 60f);
  }
  

  private int computedHolidayNightOvertime = 0;
  /**
   * 計算後の休日深夜残業時間
   * 時間単位は時です。
   */
  public String getComputedHolidayNightOvertime(){
    if(computedHolidayNightOvertime == 0) return "";
    return String.format("%2.2f", (double)computedHolidayNightOvertime / 60f);
  }
  
  private int computedExtralegalOvertime = 0;
  /**
   * 計算後の法定外休日残業時間
   * 時間単位は時です。
   */
  public String getComputedExtralegalOvertime(){
    if(computedExtralegalOvertime == 0) return "";
    return String.format("%2.2f", (double)computedExtralegalOvertime / 60f);
  }
  

  private int computedExtralegalNightOvertime = 0;
  /**
   * 計算後の法定外休日深夜残業時間
   * 時間単位は時です。
   */
  public String getComputedExtralegalNightOvertime(){
    if(computedExtralegalNightOvertime == 0) return "";
    return String.format("%2.2f", (double)computedExtralegalNightOvertime / 60f);
  }

  private int computedChikoku = 0;
  /**
   * 計算後の遅刻早退時間
   * 時間単位は時です。
   * 
   * 代休時間がある場合は優先的にこの遅刻早退を相殺させる
   * さらに代休時間にあまりがある場合は欠勤時間も相殺させる
   * @author 青柳
   * @return 少数2桁にフォーマットされた文字
   */
  public String getComputedChikoku(){
    if(computedChikoku == 0) return "";
    if(rd != null){
      float fc = (computedChikoku - rd.getOffTimeMinutes()) / 60f;
      if(fc<0) return "";
      return String.format("%2.2f", fc);
    }
    
    return String.format("%2.2f", computedChikoku / 60f);
  }

  private int computedBreakTime = 0;
  /**
   * 計算後の休憩時間
   * 時間単位は時です。
   */
  public String getComputedBreakTime(){
    if(computedBreakTime == 0) return "";
    return String.format("%2.2f", (double)computedBreakTime / 60f);
  }

  private int computedAbsenceTime = 0;
  /**
   * 計算後の欠勤時間
   * 時間単位は時です。
   * 
   * 代休時間がある場合、遅刻早退時間を差し引いた残りがあれば、この
   * 欠勤時間からも相殺する
   * @author 青柳
   * @return 少数2桁にフォーマットされた文字
   */
  public String getComputedAbsenceTime(){
    if(computedAbsenceTime == 0) return "";
    if(rd != null){
      int ic = rd.getOffTimeMinutes() - computedChikoku;
      if(ic < 0) ic = 0;
      float fc = (float)((computedAbsenceTime - ic) / 60f);
      if(fc < 0) return "";
      return String.format("%2.2f", fc);
    }
    return String.format("%2.2f", (double)computedAbsenceTime / 60f);
  }  
  
  public String getUseCarFlg(){
    if(rd != null){
      return rd.getCarCommutingClass();
    }else return null;
  }
  
  /**
   * カレント行の勤務形態タイムテーブルから残業時間の算出に
   * 必要な詳細時間データを取得します。
   * 
   * @author 青柳
   * @return
   */
  public List<TimeDetailRow> getCurrentTimeDetails(){
    if(timecard_system == null) return null;
    
    int workInTime = 0;
    int workOutTime = 0;
    int paidVacType = 0;
    
    try
    {
    
      //出勤時間→分換算
      ALDateTimeField tmp = rd.getClockInTime();
      if(tmp == null || !tmp.isNotNullValue()) return null;
      workInTime = tmp.getValue().getHours() * 60
                     + tmp.getValue().getMinutes();       //9 * 60 + 0;
      
      //退勤時間→分換算
      Calendar c = rd.getComputedClockOutTime();
      if(c != null)
        workOutTime = c.getTime().getHours() * 60
                      + c.getTime().getMinutes();     //17 * 60 + 30;
    

      //有給 [全休・半休]
      String flg = rd.getPaidHolidayType();
      if(flg != null)
        paidVacType = Integer.parseInt(flg);
      if(getIsSaturdayOrSundayOrHoliday() != 0)
        paidVacType = 1;
      
    }catch(Exception exp){
      logger.error("Exception", exp);
      return null;
    }
    
    List<TimeDetailRow> rows = this.getTimeDetails(timecard_system.getSystemId(), workInTime, workOutTime, paidVacType);
 
    return rows;
  }
  
  /**
   * 区分毎の作業時間を算出するSQL文を返します。
   * 
   * @author 青柳
   * @param systemId    勤務形態ID
   * @param workInTime  出勤時刻（分）
   * @param wordOutTime 退勤時刻（分）
   * @param paidVacType 有給休暇タイプ
   * @return SQL文
   */
  public static String getFixedTimeTableQuery(int systemId, int workInTime, int wordOutTime, int paidVacType){
    if(workInTime > wordOutTime) wordOutTime += 24 * 60;
    
    String sql = "" +
    		"SELECT    区分 AS 作業時間区分, \n" +
    		"    CASE \n" +
    		"      WHEN @YK = 1 THEN 0 \n" +
    		"      ELSE COALESCE( \n" +
    		"       SUM(モスト) - SUM(COALESCE(作業補正, 0)) \n" +
    		"              , 0) END AS 遅刻早退時間, \n" +
    		"    SUM(COALESCE(作業補正, 0)) AS 作業時間  \n" +
    		"FROM ( \n" +
    		" SELECT    開始, 作業, 始業フラグ AS 始業, \n" +
    		"  CASE  \n" +
    		"    WHEN @ST > 開始 THEN @ST \n" +
    		"    ELSE 開始 END AS 開始補正, \n" +
    		"  CASE  \n" +
    		"    WHEN @ST > 開始 AND @ED < 開始 + 作業 THEN @ED - @ST \n" +
    		"    WHEN @ST > 開始 AND @ED >=  開始 + 作業 THEN 開始 + 作業 - @ST \n" +
    		"    WHEN @ED < 開始 + 作業 THEN @ED - 開始 \n" +
    		"    ELSE  作業 END AS 作業補正, COALESCE(補正.区分, ロス.区分) AS 区分, ロス.モスト  \n" +
    		" FROM ( \n" +
    		BusinessSystemUtils.getTimeTableQuery(systemId, workInTime, wordOutTime, paidVacType) +
    		" \n ) AS 補正 \n" +
    		"       FULL OUTER JOIN ( \n" + // 大幅な遅刻に対応
    		"       SELECT kd.worktime_status AS 区分, SUM(kd.worktime) AS モスト FROM imw_t_ext_timecard_system_detail AS kd \n" +
    		"       WHERE kd.system_id = @KID AND ( \n" +
    		"              (kd.worktime_status = '0' AND @YK IN (0, 3, 4)) \n" +
    		"               OR " +
    		"              (kd.worktime_status = '1' AND @YK IN (0, 2, 4)) \n" +
    		"                                  ) GROUP BY kd.worktime_status \n" +
    		"        ) AS ロス ON 補正.区分 = ロス.区分  \n" +
    		" ) AS 集計 GROUP BY 始業, 区分 ORDER BY 区分 ASC; \n";

    sql = sql.replaceAll("@KID", String.valueOf(systemId));
    sql = sql.replaceAll("@ST", String.valueOf(workInTime));
    sql = sql.replaceAll("@ED", String.valueOf(wordOutTime));
    sql = sql.replaceAll("@YK", String.valueOf(paidVacType));// 1:全休　2:半休（午前）　3：半休（午後）　4:代休休暇　5:振替休暇　6:特別休暇　7:生理休暇  
    
    return sql;
  }
  
  /**
   * 区分毎の作業時間を一覧で返します。
   * 
   * @author 青柳
   * @param systemId    勤務形態ID
   * @param workInTime  出勤時刻（分）
   * @param wordOutTime 退勤時刻（分）
   * @param paidVacType 有給休暇タイプ
   * 
   * @return List   結果テーブル
   */
  public List<TimeDetailRow> getTimeDetails(int systemId, int workInTime, int wordOutTime, int paidVacType){
    try{
      DataContext dc = DatabaseOrmService.getInstance().getDataContext();
      String sql = getFixedTimeTableQuery(systemId, workInTime, wordOutTime, paidVacType);
     
      SQLTemplate q = new SQLTemplate(ImwTExtTimecardSystemDetail.class, sql, true);
   
      List<DataRow> res;
      List<TimeDetailRow> rows;
      
      q.setFetchingDataRows(true);
      res = dc.performQuery(q);
      rows = new ArrayList<TimeDetailRow>();
      
      // 結果をオブジェクトに入れて返す。
      for(Iterator<DataRow> i = res.iterator();i.hasNext();){
        DataRow drow = i.next();
        TimeDetailRow row = new TimeDetailRow();
        
        row.TimeKind = Integer.parseInt(drow.get("作業時間区分").toString());
        row.TimeSpan =  Integer.parseInt(drow.get("作業時間").toString());
        row.LatedTime =  Integer.parseInt(drow.get("遅刻早退時間").toString());
        
        rows.add(row);
      }

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

  }
  
  /**
   * カレント行の時間を、作業時間、残業時間、深夜残業時間、に振り分け
   * プロパティからアクセスできるように準備します。
   * 
   * 時間単位は分です。
   * 
   * @author  青柳
   */
  public void CalcTimes(){
    if(! getIsResultData()) return;
    
    computedTotal = 0;
    computedChikoku = 0;
    computedSagyo = 0;
    computedNightOvertime = 0;
    computedOvertime = 0;
    computedHolidayNightOvertime = 0;
    computedHolidayOvertime = 0;
    computedExtralegalNightOvertime = 0;
    computedExtralegalOvertime = 0;  
    computedAbsenceTime = 0;
    
    int tempSumWorkTime = 0;//日中の時間のみを後で実作業時間と比較するための変数
    
    List<TimeDetailRow> rows = this.getCurrentTimeDetails();
    if(rows == null) return;

    //欠勤時間の算出のため実作業データを取得
    int workTrueTime = getWorkTrueMinutes();
    int holKind = getIsSaturdayOrSundayOrHoliday();
    
    for(Iterator<TimeDetailRow> i = rows.iterator();i.hasNext();){
      TimeDetailRow row = i.next();
      computedTotal += row.TimeSpan;
      computedChikoku += row.LatedTime;
      switch(holKind){
      case 0://平日
        switch(row.TimeKind){
        case 0://午前
        case 1://午後
          computedSagyo += row.TimeSpan;
          tempSumWorkTime += row.TimeSpan;
          break;
          
        case 3://深夜
          computedNightOvertime += row.TimeSpan;
          break;
          
        default://夜間　早朝
          computedOvertime += row.TimeSpan;
        }
        break;
      case 1://土曜
      /** Add 20110527 小濵 休日が法定休日になってしまう不具合の修正 Start --- */
      case 3://祝日
      /** Add 20110527 小濵 休日が法定休日になってしまう不具合の修正 End   --- */
        switch(row.TimeKind){
        case 0://午前
        case 1://午後
          tempSumWorkTime += row.TimeSpan;
        case 2://夜間
        case 4://早朝
          computedExtralegalOvertime += row.TimeSpan;
          break;
        default://深夜
          computedExtralegalNightOvertime += row.TimeSpan;
        }
        break;
      default://日曜
        switch(row.TimeKind){
        case 0://午前
        case 1://午後
          tempSumWorkTime += row.TimeSpan;
        case 2://夜間
        case 4://早朝
          computedHolidayOvertime += row.TimeSpan;
          break;
        default://深夜
          computedHolidayNightOvertime += row.TimeSpan;
        }
                
      }
    }

    //実作業時間との差を引く
    if(workTrueTime != -1 && tempSumWorkTime > 0){
    switch(holKind){
      case 0://平日
        computedAbsenceTime = computedSagyo - workTrueTime;
        computedSagyo -= computedAbsenceTime;
        break;
      case 1://土曜
      /** Add 20110527 小濵 休日が法定休日になってしまう不具合の修正 Start --- */
      case 3://祝日
      /** Add 20110527 小濵 休日が法定休日になってしまう不具合の修正 End   --- */
        computedExtralegalOvertime -= tempSumWorkTime - workTrueTime;
        break;
      default://日曜
        computedHolidayOvertime -= tempSumWorkTime - workTrueTime;
      }
    }
    
  //休憩時間を作業時間から逆算します。
    int workInTime = 0;
    int workOutTime = 0;
    computedBreakTime = 0;
    
    try {
    
    ALDateTimeField tmp = rd.getClockInTime();
    if(tmp != null && tmp.isNotNullValue())
      workInTime = tmp.getValue().getHours() * 60
                   + tmp.getValue().getMinutes();       //9 * 60 + 0;
    
    Calendar c = rd.getComputedClockOutTime();
    if(c != null)
      workOutTime = c.getTime().getHours() * 60
                    + c.getTime().getMinutes();     //17 * 60 + 30;
    
    }catch(Exception exp){
      return;
    }
    
    if(workOutTime < workInTime)workOutTime += 60 * 24;
    /** Update 2010/10/14 金廣 Start--- */
    // 課題51:午後休の日に残業を行った場合、在席管理で退勤ボタンを押すと12時になる。休憩時間に午後休が考慮されない問題の対
    // 午後休の場合に余分にカウントされる休憩時間を補正
    // computedBreakTime = workOutTime - workInTime - computedTotal;
    // 休憩時間補正
    Integer computedBreakTimeRev = 0;
    //　有給 [全休・半休]
    int paidVacType = 0;
    String flg = rd.getPaidHolidayType();
    if(flg != null)
      paidVacType = Integer.parseInt(flg);
    if(getIsSaturdayOrSundayOrHoliday() != 0)
      paidVacType = 1;
    // 休憩時間補正を算出
    computedBreakTimeRev = BusinessSystemUtils.getBreakTimeRevision(timecard_system.getSystemId(), workInTime, workOutTime, paidVacType);
    if (computedBreakTimeRev == null) return;
    // 休憩時間を算出
    computedBreakTime = workOutTime - workInTime - computedTotal - computedBreakTimeRev;
    /** Update 2010/10/14 金廣 End----- */
   }

  /**
   * 作業入力の一覧から作業時間集計データを作成します。
   * 
   * @author 青柳
   * 
   */
  public void setWorkDetail() {
    String job_name = "";
    
    if (rd != null){
      DataContext dc = DatabaseOrmService.getInstance()
      .getDataContext();

      /** Update 2010/10/04 金廣 Start--- */
      // 課題55 月報の作業内容記入欄の件名を5件→1件に修正
      // 課題56 作業時間が空欄の場合、月報が正常に表示されない問題の対応
//      String sql = "SELECT " +
//      		" jo.job_order_id, jo.job_order_name," +
//      		" SUM(td.worktime_in + td.worktime_out) AS WTIME" +
//      		" FROM IMW_T_EXT_TIMECARD_DETAIL td" +
//      		" INNER JOIN IMW_T_JOB_ORDER jo ON td.job_order_id = jo.job_order_id" +
//      		" WHERE TIMECARD_ID = '" + rd.getTimecardId().getValue() + "'" +
//      		" GROUP BY jo.job_order_id, jo.job_order_name" +
//      		" ORDER BY WTIME DESC LIMIT 5 OFFSET 0";

      String sql = "SELECT " +
      " jo.job_order_id, jo.job_order_name," +
      " SUM(coalesce(td.worktime_in,0) + coalesce(td.worktime_out,0)) AS WTIME" +
      " FROM IMW_T_EXT_TIMECARD_DETAIL td" +
      " INNER JOIN IMW_T_JOB_ORDER jo ON td.job_order_id = jo.job_order_id" +
      " WHERE TIMECARD_ID = '" + rd.getTimecardId().getValue() + "'" +
      " GROUP BY jo.job_order_id, jo.job_order_name" +
      " ORDER BY WTIME DESC LIMIT 1 OFFSET 0";
      
      /** Update 2010/10/04 金廣 End----- */
      
      SQLTemplate q = new SQLTemplate(ImwTExtTimecardDetail.class, sql, true);
      q.setFetchingDataRows(true);
      List<DataRow> res = dc.performQuery(q);
      
      if(res.size()>0)
        for(Iterator<DataRow> itr = res.iterator();itr.hasNext();){
          DataRow row = itr.next();
          if(job_name==""){
            job_name += row.get("job_order_name").toString();
          }else{
            job_name += " / " + row.get("job_order_name").toString();
          }
        }
    }

    jobName = job_name;
  }
  private String jobName;
  public String getJobName(){
    return jobName;
  }

  
  /**
   * 作業入力の一覧から作業時間合計分を取得します
   * 
   * @author 青柳
   * 
   * @return 作業時間（分）
   */
  private int getWorkTrueMinutes() {
    try {

      if (rd != null){
        DataContext dc = DatabaseOrmService.getInstance()
        .getDataContext();
        String sql = "SELECT SUM(WORKTIME_IN) AS 合計" +
              "  FROM IMW_T_EXT_TIMECARD_DETAIL" +
              "  WHERE TIMECARD_ID = '" + rd.getTimecardId().getValue() + "'";
  
        SQLTemplate q = new SQLTemplate(ImwTExtTimecardDetail.class, sql, true);
        q.setFetchingDataRows(true);
        List<DataRow> res = dc.performQuery(q);

        if(res.size() > 0){
          return Integer.parseInt(res.get(0).get("合計").toString());
        }else{
          //　作業入力されていない
          return -1;
        }
       }else{
         //対象の行にタイムカードデータが無い
         return -1;
       }

      
    } catch (NullPointerException ex) {
      return -1;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return -1;
    }
  }
  
  /**
   * 作業区分毎の作業時間をリスト形式で保持する為の
   * 一行分のデータを格納します。
   * 
   * 時間単位は分です。
   * 
   * @author  青柳
   */
  public class TimeDetailRow{
    /**
     * 遅刻早退時間
     */
    public int LatedTime;
    
    /**
     * 作業時間
     */
    public int TimeSpan;
    
    /**
     * 作業時間区分
     */
    public int TimeKind;
  }

  /**
   * オフィスカレンダー情報
   */
  private OfficeCalData officeCalData;
  /**
   * オフィスID
   */
  private Integer officeId;
  /**
   * オフィス
   */
  private ImwTOffice office;
  
  /**
   * オフィスIDを設定し、オフィスデータを同時に設定します。
   * 
   * @param value
   */
  public void setOfficeId(Integer value){
     officeId = value;
     //office = getOfficeById(officeId);
  }
  
  /**
   * オフィスIDを取得します。
   * 
   * @return
   */
  public Integer getOfficeId(){
    return officeId;
  }

  /**
   * オフィスを設定します。
   * 
   * @return
   * 
  public void setOffice(ImwTOffice value){
    office = value;
  }*/
  
  /**
   * オフィスを取得します。
   * 
   * @return
   * 
  public ImwTOffice getOffice(){
    return office;
  }*/


  /**
   * オフィスを設定します。
   * 
   * @return
   */
  public void setOfficeCalData(OfficeCalData value){
    officeCalData = value;
  }
  
  /**
   * オフィスを取得します。
   * 
   * @return
   */
  public OfficeCalData getOfficeCalData(){
    return officeCalData;
  }

  /**
   * オフィス名を取得します。
   */  
  public String getOfficeName(){
    if(getOfficeCalData() == null) return "";
    return getOfficeCalData().OfficeName;
  }
  
  /**
   * オフィスIDからオフィスデータを取得します。
   * 
   * @author 青柳
   * 
   * @param OfficeId
   * @return
   */
  public static ImwTOffice getOfficeById(Integer OfficeId) {
    if(OfficeId == null) return null;
    try{
      
      DataContext dc = DatabaseOrmService.getInstance().getDataContext();
      SelectQuery q = new SelectQuery(ImwTOffice.class);
      
      // オフィスIDの一致
      Expression expr_1 = ExpressionFactory.matchDbExp(ImwTOffice.OFFICE_ID_PK_COLUMN, OfficeId);
      
      //無効フラグがF（無効ではない）物
      Expression expr_2 = ExpressionFactory.matchExp(ImwTOffice.DISABLED_PROPERTY, "F");
  
      q.setQualifier(expr_1);
      q.andQualifier(expr_2);
      
      List<ImwTOffice> results = dc.performQuery(q);
      
      if(results.isEmpty()) return null;
      return results.get(0);

    }catch(Exception ex){
      logger.error("Exception", ex);
      return null;
    }
  }
  
  /**
   * ユーザーIDと日付からカレンダー情報を取得します。
   * 
   * @author 青柳
   * 
   * @param userId
   * @return
   */
  public static OfficeCalData getOfficeCalDataRow(int userId, Date now) {
    DataContext dc = DatabaseOrmService.getInstance().getDataContext();
    String sql = "SELECT ocm.office_id" +
    		" FROM turbine_user tu " +
    		" INNER JOIN imw_t_office_calendar_map ocm ON tu.user_id = ocm.user_id " +
    		" WHERE (NOT ocm.office_id IS NULL) AND tu.user_id = " + userId;

    SQLTemplate q = new SQLTemplate(ImwTOfficeCalendar.class, sql, true);
    q.setFetchingDataRows(true);
    List<DataRow> res = dc.performQuery(q);
    int OfficeId;
    
    if(res.isEmpty())return null;
    OfficeId = Integer.valueOf(res.get(0).get("office_id").toString());
    
    return getOfficeCalDataRowByOfficeId(OfficeId, now);
  }
  
  /**
   * オフィスの名前と休日指定を管理します。
   * 
   * @author 青柳
   *
   */
  public static class OfficeCalData{
    public String OfficeName = "";
    /**
     * オフィス指定休日 　0：平日　/　1：休日
     */
    public String OnOffClass = "";
  }
  
  /**
   * オフィスIDと日付から休日情報を取得します。
   * 
   * @author 青柳
   * 
   * @param OfficeId
   * @param now
   * @return
   */
  public static OfficeCalData getOfficeCalDataRowByOfficeId(int OfficeId, Date now) {
    DataContext dc = DatabaseOrmService.getInstance().getDataContext();

    String sql = "SELECT o.office_name" +
          " FROM imw_t_office o " +
          " WHERE o.disabled = 'F' AND o.office_id = " + OfficeId;

    SQLTemplate q = new SQLTemplate(ImwTOfficeCalendar.class, sql, true);
    q.setFetchingDataRows(true);
    List<DataRow> res = dc.performQuery(q);
    OfficeCalData result = new OfficeCalData();

    if(res.isEmpty())return result;
    result.OfficeName = res.get(0).get("office_name").toString();
    
    
    sql = "SELECT oc.on_off_class" +
          " FROM imw_t_office o " +
          " LEFT OUTER JOIN imw_t_office_calendar oc ON o.office_id = oc.office_id AND oc.disabled = 'F' AND o.disabled = 'F'" +
          " WHERE o.office_id = " + OfficeId + " AND oc.calendar_date = '" + String.format("%1$tY-%1$tm-%1$td", now) + "'";
    
    q = new SQLTemplate(ImwTOfficeCalendar.class, sql, true);
    q.setFetchingDataRows(true);
    res = dc.performQuery(q);
    
    if(res.isEmpty())return result;
    result.OnOffClass = res.get(0).get("on_off_class").toString();
    
    return result;
  }
    
  /**
   * オフィスカレンダーに基づく休日状態を取得します。
   *
   * @return int 0 ... 平日 1 ... 土曜日 2 ... 日曜日 3 ... 休日
   */
  public int getIsSaturdayOrSundayOrHoliday() { 
    int defHolClass = getIsSaturdayOrSundayOrHolidayDefault();
    OfficeCalData oc = getOfficeCalData();
    if(oc==null)return defHolClass;
    
    if(defHolClass == 0){
      //平日に
      if(oc.OnOffClass.equals("1"))//休みがあれば
        return 1;//土曜扱い（法定外休日）
    }else{
      //その他の場合に
      if(oc.OnOffClass.equals("0"))//平日
        return 0;//平日扱い
    }
    
    return defHolClass; //上記以外はデフォルトと同じ
  }
  
}
