/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.taglib;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.resource.CalendarData;
import org.opengion.hayabusa.resource.CalendarFactory;
import org.opengion.hayabusa.html.ViewStackTableParam;
import org.opengion.fukurou.util.StringUtil;
import static org.opengion.fukurou.util.StringUtil.nval ;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Locale ;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * ガントチャート用のヘッダー情報(日付け等)を出力するタグです。
 *
 * スライドバー式ガントチャートの表示時に、スライドバーの長さと日付とを関連付けるための
 * ヘッダー情報(日付け等)を出力します。スライドバーと日付間隔は、zoom 属性によって、
 * CSSファイルのフォントサイズと、JavaScript の内部配列に依存しています。
 * また、このヘッダーでは、日付の休日情報を、カレンダテーブルを参照することで取得しています。
 * calDB 属性への指定は、CalendarFactory で生成されるテーブル名(CalendarDataの実装クラス)
 * を指定します。
 *
 * @og.formSample
 * ●形式：&lt;og:ganttHeader startDate="…" endDate="…" zoom="[…]" /&gt;
 * ●body：なし
 *
 * ●Tag定義：
 *   &lt;og:ganttHeader
 *       startDate          【TAG】表示開始日付けを設定します(yyyyMMdd または、yyyyMMddHHmm 形式)
 *       endDate            【TAG】表示最終日を設定します(yyyyMMdd または、yyyyMMddHHmm 形式)
 *       zoom               【TAG】ズーム変数(0～13,20～31,40～49)を設定します(初期値:2)
 *       calDB              【TAG】DB検索するＤＢを指定します
 *       arg1               【TAG】ＤＢ検索する場合の第１のキーを指定します
 *       arg2               【TAG】ＤＢ検索する場合の第２のキーを指定します
 *       arg3               【TAG】ＤＢ検索する場合の第３のキーを指定します
 *       arg4               【TAG】ＤＢ検索する場合の第４のキーを指定します
 *       daySpan            【TAG】１日の開始終了時間を24時間形式(HHmm-HHmm)で設定します(初期値:0700-2000)
 *       breakTimes         【TAG】時間軸での休憩時間の開始-終了時刻をカンマ区切りで複数指定します(HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm形式、または、yyyyMMddHHmm-yyyyMMddHHmm形式)
 *       breakTimeStyle     【TAG】時間軸での休憩時間の表示スタイルを設定します(初期値:top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;)
 *       baseTimes          【TAG】時間軸でのベース時刻の開始時刻をカンマ区切りで複数指定します(HHmm形式、または、yyyyMMddHHmm形式)
 *       baseTimeStyle      【TAG】時間軸でのベース時刻の表示スタイルを設定します(初期値:top:20px;background-color:transparent;border-left:2px dashed red;)
 *       skipHoliday        【TAG】時間ガントで休日を表示する/しないを設定します (初期値:USE_GANTTHEADER_SKIP_HOLIDAY[=true])
 *       useMultiClm        【TAG】時間ヘッダーの上段に日付を、下段の時間を表示します (初期値:USE_GANTTHEADER_MULTIPLE_COLUMN[=false])
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   /&gt;
 *
 * ●使用例
 *    参照：jsp/GANTT06 フォルダ
 *
 *     &lt;og:ganttHeader
 *         startDate = "{&#064;VIEW_DATE}"
 *         endDate   = "{&#064;DYMAX}"
 *         zoom      = "{&#064;VIEW_ZOOM}"
 *         calDB     = "GF13"
 *         arg1      = "{&#064;CDJGS}"
 *         arg2      = ""
 *     /og:ganttHeader&gt;
 *
 *     &lt;og:ganttHeader
 *         startDate  = "{&#064;VIEW_DATE}"
 *         endDate    = "{&#064;DYMAX}"
 *         daySpan    = "0700-2000"                               HHmm-HHmm 形式で１日の時間範囲を指定
 *         breakTimes = "1200-1245,1645-1650,200508200700-1200;"  休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm形式、または、yyyyMMddHHmm-yyyyMMddHHmm形式です。
 *         breakTimeStyle = "top:20px;background-color:yellow;"   休憩時間のスタイルに追加します。
 *         zoom       = "20"
 *     /og:ganttHeader&gt;
 *
 * ●定義・解説
 *   PL/SQL の VIEW_ZOOM メソッドを用いて、実際の日付けから画面表示ピクセルへ
 *   変換する割合を求めます。これと、jsp\GANTT\image の ganttBGx.gif(x は ZOOM変数)
 *   を対応付けて、日付けのヘッダーを求めます。
 *   jsp\custom\custom.css の th.zoomx(x は ZOOM変数) により、日付けヘッダー文字の
 *   表示間隔を制御していますので、これらの関係を正確に把握しておいて下さい。
 *   日付けヘッダーは、イメージ変数を用いている関係上、固定の日数を加算して、
 *   求めます。(週:7日, 半月:15日, 月:30日, 4半期:90日, 年:360日)
 *
 * ヘッダー部のカレンダに、calDB で指定された カレンダテーブルを使用出来ます。
 * 使用する場合は、arg1(事業所ｺｰﾄﾞ等)～arg4(WCｺｰﾄﾞ等) の属性を指定する事ができます。
 * zoom="10"(週単位) を使用の週数の計算は、年初の最初の７日間が含まれる週を、第１週と数えます。
 *
 * zoom="20"(時)間 では、１日の時間範囲をdaySpanでHHmm-HHmm形式で指定します。
 * 開始時刻は、内部で１時間単位に変換されます。８時３０分～は、８時～になります。
 * 終了時間は、その時間を「含みません」
 * 開始終了は、startDate、endDateで指定しますが、yyyyMMdd または、yyyyMMddHHmm 形式とします。
 * calDB で指定された カレンダテーブルを見て、休日の場合は、表示をスキップします。
 * 休憩時間は、breakTimes で指定します。(HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、
 * または、yyyyMMddHHmm-yyyyMMddHHmm形式)
 * カンマ区切りで複数指定できます。日付指定がない場合は、毎日、日付指定がある場合は、
 * その日のみ有効です。休憩時間は、日をまたぐ事は可能です。
 * breakTimeStyle として、休憩時間の指定に追加するスタイル属性を追加します。
 * 通常は、バックカラーと上からの位置です。ヘッダー表示は、１時間単位です。
 * 初期値は、"top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" です。
 *
 * ベース時刻(baseTimes)は、HHmm形式、または、yyyyMMddHHmm形式で指定した箇所に、線を引きます。
 * 例えば、検索した時刻を指定すると、現在時刻の箇所を示す線になります。
 * また、業務自体の開始時刻や終了時刻の箇所を表すことも可能です。
 * baseTimeStyle は、このベース時刻のスタイルを決めます。breakTimeStyle との違いは、
 * 帯の幅を、このスタイルシートで指定していることです。
 * 初期値は、top:20px;background-color:transparent;border-left:2px dashed red; です。
 *
 * zoom="21"(時)間 では、一時間のピクセルを"20"(時)の半分に変更します。
 *
 * useMultiClm  パラメータを設定すると、ガントヘッダーにおいて、２段組を使用するかどうかを、
 * 指定できます。時間ヘッダーの上段に日付を、下段の時間軸の(h)の削除を行います。
 * 日付は、表示開始時刻の上と、それの６時間ごとに表示します。
 * 初期値は、システムリソースの USE_GANTTHEADER_MULTIPLE_COLUMN で指定します。
 *
 * システムリソースに USE_GANTTHEADER_MONTH_DATE パラメータを設定すると、
 * ガントヘッダーにおいて、30日、90日、180日のヘッダー表示で、日付まで
 * 表示するか、月のみ表示するかを指定します。
 * ガントヘッダーの繰返し表示でバックグラウンドイメージは固定日なので、一月表示を
 * 30日単位で表示していますが、先頭日付が 1日でないため、判りにくいと苦情がありました。
 * そこで、30日、90日、180日のヘッダー表示時に、日付を表示しないようにするフラグです。
 * 月表示は、その月が 20日以降の場合、翌月を表示します。
 * 初期値は、互換性の為、false です。
 *
 * zoom 40(DAY),41(WEEK),42(MONTH) は、積み上げガント用のヘッダー処理を行います。
 * 積み上げガントは、固定日処理ではなく、月単位に加算します。
 *
 * @og.rev 3.5.4.8 (2004/02/23) 新規作成
 * @og.group 画面部品
 *
 * @version  4.0
 * @author	Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class GanttHeaderTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "5.7.6.2 (2014/05/16)" ;

	private static final long serialVersionUID = 576220140516L ;

	// 5.6.2.3 (2013/03/22) 日付をセンターに表示させる場合の両端スペースの元ネタ
	private static final String SPACE = "                                   " ;		// 日付(31日分)より多いスペース

	// 5.6.5.0 (2013/06/07) 曜日データを配列で持っておきます。
	private static final String[] DAY_OF_WEEK_ja = new String[] { " ","日 ","月 ","火 ","水 ","木 ","金 ","土 " };
	private static final String[] DAY_OF_WEEK_en = new String[] { " ","Su" ,"Mo" ,"Tu" ,"We" ,"Th" ,"Fr" ,"Sa"  };

	private String	startDate	= null;
	private String	endDate		= null;
	private String	daySpan		= "0700-2000";	// １日の時間範囲(HHmm-HHmm) 3.8.0.5 (2005/08/26)
	private int		zoom		= 2;
	private String	breakTimes	= null;		// 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-HHmmyyyyMMdd形式です。
	private String	breakTimeStyle	= "top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" ;	// 5.6.4.3 (2013/05/24) 初期値変更
	private String	calDB	= null;	// 3.6.0.0 (2004/09/17) DB検索するＤＢのキー
	private String	arg1	= null;	// 3.6.0.0 (2004/09/17) DB検索の第１キー(事業所コードなど)
	private String	arg2	= null;	// 3.6.0.0 (2004/09/17) DB検索の第２キー(ＷＣコードなど)
	private String	arg3	= null;	// 3.6.0.0 (2004/09/17) DB検索の第３キー(事業所コードなど)
	private String	arg4	= null;	// 3.6.0.0 (2004/09/17) DB検索の第４キー(ＷＣコードなど)
	private boolean skipHoliday	= HybsSystem.sysBool( "USE_GANTTHEADER_SKIP_HOLIDAY" );		// 4.0.0.0 (2007/09/07) 休日をスキップするかどうか
	private String 	calStr	= null; // 5.5.4.0 (2012/07/02) 出勤日・休日のフラグ

	private static final int	 TIME_PIXEL		= 48;	// 3.8.1.1 (2005/11/21) 時間ヘッダー時の１時間のピクセル数
