/*
 * Copyright (c) 2009 KMS
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *  
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * $Author: h-kawase $
 * $Date: 2009-02-27 17:50:11 +0900 (金, 27 2 2009) $
 * $Rev: 558 $
 * 
 * 
 * 例1：単純な使用
 * 
 * var holiday = new Holiday();
 * var test = new Date("2009/02/11");
 * var holidayName = holiday.getHolidayName(test); // "建国記念の日"
 * 
 * 
 * 例2：任意の祝日を設定
 * 
 * {祝日名: Date, 祝日名:Date, ... }の形式でオブジェクトとして登録する。
 * 任意に設定した祝日は、通常の祝日よりも優先される。
 * 
 * var myHoliday = {
 *     "KMS設立記念日": new Date("2008/04/01")
 * }
 * 
 * var holiday = new Holiday(myHoliday); // holiday.customHolidays = myHoliday;
 * var test = new Date("2008/04/01");
 * var holidayName = holiday.getHolidayName(test); // "KMS設立記念日"
 */

var Holiday = function(customHolidays) {
	this.customHolidays = customHolidays || {};
}

Holiday.prototype = {
	FURIKAE_START : new Date("1973/04/12").getTime(),

	customHolidays : {},

	getHolidayName : function(argDate) {
		var holidayName = this._getHolidayNameIncomplete(argDate);

		if (holidayName == null) {
			if (argDate.getDay() == 1 && argDate.getTime() >= this.FURIKAE_START) {
				var yesterDay = new Date(argDate.getFullYear(), argDate.getMonth(), argDate.getDate() - 1);
				var tempHoliday = this._getHolidayNameIncomplete(yesterDay);

				if (tempHoliday != null) {
					return "振替休日";
				}
			}
		}

		for ( var name in this.customHolidays) {
			if (argDate.getTime() == this.customHolidays[name].getTime()) {
				return name;
			}
		}

		return holidayName;
	},

	_getHolidayNameIncomplete : function(argDate) {
		var year = argDate.getFullYear();
		var month = argDate.getMonth() + 1;
		var date = argDate.getDate();
		var dayOfWeek = argDate.getDay();
		var weekNumOfMonth = Math.floor((date - 1) / 7) + 1;

		switch (month) {
		case 1:
			if (date == 1) {
				return "元日";
			} else {
				if (year >= 2000) {
					if (weekNumOfMonth == 2 && dayOfWeek == 1) {
						return "成人の日";
					}
				} else if (date == 15) {
					return "成人の日";
				}
			}
			break;
		case 2:
			if (date == 11 && year >= 1967) {
				return "建国記念の日";
			}
			break;
		case 3:
			if (date == this.getSpringEquinoxDayOfMonth(year)) {
				return "春分の日";
			}
		break;
		case 4:
			if (date == 29) {
				if (year >= 2007) {
					return "昭和の日";
				} else if (year >= 1989) {
					return "みどりの日";
				} else {
					return "天皇誕生日";
				}
			}
			break;
		case 5:
			switch (date) {
			case 3:
				return "憲法記念日";
				break;
			case 4:
				if (year >= 2007) {
					return "みどりの日";
				} else if (year >= 1986 && dayOfWeek > 1) {
					return "国民の休日";
				}
				break;
			case 5:
				return "こどもの日";
				break;
			case 6:
				if (year >= 2007 && (dayOfWeek == 2 || dayOfWeek == 3)) {
					return "振替休日";
				}
				break;
			}
			break;
		case 6:
			break;
		case 7:
			if (year >= 2003) {
				if (weekNumOfMonth == 3 && dayOfWeek == 1) {
					return "海の日";
				}
			} else {
				if (year >= 1996 && date == 20) {
					return "海の日";
				}
			}
			break;
		case 9:
			autumnEquinox = this.getAutumnEquinoxDayOfMonth(year);

			if (date == autumnEquinox) {
				return "秋分の日";
			} else {
				if (year >= 2003) {
					if (weekNumOfMonth == 3 && dayOfWeek == 1) {
						return "敬老の日";
					} else if (dayOfWeek == 2 && date == (autumnEquinox - 1)) {
						return "国民の休日";
					}
				} else if (year >= 1966 && date == 15) {
					return "敬老の日";
				}
			}
			break;
		case 10:
			if (year >= 2000) {
				if (weekNumOfMonth == 2 && dayOfWeek == 1) {
					return "体育の日";
				}
			} else if (year >= 1966 && date == 10) {
				return "体育の日";
			}
			break;
		case 11:
			if (date == 3) {
				return "文化の日";
			} else if (date == 23) {
				return "勤労感謝の日";
			}
			break;
		case 12:
			if (date == 23 && year >= 1989) {
				return "天皇誕生日";
			}
			break;
		}

		return null;
	},

	getSpringEquinoxDayOfMonth : function(year) {
		if (year <= 1947) {
			return null;
		} else if (year <= 1979) {
			return Math.floor(20.8357 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else if (year <= 2099) {
			return Math.floor(20.8431 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else if (year <= 2150) {
			return Math.floor(21.851 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else {
			return null;
		}
	},

	getAutumnEquinoxDayOfMonth : function(year) {
		if (year <= 1947) {
			return null;
		} else if (year <= 1979) {
			return Math.floor(23.2588 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else if (year <= 2099) {
			return Math.floor(23.2488 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else if (year <= 2150) {
			return Math.floor(24.2488 + (0.242194 * (year - 1980)) - Math.floor((year - 1980) / 4));
		} else {
			return null;
		}
	}
}
