// System.Globalization.DateTimeFormatInfo
//
// Some useful functions are missing in the ECMA specs.
// They have been added following MS SDK Beta2
//
// Martin Weindel (martin.weindel@t-online.de)
//
// (C) Martin Weindel (martin.weindel@t-online.de)

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// 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.
//

using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;

namespace System.Globalization
{
#if NET_2_0
	[Flags]
	enum DateTimeFormatFlags {
		Unused,
		But,
		Serialized,
		By,
		Microsoft
	}
#endif

	[Serializable]
#if NET_2_0
	[ComVisible (true)]
#endif
	public sealed class DateTimeFormatInfo : ICloneable, IFormatProvider {
		private static readonly string MSG_READONLY = "This instance is read only";
		private static readonly string MSG_ARRAYSIZE_MONTH = "An array with exactly 13 elements is needed";
		private static readonly string MSG_ARRAYSIZE_DAY = "An array with exactly 7 elements is needed";
		private static readonly string[] INVARIANT_ABBREVIATED_DAY_NAMES
			= new string[7] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
		private static readonly string[] INVARIANT_DAY_NAMES
			= new string[7] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
		private static readonly string[] INVARIANT_ABBREVIATED_MONTH_NAMES
			= new string[13] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
		private static readonly string[] INVARIANT_MONTH_NAMES
			= new string[13] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""};
		private static readonly string[] INVARIANT_ERA_NAMES = {"A.D."};
#if NET_2_0
		static readonly string [] INVARIANT_SHORT_DAY_NAMES =
			new string [7] {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"};
#endif
		private static DateTimeFormatInfo theInvariantDateTimeFormatInfo;

		private const string _RoundtripPattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";

		//
		// BIG FAT WARNING:
		//
		// DO NOT ALTER THE NAME OR ORDER OF THESE FIELDS
		// AND DO NOT INSERT ANY VARIABLES ANYWHERE BUT AT THE END
		// SINCE MONO RELIES ON THE ORDER AND ON THE NAMES
		// see mono/mono/metadata/verify.c
		//
		private bool m_isReadOnly;
		private string amDesignator;
		private string pmDesignator;
		private string dateSeparator;
		private string timeSeparator;
		private string shortDatePattern;
		private string longDatePattern;
		private string shortTimePattern;
		private string longTimePattern;
		private string monthDayPattern;
		private string yearMonthPattern;
		private string fullDateTimePattern;
		private string _RFC1123Pattern;
		private string _SortableDateTimePattern;
		private string _UniversalSortableDateTimePattern;
		private int firstDayOfWeek;
		private Calendar calendar;
		private int calendarWeekRule;
		private string[] abbreviatedDayNames;
		private string[] dayNames;
		private string[] monthNames;
		private string[] abbreviatedMonthNames;

		// FIXME: not supported other than invariant
		private string [] allShortDatePatterns;
		private string [] allLongDatePatterns;
		private string [] allShortTimePatterns;
		private string [] allLongTimePatterns;
		private string [] monthDayPatterns;
		private string [] yearMonthPatterns;
		private string [] shortDayNames;

		//
		// END OF BIG FAT WARNING
		//

		// MS Serialization needs this
		private int nDataItem;
		private bool m_useUserOverride;
		private bool m_isDefaultCalendar;
		private int CultureID;
		private bool bUseCalendarInfo;
		private string generalShortTimePattern;
		private string generalLongTimePattern;
		private string[] m_eraNames;
		private string[] m_abbrevEraNames;
		private string[] m_abbrevEnglishEraNames;
		private string[] m_dateWords;
		private int[] optionalCalendars;
#if NET_2_0
		private string[] m_superShortDayNames;
		private string[] genitiveMonthNames;
		private string[] m_genitiveAbbreviatedMonthNames;
		private string[] leapYearMonthNames;
		private DateTimeFormatFlags formatFlags;
		private string m_name; // Unused, but MS.NET serializes this
#endif

		public DateTimeFormatInfo()
		{
			m_isReadOnly = false;
			amDesignator = "AM";
			pmDesignator = "PM";
			dateSeparator = "/";
			timeSeparator = ":";
			shortDatePattern = "MM/dd/yyyy";
			longDatePattern = "dddd, dd MMMM yyyy";
			shortTimePattern = "HH:mm";
			longTimePattern = "HH:mm:ss";
			monthDayPattern = "MMMM dd";
			yearMonthPattern = "yyyy MMMM";
			fullDateTimePattern = "dddd, dd MMMM yyyy HH:mm:ss";

			// FIXME: for the following three pattern: "The
			// default value of this property is derived
			// from the calendar that is set for
			// CultureInfo.CurrentCulture or the default
			// calendar of CultureInfo.CurrentCulture."

			// Actually, no predefined culture has different values
			// than those default values.

			_RFC1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"; 
			_SortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
			_UniversalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";

			firstDayOfWeek = (int)DayOfWeek.Sunday;
			calendar = new GregorianCalendar();
			calendarWeekRule = (int)CalendarWeekRule.FirstDay;

			abbreviatedDayNames = INVARIANT_ABBREVIATED_DAY_NAMES;
			dayNames = INVARIANT_DAY_NAMES;
			abbreviatedMonthNames = INVARIANT_ABBREVIATED_MONTH_NAMES;
			monthNames = INVARIANT_MONTH_NAMES;
#if NET_2_0
			shortDayNames = INVARIANT_SHORT_DAY_NAMES;
#endif
		}
				
		public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
		{
			if (provider != null) {
				DateTimeFormatInfo dtfi;
				dtfi = (DateTimeFormatInfo)provider.GetFormat(typeof(DateTimeFormatInfo));
				if (dtfi != null)
					return dtfi;
			}
			
			return CurrentInfo;
		}

		public bool IsReadOnly {
			get {
				return m_isReadOnly;
			}
		}

		public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
		{
			DateTimeFormatInfo copy = (DateTimeFormatInfo)dtfi.Clone();
			copy.m_isReadOnly = true;
			return copy;
		}			

		public object Clone () 
		{
			DateTimeFormatInfo clone = (DateTimeFormatInfo) MemberwiseClone();
			// clone is not read only
			clone.m_isReadOnly = false;
			return clone;
		}

		public object GetFormat(Type formatType)
		{
			return (formatType == GetType()) ? this : null;
		}

		public string GetAbbreviatedEraName (int era)
		{
			if (era < 0 || era >= calendar.AbbreviatedEraNames.Length)
				throw new ArgumentOutOfRangeException ("era", era.ToString ());
			return calendar.AbbreviatedEraNames [era];
		}

		public string GetAbbreviatedMonthName(int month)
		{
			if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
			return abbreviatedMonthNames[month-1];
		}

		public int GetEra (string eraName)
		{
			if (eraName == null)
				throw new ArgumentNullException ();
			string [] eras = calendar.EraNames;
			for (int i = 0; i < eras.Length; i++)
				if (CultureInfo.InvariantCulture.CompareInfo
					.Compare (eraName, eras [i],
					CompareOptions.IgnoreCase) == 0)
					return calendar.Eras [i];
			
			eras = calendar.AbbreviatedEraNames;
			for (int i = 0; i < eras.Length; i++)
				if (CultureInfo.InvariantCulture.CompareInfo
					.Compare (eraName, eras [i],
					CompareOptions.IgnoreCase) == 0)
					return calendar.Eras [i];
			
			return -1;
		}

		public string GetEraName (int era)
		{
			if (era < 0 || era > calendar.EraNames.Length)
				throw new ArgumentOutOfRangeException ("era", era.ToString ());
			return calendar.EraNames [era - 1];
		}

		public string GetMonthName(int month)
		{
			if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
			return monthNames[month-1];
		}

		public string[] AbbreviatedDayNames
		{
			get { return (string[]) RawAbbreviatedDayNames.Clone (); }
			set { RawAbbreviatedDayNames = value; }
		}

		internal string[] RawAbbreviatedDayNames
		{
			get
			{
				return abbreviatedDayNames;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
				abbreviatedDayNames = (string[]) value.Clone();
			}
		}

		public string[] AbbreviatedMonthNames
		{
			get { return (string[]) RawAbbreviatedMonthNames.Clone (); }
			set { RawAbbreviatedMonthNames = value; }
		}

		internal string[] RawAbbreviatedMonthNames
		{
			get
			{
				return abbreviatedMonthNames;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
				abbreviatedMonthNames = (string[]) value.Clone();
			}
		}

		public string[] DayNames
		{
			get { return (string[]) RawDayNames.Clone (); }
			set { RawDayNames = value; }
		}

		internal string[] RawDayNames
		{
			get
			{
				return dayNames;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
				dayNames = (string[]) value.Clone();
			}
		}

		public string[] MonthNames
		{
			get { return (string[]) RawMonthNames.Clone (); }
			set { RawMonthNames = value; }
		}

		internal string[] RawMonthNames
		{
			get
			{
				return monthNames;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
				monthNames = (string[]) value.Clone();
			}
		}

		public string AMDesignator
		{
			get
			{
				return amDesignator;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				amDesignator = value;
			}
		}

		public string PMDesignator
		{
			get
			{
				return pmDesignator;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				pmDesignator = value;
			}
		}

		public string DateSeparator
		{
			get
			{
				return dateSeparator;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				dateSeparator = value;
			}
		}

		public string TimeSeparator
		{
			get
			{
				return timeSeparator;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				timeSeparator = value;
			}
		}

		public string LongDatePattern
		{
			get
			{
				return longDatePattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				longDatePattern = value;
			}
		}

		public string ShortDatePattern
		{
			get
			{
				return shortDatePattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				shortDatePattern = value;
			}
		}

		public string ShortTimePattern
		{
			get
			{
				return shortTimePattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				shortTimePattern = value;
			}
		}

		public string LongTimePattern
		{
			get
			{
				return longTimePattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				longTimePattern = value;
			}
		}

		public string MonthDayPattern
		{
			get
			{
				return monthDayPattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				monthDayPattern = value;
			}
		}

		public string YearMonthPattern
		{
			get
			{
				return yearMonthPattern;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				yearMonthPattern = value;
			}
		}

		public string FullDateTimePattern
		{
			get
			{
				if(fullDateTimePattern!=null) {
					return fullDateTimePattern;
				} else {
					return(longDatePattern + " " + longTimePattern);
				}
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				fullDateTimePattern = value;
			}
		}

		public static DateTimeFormatInfo CurrentInfo
		{
			get
			{
				return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
			}
		}

		public static DateTimeFormatInfo InvariantInfo
		{
			get
			{
				if (theInvariantDateTimeFormatInfo == null) {
					theInvariantDateTimeFormatInfo = 
						DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
					theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
				}
				return theInvariantDateTimeFormatInfo;
			}
		}

		public DayOfWeek FirstDayOfWeek
		{
			get
			{
				return (DayOfWeek)firstDayOfWeek;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
				firstDayOfWeek = (int)value;
			}
		}

		public Calendar Calendar
		{
			get
			{
				return calendar;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				if (value == null) throw new ArgumentNullException();
				calendar = value;
			}
		}

		public CalendarWeekRule CalendarWeekRule
		{
			get
			{
				return (CalendarWeekRule)calendarWeekRule;
			}
			set
			{
				if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
				calendarWeekRule = (int)value;
			}
		}

		public string RFC1123Pattern
		{
			get
			{
				return _RFC1123Pattern;
			}
		}

		internal string RoundtripPattern
		{
			get
			{
				return _RoundtripPattern;
			}
		}

		public string SortableDateTimePattern
		{
			get
			{
				return _SortableDateTimePattern;
			}
		}

		public string UniversalSortableDateTimePattern
		{
			get
			{
				return _UniversalSortableDateTimePattern;
			}
		}
		
		// FIXME: Not complete depending on GetAllDateTimePatterns(char)")]
		public string[] GetAllDateTimePatterns () 
		{
			return (string[]) GetAllDateTimePatternsInternal ().Clone ();
		}

		// Same as above, but with no cloning, because we know that
		// clients are friendly
		internal string [] GetAllDateTimePatternsInternal ()
		{
			FillAllDateTimePatterns ();
			return all_date_time_patterns;
		}
		
		// Prevent write reordering
		volatile string [] all_date_time_patterns;
		
		void FillAllDateTimePatterns (){

			if (all_date_time_patterns != null)
				return;
			
			ArrayList al = new ArrayList ();
			al.AddRange (GetAllRawDateTimePatterns ('d'));
			al.AddRange (GetAllRawDateTimePatterns ('D'));
			al.AddRange (GetAllRawDateTimePatterns ('g'));
			al.AddRange (GetAllRawDateTimePatterns ('G'));
			al.AddRange (GetAllRawDateTimePatterns ('f'));
			al.AddRange (GetAllRawDateTimePatterns ('F'));
			// Yes, that is very meaningless, but that is what MS
			// is doing (LAMESPEC: Since it is documented that
			// 'M' and 'm' are equal, they should not cosider
			// that there is a possibility that 'M' and 'm' are
			// different.)
			al.AddRange (GetAllRawDateTimePatterns ('m'));
			al.AddRange (GetAllRawDateTimePatterns ('M'));
			al.AddRange (GetAllRawDateTimePatterns ('r'));
			al.AddRange (GetAllRawDateTimePatterns ('R'));
			al.AddRange (GetAllRawDateTimePatterns ('s'));
			al.AddRange (GetAllRawDateTimePatterns ('t'));
			al.AddRange (GetAllRawDateTimePatterns ('T'));
			al.AddRange (GetAllRawDateTimePatterns ('u'));
			al.AddRange (GetAllRawDateTimePatterns ('U'));
			al.AddRange (GetAllRawDateTimePatterns ('y'));
			al.AddRange (GetAllRawDateTimePatterns ('Y'));

			// all_date_time_patterns needs to be volatile to prevent
			// reordering of writes here and still avoid any locking.
			all_date_time_patterns = (string []) al.ToArray (typeof (string)) as string [];
		}

		//
		// FIXME: We need more culture data in locale-builder
		//   Whoever put that comment, please expand.
		//
		public string[] GetAllDateTimePatterns (char format)
		{
			return (string[]) GetAllRawDateTimePatterns (format).Clone ();
		}

		internal string[] GetAllRawDateTimePatterns (char format)
		{
			string [] list;
			switch (format) {
			// Date
			case 'D':
				if (allLongDatePatterns != null && allLongDatePatterns.Length > 0)
					return allLongDatePatterns;
				return new string [] {LongDatePattern};
			case 'd':
				if (allShortDatePatterns != null && allShortDatePatterns.Length > 0)
					return allShortDatePatterns;
				return new string [] {ShortDatePattern};
			// Time
			case 'T':
				if (allLongTimePatterns != null && allLongTimePatterns.Length > 0)
					return allLongTimePatterns;
				return new string [] {LongTimePattern};
			case 't':
				if (allShortTimePatterns != null && allShortTimePatterns.Length > 0)
					return allShortTimePatterns;
				return new string [] {ShortTimePattern};
			// {Short|Long}Date + {Short|Long}Time
			// FIXME: they should be the agglegation of the
			// combination of the Date patterns and Time patterns.
			case 'G':
				list = PopulateCombinedList (allShortDatePatterns, allLongTimePatterns);
				if (list != null && list.Length > 0)
					return list;
				return new string [] {ShortDatePattern + " " + LongTimePattern};
			case 'g':
				list = PopulateCombinedList (allShortDatePatterns, allShortTimePatterns);
				if (list != null && list.Length > 0)
					return list;
				return new string [] {ShortDatePattern + " " + ShortTimePattern};
			// The 'U' pattern strings are always the same as 'F'.
			// (only differs in assuming UTC or not.)
			case 'U':
			case 'F':
				list = PopulateCombinedList (allLongDatePatterns, allLongTimePatterns);
				if (list != null && list.Length > 0)
					return list;
				return new string [] {LongDatePattern + " " + LongTimePattern};
			case 'f':
				list = PopulateCombinedList (allLongDatePatterns, allShortTimePatterns);
				if (list != null && list.Length > 0)
					return list;
				return new string [] {LongDatePattern + " " + ShortTimePattern};
			// MonthDay
			case 'm':
			case 'M':
				if (monthDayPatterns != null && monthDayPatterns.Length > 0)
					return monthDayPatterns;
				return new string [] {MonthDayPattern};
			// YearMonth
			case 'Y':
			case 'y':
				if (yearMonthPatterns != null && yearMonthPatterns.Length > 0)
					return yearMonthPatterns;
				return new string [] {YearMonthPattern};
			// RFC1123
			case 'r':
			case 'R':
				return new string [] {RFC1123Pattern};
			case 's':
				return new string [] {SortableDateTimePattern};
			case 'u':
				return new string [] {UniversalSortableDateTimePattern};
			}
			throw new ArgumentException ("Format specifier was invalid.");
		}

		public string GetDayName(DayOfWeek dayofweek)
		{
			int index = (int) dayofweek;
			if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
			return dayNames[index];
		}

		public string GetAbbreviatedDayName(DayOfWeek dayofweek)
		{
			int index = (int) dayofweek;
			if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
			return abbreviatedDayNames[index];
		}

		private void FillInvariantPatterns ()
		{
			allShortDatePatterns = new string [] {"MM/dd/yyyy"};
			allLongDatePatterns = new string [] {"dddd, dd MMMM yyyy"};
			allLongTimePatterns = new string [] {"HH:mm:ss"};
			allShortTimePatterns = new string [] {
				"HH:mm",
				"hh:mm tt",
				"H:mm",
				"h:mm tt"
			};
			monthDayPatterns = new string [] {"MMMM dd"};
			yearMonthPatterns = new string [] {"yyyy MMMM"};
		}

		private string [] PopulateCombinedList (string [] dates, string [] times)
		{
			if (dates != null && times != null) {
				string [] list = new string [dates.Length * times.Length];
				int i = 0;
				foreach (string d in dates)
					foreach (string t in times)
						list [i++] = d + " " + t;
				return list;
			}
			return null;
		}

#if NET_2_0
		[MonoTODO ("NotImplemented")]
		[ComVisible (false)]
		public string [] AbbreviatedMonthGenitiveNames {
			get { throw new NotImplementedException (); }
			set { throw new NotImplementedException (); }
		}

		[MonoTODO ("NotImplemented")]
		[ComVisible (false)]
		public string [] MonthGenitiveNames {
			get { throw new NotImplementedException (); }
			set { throw new NotImplementedException (); }
		}

		[MonoTODO ("NotImplemented")]
		[ComVisible (false)]
		public string NativeCalendarName {
			get { throw new NotImplementedException (); }
		}

		[ComVisible (false)]
		public string [] ShortestDayNames {
			get {
				return shortDayNames;
			}

			set {
				if (value == null)
					throw new ArgumentNullException ();

				if (value.Length != 7)
					throw new ArgumentException ("Array must have 7 entries");
				
				for (int i = 0; i < 7; i++)
					if (value [i] == null)
						throw new ArgumentNullException (String.Format ("Element {0} is null", i));
				
				shortDayNames = value;
			}
		}

		[ComVisible (false)]
		public string GetShortestDayName (DayOfWeek dayOfWeek)
		{
			int index = (int) dayOfWeek;
			if (index < 0 || index > 6)
				throw new ArgumentOutOfRangeException();

			return shortDayNames [index];
		}

		[MonoTODO ("NotImplemented")]
		[ComVisible (false)]
		public void SetAllDateTimePatterns (string [] patterns, char format)
		{
			throw new NotImplementedException ();
		}
#endif
	}
}