//	private static final boolean USE_MULTI_CLM	= HybsSystem.sysBool( "USE_GANTTHEADER_MULTIPLE_COLUMN" );	// 3.8.1.4 (2006/03/13)
	private boolean useMultiClm	= HybsSystem.sysBool( "USE_GANTTHEADER_MULTIPLE_COLUMN" );	// 5.6.1.2 (2013/02/22)

	private static final boolean USE_MONTH_DATE	= HybsSystem.sysBool( "USE_GANTTHEADER_MONTH_DATE" );	// 3.8.5.2 (2006/06/09)
	private static final int	 MONTH_DATE_LIMITER = 20;	// 当月 20 日以降は、翌月扱いとなる。

	private static final String BLUE_COLOR	= "<span style=\"color:Blue;\">" ;		// 5.6.2.3 (2013/03/22) 廃止
	private static final String RED_COLOR	= "<span style=\"color:Red;\">" ;		// 5.6.2.3 (2013/03/22) 廃止
	private static final String TODAY_CLASS		= "gntToday" ;						// 5.6.2.3 (2013/03/22) 当日を示すクラス名
	private static final String HOLIDAY_CLASS	= "gntHoliday" ;					// 5.6.2.3 (2013/03/22) 休日を示すクラス名
	private static final String END_SPAN	= "</span>" ;
	private static final String BR			= "<br/>" ;
	
	//private static final String ODD_CLASS	= "<span class=\"oddColor\">" ;			// 5.6.2.3 (2013/03/22) 奇数月の色設定
	//private static final String EVEN_CLASS	= "<span class=\"evenColor\">" ;		// 5.6.2.3 (2013/03/22) 偶数月の色設定
	// 5.9.2.0 (2015/11/06) ヘッダー列幅の固定対応
	private static final String DIV_ZOOMWEEK_START	= "<div class=\"zoomWeekBlock\">";					// 週の設定
	private static final String DIV_ZOOMEVENCOLOR = "<div class=\"zoomHeaderDiv evenColor\">";			// 奇数色の設定
	private static final String DIV_ZOOMODDCOLOR = "<div class=\"zoomHeaderDiv oddColor\">";			// 偶数色の設定
	private static final String DIV_ZOOMHEADER2 = "<div class=\"zoomHeaderDiv zoomHeaderDiv2\">";		// 列幅の設定
	private static final String DIV_ZOOMWEEKDAY = "<div class=\"zoomWeekDay\">";						// 日の設定
	private static final String END_DIV		= "</div>";
	
	private String	baseTimes		= null;										// 5.6.1.2 (2013/02/22) ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式です。
	private String	baseTimeStyle	= "top:20px;background-color:transparent;border-left:2px dashed red;" ;		// 5.6.1.2 (2013/02/22) ベース時刻を赤線表示します。
	
	private static final boolean useMdheader	= HybsSystem.sysBool( "USE_MDHEADER_ONTIME" ); // 5.7.0.0 (2013/11/07)

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.6.0.0 (2004/09/17) zoom 3 の時の計算値を変更
	 * @og.rev 3.7.1.0 (2005/04/15) zoom 10 の追加
	 * @og.rev 3.8.1.6 (2006/04/25) zoom 21 の追加
	 * @og.rev 3.8.5.2 (2006/06/09) makeZoom メソッドの USE_MONTH_DATE パラメータ追加
	 * @og.rev 3.8.9.2 (2007/07/28) makeZoomTime メソッドの 時間間隔パラメータ追加
	 * @og.rev 5.5.4.0 (2012/07/02) ヘッダー属性情報の出力追加
	 * @og.rev 5.6.3.2 (2013/04/12) 曜日を出力する場合の段組みでは、全角スペースを使う(firefox対応)
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		if( startDate == null || endDate == null ||
			 startDate.length() < 8 || endDate.length() < 8 ) {
				String errMsg = "開始日と終了日は、どちらも yyyyMMdd 形式で、必須です。"
						+ " startDate=[" + startDate + "] endDate=[" + endDate + "]" ;
				throw new HybsSystemException( errMsg );
		}

		// 月単位の処理に30,60,90などの固定日を使用しているのは、ガントバーの長さが
		// 日単位の固定長なので、長期間のガントを使用すると後ろの方でずれてくるため。
		String header = "";
		String md = (USE_MONTH_DATE) ? "MM   " : "MM/dd";
		switch( zoom ) {
			case  0: header = makeZoom( "MM/   "     ,"dd(EE)"     ,  1 ,false ) ; break;
			case  1: header = makeZoom( "MM/"        ,"dd "        ,  1 ,false ) ; break;
			case  2: header = makeZoom2( 1 ) ; break;
			case  3: header = makeZoom( "yyyy/  "    ,"MM/dd  "    ,  7 ,false ) ; break;
			case  4: header = makeZoom( "yyyy/  "    ,"MM/dd  "    , 14 ,false ) ; break;
			case  5: header = makeZoom( "yyyy/     " ,md + "     " , 30 ,USE_MONTH_DATE ) ; break;
			case  6: header = makeZoom( "yyyy/ "     ,md + " "     , 30 ,USE_MONTH_DATE ) ; break;
			case  7: header = makeZoom( "yyyy/     " ,md + "     " , 90 ,USE_MONTH_DATE ) ; break;
			case  8: header = makeZoom( "yyyy/     " ,md + "     " ,180 ,USE_MONTH_DATE ) ; break;
			case  9: header = makeZoom( "yyyy/ "     ,md + " "     ,180 ,USE_MONTH_DATE ) ; break;
			case 10: header = makeZoom( "ww'W'"      ,"'<span title=\"'MM/dd'\">'dd '</span>'" ,7 ,false ) ; break;
	//		case 11: break;	// 他物件予約済み
	//		case 12: break;	// 他物件予約済み
			case 13: header = makeZoom3( "yyyy/MM" , "dd"  ,"EE"  ,  1 ) ; break;		// 5.6.2.3 (2013/03/22) 月、曜日表示
			case 20: header = makeZoomTime( TIME_PIXEL  ,  1,true  ) ; break;	// 3.8.1.1 (2005/11/21)
			case 21: header = makeZoomTime( TIME_PIXEL/2,  1,false ) ; break;	// 3.8.1.6 (2006/04/25)
			case 22: header = makeZoomTime( TIME_PIXEL  ,  2,true  ) ; break;	// 3.8.9.2 (2007/07/28)
			case 23: header = makeZoomTime( TIME_PIXEL/2,  2,false ) ; break;	// 3.8.9.2 (2007/07/28)
			case 24: header = makeZoomTime( TIME_PIXEL  ,  4,true  ) ; break;	// 3.8.9.2 (2007/07/28)
			case 25: header = makeZoomTime( TIME_PIXEL/2,  4,false ) ; break;	// 3.8.9.2 (2007/07/28)
			case 26: header = makeZoomTime( TIME_PIXEL  ,  6,true  ) ; break;	// 3.8.9.2 (2007/07/28)
			case 27: header = makeZoomTime( TIME_PIXEL/2,  6,false ) ; break;	// 3.8.9.2 (2007/07/28)
			case 28: header = makeZoomTime( TIME_PIXEL  ,  8,true  ) ; break;	// 3.8.9.2 (2007/07/28)
			case 29: header = makeZoomTime( TIME_PIXEL/2,  8,false ) ; break;	// 3.8.9.2 (2007/07/28)
			case 30: header = makeZoomTime( TIME_PIXEL  , 12,true  ) ; break;	// 3.8.9.2 (2007/07/28)
			case 31: header = makeZoomTime( TIME_PIXEL/2, 12,false ) ; break;	// 3.8.9.2 (2007/07/28)
			// 5.6.1.2 (2013/02/22) 積み上げガント
			case 40: header = makeZoomStack( "MM/   "     ,"dd(EE)"     ,  1,false ) ; break;	// 5.6.1.2 (2013/02/22)
			case 41: header = makeZoomStack( "ww'W'   "   ,"MM/dd "     ,  7,false ) ; break;	// 5.6.1.2 (2013/02/22)
			case 42: header = makeZoomStack( "yyyy/     " ,"MM        " ,  1,true  ) ; break;	// 5.6.1.2 (2013/02/22)
	//		case 43: break;		// 日単位ヘッダー予約済み
	//			 ～
	//		case 49: break;		// 日単位ヘッダー予約済み
			default: break;
		}

		jspPrint( header );
		jspPrint(makeHeaderData()); // 5.5.4.0 (2012/07/02)
		return(EVAL_PAGE);
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 *
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) 事業所コード cdjgs 属性を追加
	 * @og.rev 3.8.0.2 (2005/07/11) startTime,timePeriod,breakTimes 属性を追加
	 * @og.rev 3.8.0.5 (2005/08/26) daySpan,breakTimes,breakTimeStyle 属性を追加
	 * @og.rev 5.5.4.0 (2012/07/02) calStr追加
	 * @og.rev 5.6.1.2 (2013/02/22) baseTimes、baseTimeStyle追加,useMultiClm追加
	 */
	@Override
	protected void release2() {
		super.release2();
		startDate	= null;
		endDate		= null;
		daySpan		= "0700-2000";	// 開始時刻(HHmm-HHmm) 3.8.0.5 (2005/08/26)
		zoom		= 2;
		calDB		= null;	// 3.6.0.0 (2004/09/17) DB検索するＤＢのキー
		arg1		= null;	// 3.6.0.0 (2004/09/17) DB検索の第１キー(事業所コードなど)
		arg2		= null;	// 3.6.0.0 (2004/09/17) DB検索の第２キー(ＷＣコードなど)
		arg3		= null;	// 3.6.0.0 (2004/09/17) DB検索の第３キー
		arg4		= null;	// 3.6.0.0 (2004/09/17) DB検索の第４キー
		breakTimes	= null;		// 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-HHmmyyyyMMdd形式です。
		breakTimeStyle	= "top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" ;
		skipHoliday = HybsSystem.sysBool( "USE_GANTTHEADER_SKIP_HOLIDAY" ); // 4.0.0.0 (2007/09/10)
		calStr		= null; // 5.5.4.0 (2012/07/02)
		baseTimes		= null;										// 5.6.1.2 (2013/02/22) ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式です。
		baseTimeStyle	= "top:20px;background-color:transparent;border-left:2px dashed red;" ;		// 5.6.1.2 (2013/02/22) ベース時刻を赤線表示します。
		useMultiClm		= HybsSystem.sysBool( "USE_GANTTHEADER_MULTIPLE_COLUMN" );	// 5.6.1.2 (2013/02/22)
	}

	/**
	 * 上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
	 * @og.rev 3.7.1.0 (2005/04/15) zoom == 10 週単位の場合の特殊処理を追加
	 * @og.rev 3.7.1.1 (2005/05/23) 本日は、青色で示します。
	 * @og.rev 3.8.5.2 (2006/06/09) makeZoom メソッドの USE_MONTH_DATE パラメータ追加
	 * @og.rev 5.5.4.0 (2012/07/02) カレンダーフラグ対応
	 * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
	 * @og.rev 5.6.5.0 (2013/06/07) 上段ヘッダーが MM の場合、週単位で月を表示し、色バーを使用します。
	 * @og.rev 5.7.2.0 (2014/01/10) 上段は、休日を出さないので、END_SPAN 不要
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダー列幅の固定対応
	 *
	 * @param	upper	上段の表示フォーマット
	 * @param	lower	下段の表示フォーマット
	 * @param	add  	表示日付けの加算
	 * @param	useMonth	月日表示でなく、月表示のみにする。(20日以降を翌月表示する。)
	 *
	 * @return  ヘッダー文字列
	 */
	private String makeZoom( final String upper ,final String lower ,final int add, final boolean useMonth ) {
		boolean colBar = upper.startsWith( "MM" );		// 5.6.5.0 (2013/06/07) 色バー使用 true

		DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
		DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );

		Calendar str = HybsSystem.getCalendar( startDate );
		Calendar end = HybsSystem.getCalendar( endDate );

		// zoom == 10 週単位の場合の特殊処理。
		// 年の第一週を完全な一週間分(７日間)として、設定します。
		if( zoom == 10 ) {
			str.setMinimalDaysInFirstWeek( 7 );
			format1.setCalendar( str );
			format2.setCalendar( str );
		}

		StringBuilder buf1   = new StringBuilder( HybsSystem.BUFFER_SMALL );
		StringBuilder buf2   = new StringBuilder( HybsSystem.BUFFER_SMALL );
		StringBuilder bufcal = new StringBuilder( HybsSystem.BUFFER_SMALL ); // 5.5.4.0 (2012/07/02) 休日判定用

		// 5.6.5.0 (2013/06/07) 文字列の作成方法の統一。pre タグを最初に設定しておく。
		//buf1.append( "<pre>" ); // 5.9.2.0 (2015/11/06) DEL

		// 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
		CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );

		boolean modifyFlag = false;
		// 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
