// Copyright (C) 2007 panacoran <panacoran@users.sourceforge.jp>
// 
// This program is part of Protra.
//
// Protra 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/>.
// 
// $Id: Utils.cs 406 2011-01-06 12:59:28Z panacoran $

using System;

namespace Protra.Lib
{
	/// <summary>
	/// ユーティリティ関数を提供する。
	/// </summary>
	public class Utils
	{
		/// <summary>
		/// 指定された日付に市場が開いているかを返す。
		/// </summary>
		/// <param name="d">日付を指定する。</param>
		/// <returns></returns>
		public static bool IsMarketOpen(DateTime d)
		{
			// 土日
			if (d.DayOfWeek == DayOfWeek.Saturday ||
				d.DayOfWeek == DayOfWeek.Sunday)
				return false;
			// 年末年始
			if ((d.Month == 12 && d.Day == 31) ||
				(d.Month == 1 && d.Day <= 3))
				return false;		
			return !IsHoliday(d);
		}

		/// <summary>
		/// 指定された日付が週の最後の開場日かを返す。
		/// </summary>
		/// <param name="d"></param>
		/// <returns></returns>
		public static bool IsLastOpenDateOfWeek(DateTime d)
		{
			for (d = d.AddDays(1); d.DayOfWeek < DayOfWeek.Saturday; d = d.AddDays(1))
				if (IsMarketOpen(d))
					return false;
			return true;
		}

		static bool IsHoliday(DateTime d)
		{
			// 動かない休日
			if ((d.Month == 1 && d.Day == 1) ||
				(d.Month == 2 && d.Day == 11) ||
				(d.Month == 4 && d.Day == 29) ||
				(d.Month == 5 && (d.Day >= 3 && d.Day <= 5)) ||
				(d.Month == 11 && (d.Day == 3 || d.Day == 23)) ||
				(d.Month == 12 && d.Day == 23))
				return true;
			// 春分と秋分(1980〜2099年に対応)
			if (d.Month == 3 &&
				d.Day == (int)(20.8431 + 0.242194 * (d.Year - 1980) - (d.Year -1980) / 4))
				return true;
			if (d.Month == 9 &&
				d.Day == (int)(23.2488 + 0.242194 * (d.Year - 1980) - (d.Year -1980) / 4))
				return true;
			// ハッピーマンデー
			if (d.Year < 2000)
			{
				if ((d.Month == 1 && d.Day == 15) ||
					(d.Month == 10 && d.Day == 10))
					return true;
			}
			else
			{
                if ((d.Month == 1 || d.Month == 10) &&
                    (d.Day >= 8 && d.Day <= 14) && d.DayOfWeek == DayOfWeek.Monday)
                    return true;
			}
			if (d.Year < 2003)
			{
				if ((d.Month == 7 && d.Day == 20) ||
					(d.Month == 9 && d.Day == 15))
					return true;
			}
			else
			{
                if ((d.Month == 7 || d.Month == 9) &&
                    (d.Day >= 15 && d.Day <= 21) && d.DayOfWeek == DayOfWeek.Monday)
                    return true;
                // シルバーウィーク
                if (d.Month == 9 && (d.Day == 21 || d.Day == 22) && d.DayOfWeek == DayOfWeek.Tuesday)
                    return IsHoliday(d.AddDays(1));
			}
			// 5月4日が国民の祝日になったので、振替休日が二日以上繰り越す。
			if (d.Year > 2007 && d.Month == 5 && d.Day == 6)
				return d.DayOfWeek >= DayOfWeek.Monday &&
					d.DayOfWeek <= DayOfWeek.Wednesday;
			// 振り替え休日
			if (d.DayOfWeek == DayOfWeek.Monday)
				return IsHoliday(d.AddDays(-1));
			return false;
		}
	}
}