//		while( str.before( end ) ) {
		int cnt  = 0;									// 5.6.5.0 (2013/06/07) 色バー対応
		
		
		//if( colBar ) { buf1.append( EVEN_CLASS ); }		// 5.6.5.0 (2013/06/07) 色バー対応
		if( colBar ) {buf1.append( DIV_ZOOMWEEK_START ); } // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応 spanをdivに変更し、1週間をdivで囲む。
		
		boolean isFirst = true;							// 5.6.5.0 (2013/06/07) 色バー対応で、最初だけ、月を表示する。

		while( str.compareTo( end ) <= 0 ) {
			boolean monday = ( Calendar.MONDAY == str.get( Calendar.DAY_OF_WEEK ) );	// 5.6.5.0 (2013/06/07) 色バー対応
			if( colBar && monday ) {
				// 5.6.5.0 (2013/06/07) 色バー対応  5.9.2.0 (2015/11/06) DEL
				//buf1.append( END_SPAN );
				
				// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応 週をdivで囲むため、buf1にbuf2を追加。
				buf1.append( buf2.toString() ).append( END_DIV );
				buf2.setLength( 0 );
					
				cnt++;
				isFirst = true;
				
				buf1.append( DIV_ZOOMWEEK_START ); // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			}

			Date dt = str.getTime();
			// 3.8.5.2 (2006/06/09) useMonth ﾌﾗｸﾞにより 月表示のみに変更します。
			// MONTH_DATE_LIMITER で指定の日以降は、翌月扱いとなる。
			if( useMonth && str.get( Calendar.DATE ) >= MONTH_DATE_LIMITER ) {
				Calendar calPlus = (Calendar)str.clone();
				calPlus.set( Calendar.DATE , 1 );		// １日にセットします。
				calPlus.add( Calendar.MONTH , 1 );		// 月を１ヶ月プラスします。
				dt = calPlus.getTime();
			}

			// 3.7.1.1 (2005/05/31) 本日は、青色で示します。
			if( calData.isContainedToday( str,add ) ) {
//				buf1.append( BLUE_COLOR );
				buf2.append( BLUE_COLOR );
				bufcal.append( "0" ); // 5.5.4.0 (2012/07/02)
				modifyFlag = true;
			}

			// 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
			// modifyFlag が立っていない場合 を条件に追加します。
			if( !modifyFlag && add == 1 && calData.isHoliday( str ) ) {
//				buf1.append( RED_COLOR );
				buf2.append( RED_COLOR );
				bufcal.append( "1" ); // 5.5.4.0 (2012/07/02) 休日
				modifyFlag = true;
			}

			// 5.6.5.0 (2013/06/07) 色バー対応。色バーで、かつ、先頭でなければ、スペースを出力
			if( colBar && !isFirst ) {
				buf1.append( SPACE.substring( 0,upper.length() ) );
			}
			else {
				// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
				if( colBar ){
					if( cnt % 2 == 0)	{ buf1.append( DIV_ZOOMEVENCOLOR ); }	// 奇数の色設定
					else				{ buf1.append( DIV_ZOOMODDCOLOR ); }	// 偶数の色設定
				}else{
					buf1.append( DIV_ZOOMHEADER2 );	// 色無しの設定
				}
				
				buf1.append( format1.format( dt ) );
				
				
				buf1.append( END_DIV ); // 5.9.2.0 (2015/11/06) 
				
				isFirst = false;
			}
			
			buf2.append( DIV_ZOOMHEADER2 ); // 5.9.2.0 (2015/11/06) 
			
			buf2.append( format2.format( dt ) );
			
			buf2.append( END_DIV ); // 5.9.2.0 (2015/11/06) 

			if( modifyFlag ) {
//				buf1.append( END_SPAN );		// 5.7.2.0 (2014/01/10) 上段は、休日を出さないので、END_SPAN 不要
				buf2.append( END_SPAN );
				modifyFlag = false;
			}
			else{
				bufcal.append( "0" ); // 5.5.4.0 (2012/07/02)
			}
			str.add(Calendar.DATE, add);
		}
		calStr = bufcal.toString(); // 5.5.4.0 (2012/07/02)

		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		if(colBar){
			buf1.append( buf2 ).append( END_DIV );
		}else{
			buf1.append( BR ).append( buf2 );
		}
		buf2.setLength( 0 );
		
		
		//if( colBar ) { buf1.append( END_SPAN ); }		// 5.6.5.0 (2013/06/07) 色バー対応 5.9.2.0 (2015/11/06) DEL
		
		//return "<pre>" + buf1.toString() + BR + buf2.toString() + "</pre>"; // 5.6.5.0 (2013/06/07) 文字列の作成方法の統一
		return buf1.toString(); // 5.9.2.0 (2015/11/06)
	}

	/**
	 * zoom = 2 の場合のヘッダーを出力します。
	 * このヘッダーだけ特別なので、別メソッドを作成します。
	 *
	 * type=1 の場合
	 * [ 0   ･･･]&lt;br/&gt;[ 2   ･･･]&lt;br/&gt;[ /   ･･･]&lt;br/&gt;[0000 ･･･]&lt;br/&gt;[1234 ･･･]
	 *
	 * という月情報を毎週月曜日にヘッダーに出力します。(上記は、２月１日～２月４日まで)
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
	 * @og.rev 3.6.0.7 (2004/11/06) 月の情報も出力します。
	 * @og.rev 3.7.1.1 (2005/05/23) 本日は、青色で示します。
	 * @og.rev 5.5.4.0 (2012/07/02) カレンダーフラグ対応
	 * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
	 * @og.rev 5.6.5.0 (2013/06/07) 日付欄の段組みを廃止し、色バーに変更します。
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @param	add  	表示日付けの加算
	 *
	 * @return  ヘッダー文字列
	 */
	private String makeZoom2( final int add ) {
		Calendar str = HybsSystem.getCalendar( startDate );
		Calendar end = HybsSystem.getCalendar( endDate );

		StringBuilder buf1   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 月の１桁目
//		StringBuilder buf2   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 月の２桁目	5.6.5.0 (2013/06/07) 色バーに変更
//		StringBuilder buf3   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 区切り記号	5.6.5.0 (2013/06/07) 色バーに変更
		StringBuilder buf4   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 日の１桁目
		StringBuilder buf5   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 日の２桁目
		StringBuilder bufcal = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 5.5.4.0 (2012/07/02) 休日判定用

		// 5.6.5.0 (2013/06/07) 文字列の作成方法の統一。pre タグを最初に設定しておく。
		//buf1.append( "<pre>" ); // 5.9.2.0 (2015/11/06) DEL

		// 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
		CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );

		boolean modifyFlag = false;

		// 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
//		while( str.before( end ) ) {
		int cnt  = 0;					// 5.6.5.0 (2013/06/07) 色バー対応
		int hCnt = 0;					// 月欄は、３文字分
		
		// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
		//buf1.append( EVEN_CLASS );		// 5.6.5.0 (2013/06/07) 色バー対応
		buf1.append(DIV_ZOOMWEEK_START);
		buf1.append(DIV_ZOOMEVENCOLOR);
		
		while( str.compareTo( end ) <= 0 ) {
			int mt = str.get( Calendar.MONTH ) + 1;
			int dt = str.get( Calendar.DATE );
			boolean monday = ( Calendar.MONDAY == str.get( Calendar.DAY_OF_WEEK ) );

			// 3.7.1.1 (2005/05/31) 本日は、青色で示します。
			if( calData.isContainedToday( str,add ) ) {
//				buf1.append( BLUE_COLOR );
//				buf2.append( BLUE_COLOR );
//				buf3.append( BLUE_COLOR );
				buf4.append( BLUE_COLOR );
				buf5.append( BLUE_COLOR );
				bufcal.append("0"); // 5.5.4.0 (2012/07/02)
				modifyFlag = true;
			}

			// 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
			// modifyFlag が立っていない場合 を条件に追加します。
			if( !modifyFlag && add == 1 && calData.isHoliday( str ) ) {
//				buf1.append( RED_COLOR );
//				buf2.append( RED_COLOR );
//				buf3.append( RED_COLOR );
				buf4.append( RED_COLOR );
				buf5.append( RED_COLOR );
				bufcal.append("1"); // 5.5.4.0 (2012/07/02)
				modifyFlag = true;
			}

			if( monday ) {
				// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
				buf1.append(END_DIV).append( buf4.toString() ).append( BR ).append(buf5.toString()).append(END_DIV);
				buf4.setLength( 0 );
				buf5.setLength( 0 );
				
				// 5.6.5.0 (2013/06/07) 色バー対応
				//buf1.append( END_SPAN ); // 5.9.2.0 (2015/11/06) DEL
				
				cnt++;
				hCnt = 0;

				// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
				//if( cnt % 2 == 0 )	{ buf1.append( EVEN_CLASS ); }		// 偶数の色
				//else 				{ buf1.append( ODD_CLASS  ); }		// 奇数の色
				buf1.append( DIV_ZOOMWEEK_START );
				if( cnt % 2 == 0) {buf1.append( DIV_ZOOMEVENCOLOR );}
				else			{buf1.append( DIV_ZOOMODDCOLOR ); }

//				buf1.append( (mt/10) );
//				buf2.append( mt%10 );
//				buf3.append( "/" );
			}
//			else {
//				buf1.append( " " );
//				buf2.append( " " );
//				buf3.append( " " );
//			}

			// 5.6.5.0 (2013/06/07) 色バー対応
			switch( hCnt++ ) {
				case 0 :	buf1.append( (mt/10) ); break;		// 月の1文字目
				case 1 :	buf1.append(  mt%10  ); break;		// 月の2文字目
				case 2 :	buf1.append(   "/"   ); break;		// 月の区切り文字
				default :	buf1.append(   " "   ); break;		// 空欄
			}

			// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
			//buf4.append( (dt/10) );
			//buf5.append( dt%10 );
			buf4.append( DIV_ZOOMHEADER2 ).append( (dt/10) ).append( END_DIV );
			buf5.append( DIV_ZOOMHEADER2 ).append( dt%10 ).append( END_DIV );

			if( modifyFlag ) {
//				buf1.append( END_SPAN );
//				buf2.append( END_SPAN );
//				buf3.append( END_SPAN );
				buf4.append( END_SPAN );
				buf5.append( END_SPAN );
				modifyFlag = false;
			}
			else{
				bufcal.append("0"); // 5.5.4.0 (2012/07/02)
			}
			str.add(Calendar.DATE, add);
		}
		
		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		buf1.append(END_DIV).append( buf4.toString() ).append( BR ).append(buf5.toString()).append(END_DIV);
		buf4.setLength( 0 );
		buf5.setLength( 0 );

//		buf1.append( BR ).append( buf2 );
//		buf1.append( BR ).append( buf3 );
		//buf1.append( END_SPAN );				// 5.6.5.0 (2013/06/07) 色バー対応 5.9.2.0 (2015/11/06) DEL
		
//		buf1.append( BR ).append( buf4 );
//		buf1.append( BR ).append( buf5 );
		calStr = bufcal.toString();				// 5.5.4.0 (2012/07/02)

//		//		return "<pre>" + buf1.toString() + "</pre>";
		
		//return buf1.append( BR ).append( buf4 ).append( BR ).append( buf5 ).append( "</pre>" ).toString();		// 5.6.5.0 (2013/06/07) 文字列の作成方法の統一
		return buf1.toString(); // 5.9.2.0 (2015/11/06)
	}

	/**
	 * ヘッダー、上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
	 * これは特殊で、ヘッダーに、年/月、上段は日、下段は、曜日を想定しています。
	 * ヘッダー部分は、月として横持で表示させます。
	 *
	 * @og.rev 5.6.2.3 (2013/03/22) 新規追加
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @param	header	年月のヘッダー部分
	 * @param	upper	上段の表示フォーマット(日)
	 * @param	lower	下段の表示フォーマット(曜日)
	 * @param	add  	表示日付けの加算
	 *
	 * @return  ヘッダー文字列
	 */
	private String makeZoom3( final String header ,final String upper ,final String lower ,final int add ) {
		DateFormat formatH = new SimpleDateFormat( header,Locale.JAPAN );
		DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
		DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );

		StringBuilder bufH   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 年月のヘッダー部分(11Byte目から)
		StringBuilder buf1   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 日(２桁)
		StringBuilder buf2   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 曜日
		StringBuilder bufcal = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 5.5.4.0 (2012/07/02) 休日判定用

		// 5.6.5.0 (2013/06/07) 文字列の作成方法の統一。pre タグを最初に設定しておく。
		//bufH.append( "<pre>" ); // 5.9.2.0 (2015/11/06) DEL

		Calendar str = HybsSystem.getCalendar( startDate );
		Calendar end = HybsSystem.getCalendar( endDate );

		// 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
		CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );

		int	dtsu		= lower.length();						// 日付欄(下段)の文字数
		int	dayCount	= 0;									// ヘッダー部の文字が入るかどうかの基準
		int	mtCnt		= str.get( Calendar.MONTH ) + 1;		// 月をチェック(色設定用) 初期値は、開始時の月
		String tmpH		= null;									// ヘッダー部のテンポラリ情報
		
		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		bufH.append(DIV_ZOOMWEEK_START);
		
		// 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
//		while( str.before( end ) ) {
		while( str.compareTo( end ) <= 0 ) {
			Date dt = str.getTime();

			if( tmpH == null ) { tmpH = formatH.format( dt ); }	// 初期値。最初にセット

			// ここから一連の処理は、月表示ヘッダーの作成
			int day = str.get( Calendar.DATE );			// ヘッダー部の制御用に、日付が必要
			if( day == 1 && dayCount > 0 ) {
				
				makeHeaderYM( bufH , dayCount*dtsu , mtCnt++ , tmpH );		// このヘッダー出力は、ひと月前の情報
				
				// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
				bufH.append( buf1 ).append(BR).append(buf2).append( "</div>" );
				buf1.setLength( 0 );
				buf2.setLength( 0 );
				bufH.append( DIV_ZOOMWEEK_START );
				
				dayCount = 0 ;
				tmpH	 = formatH.format( dt );
			}
			dayCount ++ ;	// 

			// 5.6.2.3 (2013/03/22) 休日、本日の処理を class属性化で、合成可能とします。
			String span = null;
			// 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
			if( calData.isHoliday( str ) ) {
				span = HOLIDAY_CLASS ;
				bufcal.append( "1" ); // 5.5.4.0 (2012/07/02) 休日
			}
			else {
				bufcal.append( "0" ); // 5.5.4.0 (2012/07/02)
			}

			if( calData.isContainedToday( str,add ) ) {				// 本日かどうか
				span = (span == null) ? TODAY_CLASS : span + " " + TODAY_CLASS ;
			}

			if( span != null ) {
				buf1.append( "<span class=\"" ).append( span ).append( "\">" );
				buf2.append( "<span class=\"" ).append( span ).append( "\">" );
			}

			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			buf1.append( DIV_ZOOMHEADER2 );
			buf2.append( DIV_ZOOMHEADER2 );
			
			buf1.append( format1.format( dt ) );
			buf2.append( format2.format( dt ) );

			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			buf1.append( END_DIV );
			buf2.append( END_DIV );
			
			if( span != null ) {
				buf1.append( END_SPAN );
				buf2.append( END_SPAN );
			}
			str.add(Calendar.DATE, add);
		}

		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		// 処理の最後に、ヘッダーの出力は必要
		makeHeaderYM( bufH , dayCount*dtsu , mtCnt , tmpH );
		
		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		bufH.append( buf1 ).append( BR ).append( buf2 ).append( END_DIV );
		buf1.setLength( 0 );
		buf2.setLength( 0 );
		
		calStr = bufcal.toString(); // 5.5.4.0 (2012/07/02)

//		return "<pre>" + bufH.toString() + BR + buf1.toString() + BR + buf2.toString() + "</pre>";
		
		
		//return bufH.append( BR ).append( buf1 ).append( BR ).append( buf2 ).append( "</pre>" ).toString();		// 5.6.5.0 (2013/06/07) 文字列の作成方法の統一
		return bufH.toString(); // 5.9.2.0 (2015/11/06)
	}

	/**
	 * 時間軸での月ヘッダーデータを作成します。
	 *
	 * 月ヘッダーは、1日～月末までの日付の上段に、年月(yyyy/MM)表示のヘッダーを作成します。
	 * ヘッダーは、できるだけセンター表示になるように、前後にスペースを入れて調整します。
	 * ヘッダー表示領域が少ない場合、スペースのみになります。
	 * ヘッダーは月が偶数月か奇数月かで、背景色を切り替えることで、判りやすくします。
	 *
	 * @og.rev 5.6.2.3 (2013/03/22) 新規追加
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @param		bufH	ヘッダーを追記していく StringBuilder
	 * @param		dayCnt	日付欄の文字数カウント。日数＊桁数(DTSU)。通常、横持なら 2桁 となる。
	 * @param		mtCnt	月数に基づいた色の設定用の数字。月の連番にします。
	 * @param		ymStr	ヘッダーに表示する文字列。年月(yyyy/MM)
	 *
	 * @return  ヘッダーが追記された StringBuilder
	 */
	private StringBuilder makeHeaderYM( final StringBuilder bufH , final int dayCnt , final int mtCnt , final String ymStr ) {
		// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
		// 奇数月と偶数月で色を変える。将来的に % 3 で判定すれば、３色で廻せる。
		//if( mtCnt % 2 == 0 )	{ bufH.append( EVEN_CLASS ); }		// 偶数月の色
		//else 					{ bufH.append( ODD_CLASS  ); }		// 奇数月の色
		if( mtCnt % 2 == 0 )	{ bufH.append( DIV_ZOOMEVENCOLOR ); }
		else					{ bufH.append( DIV_ZOOMODDCOLOR ); }
		
		// 表示すべき文字列が、日付欄の幅よりも小さい場合、スペースのみとする。
		if( dayCnt < ymStr.length() ) {
			bufH.append( SPACE.substring( 0,dayCnt ) );
		}
		// 大きい場合は、前後にスペースを入れて、センター配置
		else {
			int lcnt = (dayCnt-ymStr.length())/2 ;		// 左の個数。端数が切り捨てられる。
			int rcnt = dayCnt-lcnt-ymStr.length();		// 右の個数。端数を考慮し、引き算のみで求める。

			bufH.append( SPACE.substring( 0,lcnt ) );
			bufH.append( ymStr );
			bufH.append( SPACE.substring( 0,rcnt ) );
		}

		//bufH.append( END_SPAN );
		bufH.append( END_DIV ); // 5.9.2.0 (2015/11/06)

		return bufH;
	}

	/**
	 * 時間軸でのヘッダー表示を行います。
	 *
	 * 時間軸の為、ヘッダーの上下段組は行いません。
	 * ヘッダーは、１時間単位に表示します。また、休憩時刻も求めています。
	 *
	 * @og.rev 3.8.0.5 (2005/08/26) 新規追加
	 * @og.rev 3.8.1.1 (2005/11/21) 日付title,範囲class,
	 * @og.rev 3.8.1.4 (2006/03/13) 日付表示、時刻単位(h)削除、２段組(USE_MULTI_CLM)
	 * @og.rev 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、２文字分(24ピクセル)化する。
	 * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
	 * @og.rev 4.0.0.0 (2007/09/03) 休日の場合でも表示されるように対応(システムリソースで切り替え)
	 * @og.rev 5.5.4.0 (2012/07/02) ガントの一日表示枠の計算を切り上げするようにする。カレンダーフラグ対応。
	 * @og.rev 5.6.1.2 (2013/02/22) ベース時刻を管理。 ym2int 廃止 ⇒ hm2int に変更。 USE_MULTI_CLM ⇒ useMultiClm 変更。
	 * @og.rev 5.6.4.3 (2013/05/24) ヘッダーずれ対応。"日" を２文字の、"日 " に修正。
	 * @og.rev 5.6.5.0 (2013/06/07) 色バーに変更します。
	 * @og.rev 5.6.7.0 (2013/11/03) 時間軸の上段ヘッダーに月日を表示
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @param		hourOfPixcel １時間あたりのピクセル数。
	 * @param		step  時間間隔の指定(1:１時間間隔、2:２時間間隔････)
	 * @param		useTani  日や時間の単位表示を行う(true)か、行わない(false)か
	 *
	 * @return  ヘッダー文字列
	 */
//	private String makeZoomTime( final int hourOfPixcel,final boolean useTani ) {
	private String makeZoomTime( final int hourOfPixcel,final int step,final boolean useTani ) {
//		DateFormat format1 = new SimpleDateFormat( "yyyy/MM/dd",Locale.JAPAN );
		DateFormat format1 = new SimpleDateFormat( "yyyy/MM/dd(EE)",Locale.JAPAN );		// 5.6.5.0 (2013/06/07) 曜日を、tipsに出す。
		DateFormat format2 = new SimpleDateFormat( "MM/dd",Locale.JAPAN );				// 5.7.0.0 (2013/11/03) 上段

		StringBuilder bufBT  = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)
		StringBuilder buf1   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 下段の時刻データ
//		StringBuilder buf2   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 休憩の管理
		StringBuilder bufH   = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 3.8.1.4 (2006/03/13) 段組みヘッダー
		StringBuilder bufcal = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 5.5.4.0 (2012/07/02) 休日判定用
		StringBuilder bufDY	 = new StringBuilder( HybsSystem.BUFFER_SMALL );		// 5.7.0.0 (2013/11/03) 上段用
		
		String	last_title = null; // 5.7.0.0 (2013/11/03)
		int		day_length = 0; // 5.7.0.0 (2013/11/03)
		int 	base = 2;		// 5.7.0.0 (2013/11/03) 時間単位の標準桁数
		if( useTani ){ base = 4;}
		
		// daySpan	= "0700-2000";	// 開始時刻(HHmm-HHmm) 3.8.0.5 (2005/08/26)
		// 分の少数計算を行います。加算は１時間(0100)単位です。
//		int startTime = ym2int( daySpan.substring( 0,2 ),daySpan.substring( 2,4 ) ) ;
//		int endTime   = ym2int( daySpan.substring( 5,7 ),daySpan.substring( 7 ) ) ;
		// 5.6.1.2 (2013/02/22) 
		int ad = daySpan.indexOf( '-' );
		int startTime = hm2int( daySpan.substring( 0,ad ) ) ;
		int endTime   = hm2int( daySpan.substring( ad+1 ) ) ;
		
		// 開始時刻より終了時刻が同じか小さい場合は、翌日なので2400加算します。
		if( endTime <= startTime ) { endTime += 2400; }

		// 休憩時間を管理する BreakTimes オブジェクトを作成します。
//		BreakTimes breakTimeObj = new BreakTimes( hourOfPixcel,breakTimes,breakTimeStyle,startTime,endTime );
		BreakTimes breakTimeObj = new BreakTimes( hourOfPixcel/step,breakTimes,breakTimeStyle,startTime,endTime );

		// 5.6.1.2 (2013/02/22) ベース時刻を管理する BreakTimes オブジェクトを作成します。(利用するクラスは同じ)
		BreakTimes baseTimeObj = new BreakTimes( hourOfPixcel/step,baseTimes,baseTimeStyle,startTime,endTime );

		// 現在時刻を求めておきます。 現在時刻に５分加算しておきます。(余計なお世話?)
		Calendar rightNow = Calendar.getInstance();
		rightNow.add( Calendar.MINUTE,5 );		// ５分 加算
		int now = rightNow.get( Calendar.HOUR_OF_DAY ) ;

		// 3.8.5.0 (2006/02/06)
		boolean isDebug = isDebug();
		if( isDebug ) {
			System.out.println( "startDate=" + startDate );
			System.out.println( "endDate  =" + endDate );
		}

		Calendar str = HybsSystem.getCalendar( startDate );
		Calendar end = HybsSystem.getCalendar( endDate );

		// 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
		CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );

		// １時間=hourOfPixcel(px) なので、１日分のピクセルを求めておく。(休憩時刻表示用)
//		int dayOfPixel = (int)(hourOfPixcel * (endTime-startTime)/100.0 );
//		int dayOfPixel = (int)(hourOfPixcel/step * (endTime-startTime)/100.0 );
		int dayOfPixel = (int)(hourOfPixcel * Math.ceil((endTime-startTime)/100.0/step) ); // 5.5.4.0 (2012/07/02) 切り上げ

		// 休憩表示における画面上の表示日数。これが、左のバイアス値として１日分と乗算される。
		int totalDay = 0;

		// １日分の表示範囲の開始時刻とデータの表示開始時刻との差(オフセット)ピクセル
//		int offsetPixel = (int)(hourOfPixcel * (startTime - (int)(str.get( Calendar.HOUR_OF_DAY )*100 + str.get( Calendar.MINUTE )*10.0/6.0))/100.0 );
		int offsetPixel = (int)(hourOfPixcel/step * (startTime - (int)(str.get( Calendar.HOUR_OF_DAY )*100 + str.get( Calendar.MINUTE )*10.0/6.0))/100.0 );

		// 3.8.1.4 (2006/03/13) 時間単位(h)の表示有無を USE_MULTI_CLM と関係させます。
	 	// 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、２文字分(24ピクセル)化する。
		final String tani ;
//		if( useTani ) { tani = ( USE_MULTI_CLM ) ? "  " : "h " ; }
//		if( useTani ) { tani = ( useMultiClm ) ? "  " : "h " ;	}		// 5.6.1.2 (2013/02/22) useMultiClm 追加
		if( useTani ) { tani = "h " ;	}		// 5.6.5.0 (2013/06/07) useMultiClm を無視します。
		else {			tani = "";								}

		boolean modifyFlag = false;
		int cnt = 0;	// 3.8.1.1 (2005/11/21)
		
		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		StringBuilder bufSave = new StringBuilder();
		
		while( str.before( end ) ) {	// 終了時間は、「含まない」仕様
			if( isDebug ) { System.out.println( "Calendar str =" + str.getTime() ); }	// 3.8.5.0 (2006/02/06)

			// 5.6.5.0 (2013/06/07) 日付と曜日の対応
			int day = str.get( Calendar.DATE );
			String dayStr = ((day >= 10) ? day : ("0" + day) ) + ((useTani) ? DAY_OF_WEEK_ja[str.get( Calendar.DAY_OF_WEEK )] : "") ;

			// 5.5.4.0 (2012/07/02) この場合は枠単位ではなく、日単位で出力する
			// skipHolidayは無視して、範囲内の全てのカレンダーを出力
			if(calData.isHoliday( str )){
				bufcal.append("1");
			}
			else{
				bufcal.append("0");
			}

			// 休日判断を、事業所カレンダを使用:休日なら、日付を進める。
			if( calData.isHoliday( str ) && skipHoliday ) {
				if( isDebug ) { System.out.println( "Holiday =" + str.getTime() ); }	// 3.8.5.0 (2006/02/06)
				str.add(Calendar.DATE, 1);
				continue;
			}

			
			// 3.8.1.1 (2005/11/21) 日付のツールチップ表示
			//String ganttClass = "class=\"GNT_" + (cnt % 2) + "\"" ;
			String ganttClass = "class=\"GNT_" + (cnt % 2) + " zoomHeaderDiv2\""; // 5.9.2.0 (2015/11/06) 
			
			Date dt = str.getTime();
			String title = format1.format( dt );
			
			// 5.9.2.0 (2015/11/06) MODIFY
			//buf1.append( "<span " ).append( ganttClass );
			buf1.append( "<div " ).append( ganttClass );
			buf1.append( " title=\"" ).append( title ).append( "\">" );
			
			// 5.7.0.0 (2013/11/03) 上段
			if( last_title != null & day_length > 0 ){
				makeHeaderMD(bufDY , day_length*base , 0 , last_title);
				day_length = 0;
			}
			last_title = format2.format( dt );
			
			if( isDebug ) { System.out.println( "title =" + title ); }	// 3.8.5.0 (2006/02/06)
			
			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			if( cnt > 0 ){
				bufSave.append( DIV_ZOOMWEEK_START );
				if( useMdheader ){ // 5.7.0.0 （2013/11/03）月日を冗談に表示する
					bufSave.append( bufDY );
				}
				bufSave.append( bufH );
				bufDY.setLength( 0 );
				bufH.setLength( 0 );
			}
			
			// 5.6.5.0 (2013/06/07) 色バー対応
			if( useMultiClm ) {
				// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
				//if( cnt % 2 == 0 )	{ bufH.append( EVEN_CLASS ); }		// 偶数の色
				//else 				{ bufH.append( ODD_CLASS  ); }		// 奇数の色
				if( cnt % 2 == 0 )	{ bufH.append( DIV_ZOOMEVENCOLOR ); }			// 偶数の色
				else 				{ bufH.append( DIV_ZOOMODDCOLOR ); }		// 奇数の色
			}
			cnt++;		// 5.6.5.0 (2013/06/07) 他の処理は、cnt++ を先にしているが、ここでは初期設定指定ない為、cnt++ を、処理の後で行う。

			// 本日かどうかを判断する。
			boolean isToday = calData.isContainedToday( str,1 );

			int tmHd = startTime/100 ;
			int dayOut = tmHd;		// 3.8.1.4 (2006/03/13)
			boolean isTodayNow = false;		// 3.8.9.2 (2007/07/28) 時間ステップ対応

			for( int h=startTime; h<endTime; h+=100 ) {		// 加算は１時間単位
				if( isDebug ) {	// 3.8.5.0 (2006/02/06)
					System.out.println( "hour =" + h );
					System.out.println( "tmHd =" + tmHd );
				}
				// 3.8.9.2 (2007/07/28) 時間ステップ対応
				isTodayNow = isTodayNow || ( isToday && tmHd == now );
				if( ( dayOut - tmHd ) % step != 0 ) { tmHd++; continue; }

				day_length++; // 5.7.0.0 (2013/11/03)
				
				if( tmHd >= 24 ) {
					tmHd = 0;
					
					// 3.8.1.1 (2005/11/21) 日付のツールチップを次の日に設定します。
					Date dt2 = new Date( str.getTimeInMillis() + 24*3600*1000L );
					title = format1.format( dt2 );
					
					// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
					buf1.append(END_DIV).append( "<div " ).append( ganttClass );
					buf1.append( " title=\"" ).append( title ).append( "\">" );
				}

				// 本日の現在時刻は、青色で示します。
//				if( isToday && tmHd == now ) {
				if( isTodayNow ) {
					buf1.append( BLUE_COLOR );
					bufH.append( BLUE_COLOR );
					modifyFlag = true;
					isTodayNow = false;		// 初期化
				}
				// 4.0.0.0 休日の場合は赤色で表示
				else if( calData.isHoliday( str ) && !skipHoliday ) {
					buf1.append( RED_COLOR );
					bufH.append( RED_COLOR );
					modifyFlag = true;
				}

				// 実質表示日数(totalDay) * １日分のピクセル(dayOfPixel) - オフセット(offsetPixel)
//				String bt = breakTimeObj.makeSpan( totalDay*dayOfPixel-offsetPixel,str,h );
				String bt = breakTimeObj.makeSpan( totalDay*dayOfPixel-offsetPixel,str,h,step );
//				if( bt != null ) { buf2.append( bt ); }
				if( bt != null ) { bufBT.append( bt ); }		// 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)

				// 5.6.1.2 (2013/02/22) ベース時刻のタグを出力します。
				bt = baseTimeObj.makeSpan( totalDay*dayOfPixel-offsetPixel,str,h,step );
//				if( bt != null ) { buf2.append( bt ); }
				if( bt != null ) { bufBT.append( bt ); }		// 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)

				
				buf1.append( DIV_ZOOMWEEKDAY ); // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
				
				// 時間当たりの文字数は、４文字： 文字列を詰める。
				if( tmHd < 10 ) { buf1.append( '0' ); }		// 桁数あわせ
				buf1.append( tmHd ).append( tani );			// 3.8.1.4 (2006/03/13)

				buf1.append(END_DIV); // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
				
				// 3.8.1.4 (2006/03/13) 日付表示、時刻単位(h)削除、２段組(USE_MULTI_CLM)
			 	// 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、２文字分(24ピクセル)化する。
//				if( USE_MULTI_CLM ) {
				if( useMultiClm ) {						// 5.6.1.2 (2013/02/22) useMultiClm 追加
//					if( ( dayOut - tmHd ) % 6 == 0 ) {
					if( ( dayOut - tmHd ) == 0 ) {		// 5.6.5.0 (2013/06/07) 色バー対応
//						if( useTani ) { bufH.append( title.substring( 8 ) ).append( "日" ); }
//						if( useTani ) { bufH.append( title.substring( 8 ) ).append( "日 " ); }	// 5.6.4.3 (2013/05/24) ヘッダーずれ対応。"日" を２文字の、"日 " に修正。
//						else {			bufH.append( title.substring( 8 ) );				}
						bufH.append( dayStr );			// 5.6.5.0 (2013/06/07) 先に日付＋曜日の文字列を作成する。"日" を２文字の、"日 " に修正済み。
					}
					else {
						if( useTani ) { bufH.append( "    " ); }
						else {			bufH.append( "  " );   }
					}
				}

				if( modifyFlag ) {
					buf1.append( END_SPAN );
					bufH.append( END_SPAN );
					
					modifyFlag = false;
				}
				
				tmHd++;	// ヘッダーに記述する時刻
			}
			
			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			if( useMultiClm ){
				bufH.append(END_DIV);
			}
			bufH.append( buf1.toString() ).append(END_DIV);
			buf1.setLength( 0 );
			
			str.add(Calendar.DATE, 1);
			totalDay++ ;
			
			
			// if( useMultiClm ) { bufH.append( END_SPAN ); }	// 5.6.5.0 (2013/06/07) 色バー対応
			if( useMultiClm ) { bufH.append(  END_DIV ); } // 5.9.2.0 (2015/11/06)
		}

		// 3.8.1.4 (2006/03/13) 日付表示、時刻単位(h)削除、２段組(USE_MULTI_CLM)
//		buf2.append( "<pre>" );
//		buf1.append( "</pre>" );

//		if( USE_MULTI_CLM ) {
//		if( useMultiClm ) {				// 5.6.1.2 (2013/02/22) useMultiClm 追加
//			buf2.append( bufH.toString() ).append( "<br />" );
//		}
		
		// 5.9.2.0 (2015/11/06) DELETE ヘッダー列幅の固定対応
		//if( useMultiClm ) {				// 5.6.1.2 (2013/02/22) useMultiClm 追加
		//	bufH.append( BR );
		//}
		calStr = bufcal.toString(); // 5.5.4.0 (2012/07/02)
		
		// 5.7.0.0 (2013/11/03) 最後の上段
		if( last_title != null & day_length > 0 ){
			makeHeaderMD(bufDY , day_length*base , 0 , last_title);
			day_length = 0;
		}

		// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
		bufSave.append( DIV_ZOOMWEEK_START );
		if( useMdheader ){ 				// 5.7.0.0 (2013/11/03) 月日を上段に表示する
			bufSave.append( bufDY );
		}
		bufSave.append( bufH );
		bufDY.setLength( 0 );
		bufH.setLength( 0 );
		
//		return buf2.append( buf1.toString() ).toString() ;
		
		// 5.9.2.0 (2015/11/06) DEL ヘッダー列幅の固定対応
		//if( useMdheader ){ // 5.7.0.0 (2013/11/03) 月日を上段に表示する
		//	bufH = bufDY.append( BR ).append(bufH); 
		//}
		
		
		//return bufBT.append( "<pre>" ).append( bufH ).append( buf1 ).append( "</pre>" ).toString() ;
		//return bufBT.append( bufH ).append( buf1 ).toString();
		return bufBT.append( bufSave ).toString(); // 5.9.2.0 (2015/11/06) 
	}

	/**
	 * 時間軸での日ヘッダーデータを作成します。
	 *
	 * ヘッダーは、時間表示の場合に上段にMM/ddを表示します。
	 *
	 * @og.rev 5.7.0.0 (2013/11/07) 新規追加
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @param		bufH	ヘッダーを追記していく StringBuilder
	 * @param		fillCnt	日付欄の文字数カウント。通常は2*時間数か、4*時間数のどちらか。
	 * @param		mtCnt	月数に基づいた色の設定用の数字。(将来的な拡張用）
	 * @param		mdStr	ヘッダーに表示する文字列。月日(MM/dd)
	 *
	 * @return  ヘッダーが追記された StringBuilder
	 */
	private StringBuilder makeHeaderMD( final StringBuilder bufH , final int fillCnt , final int mtCnt ,  final String mdStr ) {
		// 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
		//if( mtCnt % 2 == 0 )	{ bufH.append( EVEN_CLASS ); }		// 偶数色
		//else 					{ bufH.append( ODD_CLASS  ); }		// 奇数色
		if( mtCnt % 2 == 0 )	{ bufH.append( DIV_ZOOMEVENCOLOR ); }			// 偶数の色
		else 				{ bufH.append( DIV_ZOOMODDCOLOR ); }		// 奇数の色
		
		// 表示すべき文字列が、表示すべき幅よりも小さい場合、スペースのみとする。
		if( fillCnt < mdStr.length() ) {
			bufH.append( StringUtil.stringXFill(" ",fillCnt) );
		}
		// 大きい場合は、前後にスペースを入れて、センター配置
		else {
			bufH.append( StringUtil.stringXFill(mdStr,fillCnt) );
		}

		
		//bufH.append( END_SPAN );
		bufH.append( END_DIV ); // 5.9.2.0 (2015/11/06) 

		return bufH;
	}

	/**
	 * 上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
	 *
	 * @param	upper	上段の表示フォーマット
	 * @param	lower	下段の表示フォーマット
	 * @param	add  	表示日付けの加算
	 * @param	useMonth	月日表示でなく、月表示のみにする
	 * 
	 * @og.rev 5.6.1.2 (2013/02/22) 新規作成
	 * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
	 * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
	 *
	 * @return  ヘッダー文字列
	 */
	private String makeZoomStack( final String upper ,final String lower ,final int add, final boolean useMonth ) {
		DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
		DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );

		DateFormat formatCal = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );

		// 5.5.8.3 (2012/11/17) スタック用にカレンダー枠の情報を保持(開始、休日判定、次枠開始)
		ArrayList<String[]> calList = new ArrayList<String[]>(); 			// 個人的には Listを渡す方が好き
		String[] calArray = new String[3]; // 開始、休日判定、次枠開始

		Calendar str = HybsSystem.getCalendar( startDate );
		Calendar end = HybsSystem.getCalendar( endDate );

		// 週単位の場合の特殊処理。
		// 年の第一週を完全な一週間分(７日間)として、設定します。
		if( zoom == 41 ) {		// ViewStackTableParam.STACK_ZOOM_WEEK
			str.setMinimalDaysInFirstWeek( 7 );
			format1.setCalendar( str );
			format2.setCalendar( str );
		}

		if( useMonth ){
			str.set(Calendar.DAY_OF_MONTH, 1);
			startDate = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN ).format(str.getTime());
		}

		StringBuilder buf1   = new StringBuilder( HybsSystem.BUFFER_SMALL );
		StringBuilder buf2   = new StringBuilder( HybsSystem.BUFFER_SMALL );
		StringBuilder bufcal = new StringBuilder( HybsSystem.BUFFER_SMALL ); 

		//  カレンダDB検索機能
		CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );

		boolean modifyFlag = false;
		// 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
//		while( str.before( end ) ) {
		while( str.compareTo( end ) <= 0 ) {
			Date dt = str.getTime();
			calArray[0] = formatCal.format( dt ); // 5.5.8.3 (2012/11/17)

			// 本日は、青色で示します。
			if( calData.isContainedToday( str,add ) ) {
				buf1.append( BLUE_COLOR );
				buf2.append( BLUE_COLOR );
				bufcal.append( "0" ); 
				calArray[1] = "0"; // 5.5.8.3 (2012/11/17)
				modifyFlag = true;
			}

			// 休日判断を、事業所カレンダを使用
			// modifyFlag が立っていない場合 を条件に追加します。
			if( !modifyFlag && add == 1 && calData.isHoliday( str ) && !useMonth) {
				buf1.append( RED_COLOR );
				buf2.append( RED_COLOR );
				bufcal.append( "1" ); // 休日
				calArray[1] = "1"; // 5.5.8.3 (2012/11/17)
				modifyFlag = true;
			}

			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			buf1.append( DIV_ZOOMHEADER2 );
			buf2.append( DIV_ZOOMHEADER2 );
			
			buf1.append( format1.format( dt ) );
			buf2.append( format2.format( dt ) );
			
			// 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
			buf1.append( END_DIV );
			buf2.append( END_DIV );

			if( modifyFlag ) {
				buf1.append( END_SPAN );
				buf2.append( END_SPAN );
				modifyFlag = false;
			}
			else{
				bufcal.append( "0" ); 
				calArray[1] = "0"; // 5.5.8.3 (2012/11/17)
			}

			// カレンダーを進める
			if( useMonth ){
				str.add(Calendar.MONTH, add);
			}
			else{
				str.add(Calendar.DATE, add);
			}

			dt = str.getTime();
			calArray[2] = formatCal.format( dt ); // 5.5.8.3 (2012/11/17)
			calList.add( calArray.clone() );
		}

		// スタックガント用の特別な処理。
		// 上位の ViewForm_HTMLStackedGanttTable クラスに対して、「開始、休日判定、次枠開始」リストを渡します。
		ViewFormTag viewform = (ViewFormTag)findAncestorWithClass( this,ViewFormTag.class );
		viewform.setViewArrayList( calList ); 

		calStr = bufcal.toString(); 

		// return "<pre>" + buf1.toString() + BR + buf2.toString() + "</pre>";
		return buf1.toString() + BR + buf2.toString(); // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
	}

	/**
	 * ganttHeaderの属性情報をdisplay:noneで作成します。
	 * ganttHeaderというタグで、id,class共にganttHeaderDataという名称で出力します。
	 *
	 * @og.rev 5.5.4.0 (2012/07/02) 新規作成
	 * @og.rev 5.6.1.2 (2013/02/22) baseTimes 追加
	 *
	 * @return  ヘッダー情報の文字列
	 */
	private String makeHeaderData() {

		StringBuilder buf1 = new StringBuilder( HybsSystem.BUFFER_SMALL );

		buf1.append( "\n" )
			.append( "<ganttHeader style='display:none' id='ganttHeaderData' class='ganttHeaderData' " )
			.append( "startDate='"	).append( startDate		).append( "' " )
			.append( "endDate='"	).append( endDate		).append( "' " )
			.append( "zoom='"		).append( zoom			).append( "' " )
			.append( "daySpan='"	).append( daySpan		).append( "' " )
			.append( "calDB='"		).append( calStr		).append( "' " )
			.append( "breakTimes='" ).append( breakTimes	).append( "' " )
			.append( "baseTimes='"	).append( baseTimes		).append( "' " )		// 5.6.1.2 (2013/02/22) baseTimes 追加
			.append( "skipHoliday='" ).append( skipHoliday	).append( "' " )
			.append( "useMultiClm='" ).append( useMultiClm	).append( "' " )		// 5.6.1.2 (2013/02/22) useMultiClm 追加
			.append( " />" );

		return buf1.toString();
	}

	/**
	 * 【TAG】表示開始日付けを設定します(yyyyMMdd または、yyyyMMddHHmm 形式)。
	 *
	 * @og.tag
	 * この値は、ヘッダーの先頭に表示する日付けを指定します。
	 * 通常の日付ヘッダーの場合は、 yyyyMMdd 形式ですが、時間ヘッダーの場合は、
	 * yyyyMMddHHmm 形式で指定します。
	 *
	 * @param	val 表示開始日付(yyyyMMdd または、yyyyMMddHHmm 形式)
	 */
	public void setStartDate( final String val ) {
		startDate = nval( getRequestParameter( val ),startDate );
	}

	/**
	 * 【TAG】表示最終日を設定します(yyyyMMdd または、yyyyMMddHHmm 形式)。
	 *
	 * @og.tag
	 * 表示開始日から終了日までを、zoom 変数の値に応じてヘッダーラベルを
	 * 作成します。
	 * 通常の日付ヘッダーの場合は、 yyyyMMdd 形式ですが、時間ヘッダーの場合は、
	 * yyyyMMddHHmm 形式で指定します。
	 *
	 * @param	val 表示最終日(yyyyMMdd または、yyyyMMddHHmm 形式)
	 */
	public void setEndDate( final String val ) {
		endDate = nval( getRequestParameter( val ),endDate );
	}

	/**
	 * 【TAG】１日の開始終了時間を24時間形式(HHmm-HHmm または HH-HH)で設定します(初期値:0700-2000)。
	 *
	 * @og.tag
	 * この値は、１日の開始終了時間を指定します。
	 * 開始時刻は、内部で１時間単位に変換されます。８時３０分～は、８時～になります。
	 * 終了時間は、その時間を「含みません」
	 * 開始時刻より終了時刻が小さい場合は、翌日への日またぎとして計算します。
	 * たとえば、夜勤等で、17:00-07:00 という指定が可能です。
	 * 初期値は、朝の7:00から夜の20:00までです。(0700-2000)です。
	 *
	 * @og.rev 3.8.0.5 (2005/08/26) 本日は、青色で示します。
	 * @og.rev 5.6.1.2 (2013/02/22) daySpan（時刻表示範囲）は、内部では１時間単位
	 *
	 * @param	val 開始終了時間(HHmm-HHmm)形式
	 */
	public void setDaySpan( final String val ) {
		daySpan = nval( getRequestParameter( val ),daySpan );

		// 5.6.1.2 (2013/02/22) daySpan（時刻表示範囲）は、内部では１時間単位
		if( daySpan.length() == 5 && daySpan.charAt(2) == '-' ) {
			daySpan = daySpan.substring( 0,2 ) + "00-" + daySpan.substring( 3 ) + "00" ;	// HH-HH ⇒ HH00-HH00
		}
		else if( daySpan.length() == 9 && daySpan.charAt(4) == '-' ) {
			daySpan = daySpan.substring( 0,2 ) + "00-" + daySpan.substring( 5 ) ;			// HHmm-HHmm  ⇒ HH00-HHmm
		}
		else {
//		if( daySpan.length() != 9 || daySpan.charAt(4) != '-' ) {		// 5.6.1.2 (2013/02/22)
//			String errMsg = "１日の開始終了時間は24時間制で(HHmm-HHmm)形式で指定してください。"
			String errMsg = "１日の開始終了時間は24時間制で(HHmm-HHmm または HH-HH)形式で指定してください。"
					+ " value=[" + val + "]"
					+ " daySpan=[" + daySpan + "]" ;		// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】ズーム変数(0～9,10,11,12,20～31,40～42)を設定します(初期値:2)。
	 *
	 * @og.tag
	 * CSSファイルでの定義と、背景画像との関係で、作成します。
	 * ズーム変数は、CSSファイルや、JavaScript、PL/SQLと連動して、日付間隔
	 * あたりのピクセルを計算して、ヘッダーを作成しています。
	 * また、現在の標準的なクライアントでの換算になる為、高解像度のディスプレイや
	 * 特殊設定された環境では、表示間隔にずれが発生する可能性があります。
	 *
	 *    ZOOM  ラベル        日数ピクセル変換率          ヘッダ上      ヘッダ下    1文字(CSS)
	 *  ========================================================================================
	 *      0 : １週間 日数 *  8 * 6       48    48px =  1日  [02/   ]      [23(EE)]       8px
	 *      1 : ２週間 日数 *  8 * 3       24    24px =  1日  [02/]         [23 ]          8px
	 *      2 : １ヶ月 日数 *  12* 1       12    12px =  1日  [2]           [3]           12px
	 *      3 : ２ヶ月 日数 *  8 * 7  /  7  8    56px =  7日  [2004/  ]     [02/03  ]      8px
	 *      4 : ３ヶ月 日数 *  8 * 7  / 14  4    56px = 14日  [2004/  ]     [02/03  ]      8px
	 *      5 : ４ヶ月 日数 *  9 * 10 / 30  3    90px = 30日  [2004/     ]  [02/03     ]   9px
	 *      6 : ６ヶ月 日数 * 10 / 6  / 30  2    60px = 30日  [2004/ ]      [02/03 ]      10px
	 *      7 : １年   日数 *  9 / 10 / 90  1    90px = 90日  [2004/     ]  [02/03     ]   9px
	 *      8 : ２年   日数 *  9 / 10 /180  0.5  90px =180日  [2004/     ]  [02/03     ]   9px
	 *      9 : ３年   日数 * 10 / 6  /180  0.33 60px =180日  [2004/ ]      [02/03 ]      10px
	 *     10 : 週単位 日数 *  8 / 3  /  7  3.43 24px =  7日  [19W]         [12 ]          8px
	 *     11 : 予約済み(他物10件使用済み)
	 *     12 : 予約済み(他物 8件使用済み)
	 *     13 : 日(週) 日数 *  8 * 2       16    16px =  1日  [23]          [EE]           8px
	 *  ========================================================================================
	 *     20 :  1時間   時間 * 12 * 4        48 48px = 1時間 [02EE]        [07h ]        12px
	 *     21 :  1時間2  時間 * 12 * 2        24 24px = 1時間 [02]          [07]          12px
	 *     22 :  2時間   時間 * 12 * 4  /  2  24 48px = 2時間 [02EE]        [07h ]        12px
	 *     23 :  2時間2  時間 * 12 * 2  /  2  12 24px = 2時間 [02]          [07]          12px
	 *     24 :  4時間   時間 * 12 * 4  /  4  12 48px = 4時間 [02EE]        [07h ]        12px
	 *     25 :  4時間2  時間 * 12 * 2  /  4   6 24px = 4時間 [02]          [07]          12px
	 *     26 :  6時間   時間 * 12 * 4  /  6   8 48px = 6時間 [02EE]        [07h ]        12px
	 *     27 :  6時間2  時間 * 12 * 2  /  6   4 24px = 6時間 [02]          [07]          12px
	 *     28 :  8時間   時間 * 12 * 4  /  8   6 48px = 8時間 [02EE]        [07h ]        12px
	 *     29 :  8時間2  時間 * 12 * 2  /  8   3 24px = 8時間 [02]          [07]          12px
	 *     30 : 12時間   時間 * 12 * 4  / 12   4 48px =12時間 [02EE]        [07h ]        12px
	 *     31 : 12時間2  時間 * 12 * 2  / 12   2 24px =12時間 [02]          [07]          12px
	 *  ========================================================================================
	 *     40 : 積上(日)                    48   48px =  1日  [02/   ]      [23(EE)]       8px
	 *     41 : 積上(週)                    3.43 48px =  7日  [19W]         [12 ]          8px
	 *     42 : 積上(月) 月数 * 1            1   90px = 30日  [2004/     ]  [02/03     ]   9px
	 *     43 : 日単位ヘッダー予約済み
	 *     ～
	 *     49 : 日単位ヘッダー予約済み
	 *
	 * @og.rev 5.7.6.2 (2014/05/16) stackHeaderタグの互換機能として、DAY⇒40,WEEK⇒41,MONTH⇒42 対応する。
	 *
	 * @param	val ズーム変数(0～9,10,11,12,20～31,40～42)
	 */
	public void setZoom( final String val ) {
//		zoom = nval( getRequestParameter( val ),zoom );

		String zm = nval( getRequestParameter( val ),null );

		// 6.0.0.1 (2014/04/25) zoom の、DAY⇒40,WEEK⇒41,MONTH⇒42 対応
		if( ViewStackTableParam.STACK_ZOOM_DAY.equalsIgnoreCase( zm ) ) {
			zoom = 40;
		} else if( ViewStackTableParam.STACK_ZOOM_WEEK.equalsIgnoreCase( zm ) ) {
			zoom = 41;
		} else if( ViewStackTableParam.STACK_ZOOM_MONTH.equalsIgnoreCase( zm ) ) {
			zoom = 42;
		}
		else {
			zoom = nval( zm,zoom );
		}

		if( zoom < 0 || (13 < zoom && zoom < 20) || (31 < zoom && zoom < 40) || 42 < zoom ) {
			String errMsg = "ズーム変数は、(0～9,10,11,12,20～31,40～42)の範囲で指定してください。"
					+ " zoom=[" + val + "]" ;
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】DB検索するＤＢを指定します。
	 *
	 * @og.tag
	 * カレンダデータは、システムパラメータ の CalendarQuery_**** で
	 * 指定する、CalendarQuery クラスの QUERY 文で、実際に取得します。
	 * 上記の **** 部分に、ここで指定するキーワードを設定して置きます。
	 * 通常は、データベースID (GE13, ZY01 など)を指定します。
	 * このキーワードに対する実装クラスを、先のシステムパラメータ の
	 * キーワード以下に記述しておきます。
	 * {@og.doc03Link calDB CalendarQuery_****}
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) DB検索するＤＢのキー
	 *
	 * @param	db	DB検索するＤＢを指定
	 */
	public void setCalDB( final String db ) {
		calDB = nval( getRequestParameter( db ),calDB );
	}

	/**
	 * 【TAG】時間軸での休憩時間の開始-終了時刻をカンマ区切りで複数指定します。
	 *
	 * @og.tag
	 * 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、
	 * yyyyMMddHHmm-yyyyMMddHHmm形式で複数指定できます。
	 * これは、開始-終了というハイフン形式でつなげます。
	 * このセットを、カンマで複数指定できます。
	 * 例えば、200508201200-1245,200508201300-1315 という感じです。
	 * - の前後が、４桁の場合は、HHmm-HHmm 形式として、日付に関係なく、常にこの時分
	 * で休憩が入るという認識をします。つまり、開始は、12桁か、4桁の日付形式、
	 * 終了も、12桁か、4桁の日付形式になります。
	 *
	 * @og.rev 3.8.0.5 (2005/08/26) 新規追加
	 * @og.rev 3.8.0.7 (2005/09/20) 日付またがり追加追加
	 *
	 * @param	times	休憩時間の開始-終了時刻(CSV区切り)
	 */
	public void setBreakTimes( final String times ) {
		breakTimes = nval( getRequestParameter( times ),null );
	}

	/**
	 * 【TAG】時間軸での休憩時間の表示スタイルを設定します。
	 *
	 * @og.tag
	 * 通常は、ヘッダーのトップからの位置と、色です。
	 * それ以外にも、スタイルシート属性(キー:値;) というセットを指定できます。
	 * class="breakTime" を出力していますので、そちらを使用したい場合は、breakTimeStyleを無効化してください。
	 * そうしないと、こちらは、直接 style属性で設定しているので、強いです。
	 * 初期値は、top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60; です。
	 * IE8以下のために、filter:alpha(opacity=60); しています。
	 * 設定の後ろに、; を付ける様にしてください。
	 *
	 * @og.rev 3.8.0.5 (2005/08/26) 新規追加
	 *
	 * @param	style	休憩時間の表示スタイル
	 */
	public void setBreakTimeStyle( final String style ) {
		breakTimeStyle = nval( getRequestParameter( style ),breakTimeStyle );
	}

	/**
	 * 【TAG】時間軸でのベース時刻の開始時刻をカンマ区切りで複数指定します。
	 *
	 * @og.tag
	 * ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式で複数指定できます。
	 * このセットを、カンマで複数指定できます。
	 * 例えば、1700,200508201300 という感じです。
	 *
	 * @og.rev 5.6.1.2 (2013/02/22) 新規追加
	 *
	 * @param	times	ベース時刻の開始時刻(CSV区切り)
	 */
	public void setBaseTimes( final String times ) {
		baseTimes = nval( getRequestParameter( times ),null );
	}

	/**
	 * 【TAG】時間軸でのベース時刻の表示スタイルを設定します。
	 *
	 * @og.tag
	 * 通常は、ベース時刻の幅と、ヘッダーのトップからの位置と、色です。
	 * それ以外にも、スタイルシート属性(キー:値;) というセットを指定できます。
	 * 初期値は、top:20px;background-color:transparent;border-left:2px dashed red; です。
	 * 設定の後ろに、; を付ける様にしてください。
	 *
	 * @og.rev 5.6.1.2 (2013/02/22) 新規追加
	 *
	 * @param	style	ベース時刻の表示スタイル
	 */
	public void setBaseTimeStyle( final String style ) {
		baseTimeStyle = nval( getRequestParameter( style ),baseTimeStyle );
	}

	/**
	 * 【TAG】ＤＢ検索する場合の第１のキーを指定します。
	 *
	 * @og.tag
	 * 例えば、GE13, ZY01 では、事業所コード(CDJGS)を設定します。
	 * この値は、システムパラメータ の CalendarQuery_**** で
	 * 指定する、CalendarQuery クラスの QUERY 文に依存します。
	 * データベース定義の統一を望むところです。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) DB検索の第１キー(事業所コードなど)を追加
	 *
	 * @param	arg DB検索の第１キー(事業所コードなど)
	 */
	public void setArg1( final String arg ) {
		arg1 = nval( getRequestParameter( arg ),arg1 );
	}

	/**
	 * 【TAG】ＤＢ検索する場合の第２のキーを指定します。
	 *
	 * @og.tag
	 * 例えば、TP652 では、事業部コード(CDJGS) と 物件工程コード(CDKTEI)の２つの
	 * キーで、カレンダを取得します。(＋年月で、行を決定)
	 * 引数が、２つまで対応しています
	 * この値は、システムパラメータ の CalendarQuery_**** で
	 * 指定する、CalendarQuery クラスの QUERY 文に依存します。
	 * データベース定義の統一を望むところです。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) DB検索の第２キー(ＷＣコードなど)を追加
	 *
	 * @param	arg DB検索の第２キー(ＷＣコードなど)
	 */
	public void setArg2( final String arg ) {
		arg2 = nval( getRequestParameter( arg ),arg2 );
	}

	/**
	 * 【TAG】ＤＢ検索する場合の第３のキーを指定します。
	 *
	 * @og.tag
	 * この値は、システムパラメータ の CalendarQuery_**** で
	 * 指定する、CalendarQuery クラスの QUERY 文に依存します。
	 * データベース定義の統一を望むところです。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) DB検索の第３キーを追加
	 *
	 * @param	arg DB検索の第３キー
	 */
	public void setArg3( final String arg ) {
		arg3 = nval( getRequestParameter( arg ),arg3 );
	}

	/**
	 * 【TAG】ＤＢ検索する場合の第４のキーを指定します。
	 *
	 * @og.tag
	 * この値は、システムパラメータ の CalendarQuery_**** で
	 * 指定する、CalendarQuery クラスの QUERY 文に依存します。
	 * データベース定義の統一を望むところです。
	 *
	 * @og.rev 3.6.0.0 (2004/09/17) DB検索の第４キーを追加
	 *
	 * @param	arg DB検索の第４キー
	 */
	public void setArg4( final String arg ) {
		arg4 = nval( getRequestParameter( arg ),arg4 );
	}

	/**
	 * 【TAG】時間ガントで休日を表示する/しないを設定します
	 *		(初期値:USE_GANTTHEADER_SKIP_HOLIDAY[={@og.value org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_SKIP_HOLIDAY}])。
	 *
	 * @og.tag
	 * この値をfalseにすると、時間ガントでも休日が赤色で表示
	 * されるようになります。trueにした場合は、休日は表示されません。
	 * (初期値:システム定数のUSE_GANTTHEADER_SKIP_HOLIDAY[={@og.value org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_SKIP_HOLIDAY}])。
	 *
	 * @og.rev 4.0.0.0 (2007/09/07) 新規作成
	 *
	 * @param	skipHol	休日をスキップするかどうか。
	 * @see		org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_SKIP_HOLIDAY
	 */
	public void setSkipHoliday( final String skipHol) {
		skipHoliday = nval( getRequestParameter( skipHol ),skipHoliday );
	}

	/**
	 * 【TAG】時間ガントで２段組を使用する/しないを設定します
	 *		(初期値:USE_GANTTHEADER_MULTIPLE_COLUMN[={@og.value org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN}])。
	 *
	 * @og.tag
	 * ガントヘッダーにおいて、時間ヘッダーの上段に日付を、下段の時間軸の(h)の削除を行います。
	 * 日付は、表示開始時刻の上と、それの６時間ごとに表示します。
	 * (初期値:システム定数のUSE_GANTTHEADER_MULTIPLE_COLUMN[={@og.value org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN}])。
	 *
	 * @og.rev 5.6.1.2 (2013/02/22) 新規作成
	 *
	 * @param	multiClm	時間ガントで２段組を使用するかどうか(true:する/false:しない)。
	 * @see		org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN
	 */
	public void setUseMultiClm( final String multiClm ) {
		useMultiClm = nval( getRequestParameter( multiClm ),useMultiClm );
	}

	/**
	 * 日付、時刻の文字列を時間整数に変換します。
	 *
	 * 時間を扱う場合は、厄介なのは、時間と分の単位の違いです。
	 * 分に換算してしまうと、時間の取得に６０進数で扱う必要が出てきます。
	 * そこで、単純に時間に換算するのではなく、１時間を100として、
	 * 分を０から９９までの整数に換算して計算しています。
	 * これにより時間の足し算や引き算が可能になり、かつ、時間を求めるのに
	 * 100で割るだけで求めることが可能になります。
	 *
	 * @og.rev 5.6.1.2 (2013/02/22) 廃止
	 *
	 * @param	yy	時間の文字列
	 * @param	mm	分の文字列
	 *
	 * @return １時間を100として、分を０から９９までの整数に換算した値
	 */
//	private static int ym2int( final String yy,final String mm ) {
//		return (int)(Integer.parseInt( yy ) * 100 + Integer.parseInt( mm )*10.0/6.0 ) ;
//	}

	/**
	 * 日付、時刻の文字列を時間整数に変換します。
	 *
	 * 時間を扱う場合は、厄介なのは、時間と分の単位の違いです。
	 * 分に換算してしまうと、時間の取得に６０進数で扱う必要が出てきます。
	 * そこで、単純に時間に換算するのではなく、１時間を100として、
	 * 分を０から９９までの整数に換算して計算しています。
	 * これにより時間の足し算や引き算が可能になり、かつ、時間を求めるのに
	 * 100で割るだけで求めることが可能になります。
	 *
	 * ここでは、引数に、HHmm 、 HHmmss 、yyyyMMddHHmm 、yyyyMMddHHmmss 、null が扱えます。
	 * null の場合は、-1 を返します。
	 * yyyyMMdd 部分は、無視されます。
	 *
	 * @og.rev 5.6.1.2 (2013/02/22) 日付、秒、null 対応
	 *
	 * @param	hhmm	時分の文字列
	 *
	 * @return １時間を100として、分を０から９９までの整数に換算した値
	 */
	private static int hm2int( final String hhmm ) {
		int rtn = -1;

		if( hhmm != null ) {
			int len = hhmm.length();
			String hh = null;
			String mm = null;
			if( len == 4 || len == 6 ) {			// HHmm 、HHmmss
				hh = hhmm.substring( 0,2 );
				mm = hhmm.substring( 2,4 );
			}
			else if( len == 12 || len == 14 ) {		// yyyyMMddHHmm 、yyyyMMddHHmmss
				hh = hhmm.substring( 8,10 );
				mm = hhmm.substring( 10,12 );
			}
			else {
				String errMsg = "指定できる時間形式は、HHmm 、HHmmss 、yyyyMMddHHmm 、yyyyMMddHHmmss です。"
							+ HybsSystem.CR
							+ "hm2int=[" + hhmm + "]" ;
				throw new HybsSystemException( errMsg );
			}
			rtn = (int)(Integer.parseInt( hh ) * 100 + Integer.parseInt( mm )*10.0/6.0 ) ;
		}

		return rtn;
	}

	/**
	 * 休憩時間のデータを管理する内部クラスです。
	 *
	 * @og.rev 3.8.0.7 (2005/09/20) 内部クラス新規作成
	 * @og.group 画面部品
	 *
	 * @version  4.0
	 * @author	Kazuhiko Hasegawa
	 * @since    JDK5.0,
	 */
	private static class BreakTimeData {
		private final String startDay	;		// 開始日付。null の場合は、毎日
		private final int	 startTime	;		// 開始時刻のhm2int変換済み値
		private final int	 timeSpan	;		// 開始時刻と終了時刻の時間差(hm2int変換済み)
		private final String viewTime	;		// ツールチップ表示用の文字列(HHmm-HHmm)

		/**
		 * コンストラクター
		 *
		 * 開始日付(startDay)、開始時刻(startTime)、時間差(timeSpan)、表示ラベル(viewTime)
		 * を指定して、休憩時間のデータオブジェクトを構築します。
		 * 開始日付(startDay)は、null の場合は、毎日、つまり、定常的な休憩時刻として
		 * 認識します。日付が指定された場合は、その日のみの特別な休憩時間と認識します。
		 * 開始時刻は、hm2int変換済み値で、１時間が100となり、分は、10進数に変換されている
		 * 値として認識します。7：30 の場合は、750 という値になります。
		 * 開始時刻と終了時刻の時間差(timeSpan)も hm2int変換済み値です。
		 * 表示用の文字列(viewTime)は、休憩時間の HTML表記時の title 属性として
		 * 設定される為、マウスオーバー時のツールチップに現れます。
		 *
		 * @param	startDay	yyyyMMdd 形式の開始日付。null の場合は、毎日
		 * @param	startTime	開始時刻のhm2int変換済み値
		 * @param	timeSpan 	開始時刻と終了時刻の時間差(hm2int変換済み)
		 * @param	viewTime	ツールチップ表示用の文字列(HHmm-HHmm)
		 */
		BreakTimeData( final String startDay,final int startTime,final int timeSpan,final String viewTime ) {
			this.startDay	= startDay;
			this.startTime	= startTime;
			this.timeSpan	= timeSpan;
			this.viewTime	= viewTime;
		}

		/**
		 * 指定の日付と時刻が、この BreakTimeData の開始日時とマッチするかどうかをチェックします。
		 *
		 * 開始日時とマッチするとは、内部日付がマッチし、開始時刻が、指定の time の
		 * １時間(+100)*stepの範囲に含まれている場合を指します。(true を返します。)
		 * 内部の日付(startDay)が null の場合は、毎日が対象となります。
		 * 開始時刻がマッチした場合は、timeSpan 分だけの幅を持った休憩時間を認識します。
		 * 境界条件の都合で、timeSpan == 0 の状態も存在しますが、これはマッチしないと判断します。
		 *
		 * @og.rev 3.8.1.1 (2005/11/21) timeSpan が 0 より大きい場合 条件追加
		 * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
		 *
		 * @param	inDay	yyyyMMdd 形式の日付。
		 * @param	time	休憩時間の開始時刻のhm2int変換済み値
		 * @param	step	時間間隔
		 * @return 含まれる(対象)場合は、true そうでない場合は、false
		 */
//		boolean startsWith( final String inDay,final int time ) {
		boolean startsWith( final String inDay,final int time,final int step ) {
			return ( timeSpan > 0 &&
					 time <= startTime &&
					 startTime < time+100*step &&
					 ( startDay == null || inDay.equals( startDay ) ) );
		}

		/**
		 * 休憩時間を表す SPANタグを作成します。
		 *
		 * １時間=hourOfPixcel(px) で換算します。分は、すでに分数計算(hm2int)済み
		 *
		 * @og.rev 3.8.8.4 (2007/02/17) class="breaktime"  追加
		 * @og.rev 5.6.1.2 (2013/02/22) ベース時刻対応。width が 0 の場合は、2 をセット
		 *
		 * @param	offset	表示開始ピクセル数(実質表示日数 * １日分のピクセル - オフセット)
		 * @param	hourOfPixcel	１時間あたりのピクセル数
		 * @param	breakTimeStyle	休憩時間の指定に追加するスタイル属性
		 * @return 休憩時間を表す SPANタグ
		 */
		String getBreakTime( final int offset,final int hourOfPixcel,final String breakTimeStyle ) {
			int left  = offset + (startTime*hourOfPixcel/100) ;
			int width = (timeSpan*hourOfPixcel/100) ;
			if( width == 0 ) { width = 2; }		// 5.6.1.2 (2013/02/22) ベース時刻対応。width が 0 の場合は、2 をセット

			return "<span class=\"breaktime\" title=\"" + viewTime + "\""
					+ " style=\"position:absolute;z-index:100;height:500000px;"
					+ "left:"	+ left	+ "px;"
					+ "width:"	+ width	+ "px;"
					+ breakTimeStyle	+ "\" ></span>"
					+ HybsSystem.CR ;
		}
	}

	/**
	 * 休憩時間を管理する内部クラスです。
	 * 
	 * 内部的に、休憩時間以外に、ベース時刻も処理できるようにします。
	 * これは、終了時刻を指定されていない場合でも対応できるようにすることを意味します。
	 * また、時間指定方法を、時分だけでなく、時分秒指定時でも処理できるようにします。（秒は無視）
	 *
	 * @og.rev 3.8.0.7 (2005/09/20) 内部クラスBreakTimeDataを使用するように修正
	 * @og.rev 3.8.1.6 (2006/04/25) 変数の final 化
	 * @og.rev 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
	 *
	 * @og.group 画面部品
	 *
	 * @version  4.0
	 * @author	Kazuhiko Hasegawa
	 * @since    JDK5.0,
	 */
	private static class BreakTimes {
		private final List<BreakTimeData>	timeList	= new ArrayList<BreakTimeData>();
		private final int		hourOfPixcel	; // １時間あたりのピクセル数(例:TIME_PIXEL)
		private final String	breakTimeStyle	; // 休憩時間の指定に追加するスタイル属性
		private final int		viewStartTime	; // 数値化(hm2int)された表示開始時刻(例:0700)
		private final int		viewEndTime		; // 数値化(hm2int)された表示終了時刻(例:2000)

		/**
		 * コンストラクター
		 * 必要な情報を設定して、オブジェクトを構築します。
		 * 表示終了時刻は、表示開始時刻 >= 表示終了時刻 の場合、2400加算されている。
		 *
		 * @og.rev 3.8.0.7 (2005/09/20) breakTimesの日付またがり追加
		 * @og.rev 3.8.1.1 (2005/11/21) timeSpan の計算方法を見直し
		 * @og.rev 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
		 *
		 * @param	hOfpx	１時間あたりのピクセル数
		 * @param	breakTimes	休憩時間を、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-yyyyMMddHHmm形式で指定します。
		 * @param	style	休憩時間の指定に追加するスタイル属性
		 * @param	vStartTime	数値化(hm2int)された表示開始時刻
		 * @param	vEndTime	数値化(hm2int)された表示終了時刻
		 */
		BreakTimes( final int hOfpx,final String breakTimes,final String style,
					final int vStartTime,final int vEndTime ) {
			hourOfPixcel	= hOfpx;
			breakTimeStyle	= ( style == null ) ? "" : style ;
			viewStartTime	= vStartTime;
			viewEndTime		= vEndTime;
			boolean time24		= ( viewEndTime > 2400 );	// 3.8.1.1 (2005/11/21) 開始終了が逆転している場合 true

		 	// 3.8.1.1 (2005/11/21) timeSpan の計算方法を見直し
			DateFormat format = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
			String[] startEnds = StringUtil.csv2Array( breakTimes );
			int len = startEnds.length;

			String	startDay	;		// null の場合は、毎日
			String	endDay		;		// 一時変数
			int		startTime	;		// 開始時刻のhm2int変換済み値
			int		endTime		;		// 終了時刻のhm2int変換済み値
			int		timeSpan	;		// 開始時刻と終了時刻の時間差(hm2int変換済み値)
			String	viewTime	;		// ツールチップ表示用の文字列(HH:mm-HH:mm)

			Calendar str ;
			Calendar end ;

			for( int i=0; i<len; i++ ) {
				String startEnd = startEnds[i];
				if( startEnd != null ) {
					// startEnd	= "0700ss-2000ss";						// 開始-終了時刻(HHmm-HHmm)
					// startEnd	= "200508200700ss-2000ss";				// 開始-終了時刻(yyyyMMddHHmm-HHmm)
					// startEnd	= "200508200700ss-200508212000ss";		// 開始-終了時刻(yyyyMMddHHmm-yyyyMMddHHmm)

					// 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
					int idx = startEnd.indexOf( '-' );	// ハイフンを見つける。
					if( idx > 0 ) {
						String st = startEnd.substring( 0,idx );
						String ed = startEnd.substring( idx+1 );

						startDay	= (st.length() >= 8) ? st.substring( 0,8 ) : null ;		// ８ケタ以上で、yyyyMMdd 取得
						endDay	 	= (ed.length() >= 8) ? ed.substring( 0,8 ) : null ;		// ８ケタ以上で、yyyyMMdd 取得
						startTime	= hm2int( st );
						endTime		= hm2int( ed );
					}
					// startEnd	= "0700ss";						// 開始時刻(HHmm)
					// startEnd	= "200508200700ss";				// 開始時刻(yyyyMMddHHmm)
					// startEnd	= "200508200700ss";				// 開始時刻(yyyyMMddHHmm)
					else {
						String st = startEnd;
						startDay	= (st.length() >= 8) ? st.substring( 0,8 ) : null ;		// ８ケタ以上で、yyyyMMdd 取得
						endDay	 	= null ;
						startTime	= hm2int( st );
						endTime		= startTime + 1;										// 差分を出すため、startTime に 1 だけ加算
					}

					// 5.6.1.2 (2013/02/22) 処理見直し
//					// startEnd	= "0700-2000";	// 開始-終了時刻(HHmm-HHmm)
//					if( startEnd.length() == 9 && startEnd.charAt(4) == '-' ) {
//						startDay	= null;
//						endDay		= null;
//						startTime	= ym2int( startEnd.substring( 0,2 ),startEnd.substring( 2,4 ) );
//						endTime		= ym2int( startEnd.substring( 5,7 ),startEnd.substring( 7 ) );
//					}
//					// startEnd	= "200508200700-2000";	// 開始-終了時刻(yyyyMMddHHmm-HHmm)
//					else if( startEnd.length() == 17 && startEnd.charAt(12) == '-' ) {
//						startDay	= startEnd.substring( 0,8 );
//						endDay		= null;
//						startTime	= ym2int( startEnd.substring( 8,10  ),startEnd.substring( 10,12 ) );
//						endTime		= ym2int( startEnd.substring( 13,15 ),startEnd.substring( 15 ) );
//					}
//					// startEnd	= "200508200700-200508212000";	// 開始-終了時刻(yyyyMMddHHmm-yyyyMMddHHmm)
//					else if( startEnd.length() == 25 && startEnd.charAt(12) == '-' ) {
//						startDay	= startEnd.substring( 0,8 );
//						endDay		= startEnd.substring( 13,21 );
//						startTime	= ym2int( startEnd.substring( 8,10  ),startEnd.substring( 10,12 ) );
//						endTime		= ym2int( startEnd.substring( 21,23 ),startEnd.substring( 23 ) );
//					}
//					else {
//						String errMsg = "休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-yyyyMMddHHmm形式です。"
//									+ HybsSystem.CR
//									+ "breakTimes=[" + breakTimes + "] Bad=[" + startEnd + "]" ;
//						throw new HybsSystemException( errMsg );
//					}

					str = null;
					end = null;
					if( startDay != null ) { str = HybsSystem.getCalendar( startDay ); }
					if( endDay   != null ) { end = HybsSystem.getCalendar( endDay   ); }

					// 表示終了時刻 が 2400 より大きい場合、表示開始時刻 >= 表示終了時刻 である。
					if( time24 ) {
						// 開始時刻 <  表示終了時刻 => 開始時刻に2400加算する。
						if( startTime < viewEndTime-2400 ) {
							if( str != null ) {
								str.add(Calendar.DATE, -1 );	// -1 日しておく
								startDay = format.format( str.getTime() );
							}
							startTime += 2400;
						}

						// 終了時刻 <= 表示終了時刻 => 終了時刻に2400加算する。
						if( endTime <= viewEndTime-2400 ) {
							if( end != null ) {
								end.add(Calendar.DATE, -1 );	// -1 日しておく
								endDay = format.format( end.getTime() );
							}
							endTime += 2400;
						}
					}

					// 3.8.1.1 (2005/11/21) 判定条件修正
					// 開始時刻 < 表示開始時刻 => 開始時刻に表示開始時刻をセット。
					if( startTime < viewStartTime ) { startTime = viewStartTime; }

					// 開始時刻 > 表示終了時刻 => 開始時刻に表示終了時刻をセット。
					if( startTime > viewEndTime ) { startTime = viewEndTime; }

					// 終了時刻 < 表示開始時刻 => 終了時刻に表示開始時刻をセット。
					if( endTime < viewStartTime ) { endTime = viewStartTime; }

					// 終了時刻 > 表示終了時刻 => 終了時刻に表示終了時刻をセット。
					if( endTime > viewEndTime ) { endTime = viewEndTime; }
					timeSpan = endTime - startTime ;
					viewTime = startEnd ;
				}
				// null の場合は、カンマが連続したり、最後に余分に付いたケースなので、無視する。
				else {
					continue;
				}

				// 終了日が入っていないか、開始日と終了日が同じ日の場合。
				if( timeSpan >= 0 && (
					endDay == null || ( startDay != null && startDay.equals( endDay ) ) ) ) {
						timeSpan = endTime - startTime ;
						timeList.add( new BreakTimeData( startDay,startTime,timeSpan,viewTime ) );
				}
				else {
					// 終了日が入っていると複数日に分かれているので、分解する必要がある。

					// 初日の timeSpan は、startTime から viewEndTime まで
					timeSpan = viewEndTime - startTime ;
					timeList.add( new BreakTimeData( startDay,startTime,timeSpan,viewTime ) );

					// 最終日の timeSpan は、viewStartTime から endTime まで
					timeSpan = endTime - viewStartTime ;
					timeList.add( new BreakTimeData( endDay,viewStartTime,timeSpan,viewTime ) );

					// 中日の timeSpan は、viewStartTime から viewEndTime まで
					timeSpan = viewEndTime - viewStartTime ;
					if( str != null && end != null ) {
						str.add(Calendar.DATE, 1 );		// +1 日しておく
						while( str.before( end ) ) {	// 終了時間は、「含まない」仕様
							Date dt = str.getTime();
							String tempStartDay = format.format( dt );
							timeList.add( new BreakTimeData( tempStartDay,viewStartTime,timeSpan,viewTime ) );
							str.add(Calendar.DATE, 1);
						}
					}
				}
			}
		}

		/**
		 * その日のその時間の休憩時間を表す SPANタグ群(複数ありうる)を作成します。
		 *
		 * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
		 *
		 * @param	offset	表示開始ピクセル数(実質表示日数 * １日分のピクセル - オフセット)
		 * @param day Calendar 処理すべき日付のカレンダ
		 * @param	time	処理すべき時間
		 * @param	step	時間間隔
		 * @return その日のその時間の休憩時間を表す SPANタグ群(複数ありうる)
		 */
//		String makeSpan( final int offset,final Calendar day,final int time ) {
		String makeSpan( final int offset,final Calendar day,final int time,final int step ) {
			DateFormat format1 = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
			String inDay = format1.format( day.getTime() );

			StringBuilder buf = new StringBuilder();
			int size = timeList.size();
			for( int i=0; i<size; i++ ) {
				BreakTimeData timeData = timeList.get(i);
//				if( timeData.startsWith( inDay,time ) ) {
				if( timeData.startsWith( inDay,time,step ) ) {
					buf.append( timeData.getBreakTime( offset,hourOfPixcel,breakTimeStyle ) );
				}
			}

			String rtn = null;

			if( buf.length() > 0 ) { rtn = buf.toString(); }
			return rtn;
		}
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 */
	@Override
	public String toString() {
		return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
				.println( "VERSION"			,VERSION		)
				.println( "startDate"		,startDate		)
				.println( "endDate"			,endDate		)
				.println( "daySpan"			,daySpan		)
				.println( "zoom"			,zoom			)
				.println( "breakTimes"		,breakTimes		)
				.println( "breakTimeStyle"	,breakTimeStyle	)
				.println( "baseTimes"		,baseTimes		)		// 5.6.1.2 (2013/02/22) ベース時刻
				.println( "baseTimeStyle"	,baseTimeStyle	)		// 5.6.1.2 (2013/02/22) ベース時刻スタイル
				.println( "calDB"			,calDB			)
				.println( "arg1"			,arg1			)
				.println( "arg2"			,arg2			)
				.println( "arg3"			,arg3			)
				.println( "arg4"			,arg4			)
				.println( "skipHoliday"		,skipHoliday	)
				.println( "TIME_PIXEL" 		,TIME_PIXEL 	)
				.println( "Other..."		,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
