//******************************************************************************************************
// SchedulePart.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), 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.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 08/01/2006 - Pinal C. Patel
// Generated original version of source code.
// 09/15/2008 - J. Ritchie Carroll
// Converted to C#.
// 11/03/2008 - Pinal C. Patel
// Edited code comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace GSF.Scheduling
{
#region [ Enumerations ]
///
/// Indicates the date/time element that a represents.
///
/// This enumeration specifically corresponds to the UNIX crontab date/time elements.
public enum DateTimePart
{
///
/// represents minutes. Legal values are 0 through 59.
///
Minute,
///
/// represents hours. Legal values are 0 through 23.
///
Hour,
///
/// represents day of month. Legal values are 1 through 31.
///
Day,
///
/// represents months. Legal values are 1 through 12.
///
Month,
///
/// represents day of week. Legal values are 0 through 7 where 0 is Sunday.
///
DayOfWeek
}
///
/// Indicates the syntax used in a for specifying its values.
///
public enum SchedulePartTextSyntax
{
///
/// Values for the were specified using the '*' text syntax. Included values are
/// all legal values for the that the represents.
///
Any,
///
/// Values for the were specified using the '*/n' text syntax. Included values are
/// legal values for the that the represents that are
/// divisible by 'n'.
///
EveryN,
///
/// Values for the were specified using the 'n1-nn' text syntax. Included values
/// are legal values for the that the represents that
/// are within the specified range.
///
Range,
///
/// Values for the were specified using the 'n1,n2,nn' text syntax. Included values
/// are specific legal values for the that the represents.
///
Specific
}
#endregion
///
/// Represents a part of the .
///
///
public class SchedulePart
{
#region [ Members ]
// Fields
private readonly string m_valueText;
private readonly DateTimePart m_dateTimePart;
private SchedulePartTextSyntax m_valueTextSyntax;
private List m_values;
#endregion
#region [ Constructors ]
///
/// Initializes a new instance of the class.
///
/// The text that specifies the values for the object.
/// The that the object represents.
public SchedulePart(string valueText, DateTimePart dateTimePart)
{
if (ValidateAndPopulate(valueText, dateTimePart))
{
// The text provided for populating the values is valid according to the specified date-time part.
m_valueText = valueText;
m_dateTimePart = dateTimePart;
}
else
{
throw new ArgumentException("Text is not valid for " + dateTimePart + " schedule part");
}
}
#endregion
#region [ Properties ]
///
/// Gets the text used to specify the values for the object.
///
public string ValueText
{
get
{
return m_valueText;
}
}
///
/// Gets the that the object represents.
///
public DateTimePart DateTimePart
{
get
{
return m_dateTimePart;
}
}
///
/// Gets the used in the for specifying the
/// values of the object.
///
public SchedulePartTextSyntax ValueTextSyntax
{
get
{
return m_valueTextSyntax;
}
}
///
/// Gets a meaningful description of the object.
///
public string Description
{
get
{
switch (m_valueTextSyntax)
{
case SchedulePartTextSyntax.Any:
return "Any " + m_dateTimePart.ToString();
case SchedulePartTextSyntax.EveryN:
return "Every " + m_valueText.Split('/')[1] + " " + m_dateTimePart.ToString();
case SchedulePartTextSyntax.Range:
string[] range = m_valueText.Split('-');
return m_dateTimePart.ToString() + " " + range[0] + " to " + range[1];
case SchedulePartTextSyntax.Specific:
return m_dateTimePart.ToString() + " " + m_valueText;
default:
return "";
}
}
}
///
/// Gets the list of values for the object specified using .
///
public List Values
{
get
{
return m_values;
}
}
#endregion
#region [ Methods ]
///
/// Determines if the for the that the
/// object represents matches the specified .
///
/// The against which the are to be matches.
/// true if one of the matches the ; otherwise false.
public bool Matches(DateTime dateTime)
{
switch (m_dateTimePart)
{
case DateTimePart.Minute:
return m_values.Contains(dateTime.Minute);
case DateTimePart.Hour:
return m_values.Contains(dateTime.Hour);
case DateTimePart.Day:
return m_values.Contains(dateTime.Day);
case DateTimePart.Month:
return m_values.Contains(dateTime.Month);
case DateTimePart.DayOfWeek:
return m_values.Contains((int)dateTime.DayOfWeek);
default:
return false;
}
}
private bool ValidateAndPopulate(string schedulePart, DateTimePart dateTimePart)
{
int minValue = 0;
int maxValue = 0;
switch (dateTimePart)
{
case DateTimePart.Minute:
maxValue = 59;
break;
case DateTimePart.Hour:
maxValue = 23;
break;
case DateTimePart.Day:
minValue = 1;
maxValue = 31;
break;
case DateTimePart.Month:
minValue = 1;
maxValue = 12;
break;
case DateTimePart.DayOfWeek:
maxValue = 6;
break;
}
m_values = new List();
if (Regex.Match(schedulePart, "^(\\*){1}$").Success)
{
// ^(\*){1}$ Matches: *
m_valueTextSyntax = SchedulePartTextSyntax.Any;
PopulateValues(minValue, maxValue, 1);
return true;
}
else if (Regex.Match(schedulePart, "^(\\*/\\d+){1}$").Success)
{
// ^(\*/\d+){1}$ Matches: */[any digit]
int interval = Convert.ToInt32(schedulePart.Split('/')[1]);
if (interval > 0 && interval >= minValue && interval <= maxValue)
{
m_valueTextSyntax = SchedulePartTextSyntax.EveryN;
PopulateValues(minValue, maxValue, interval);
return true;
}
}
else if (Regex.Match(schedulePart, "^(\\d+\\-\\d+){1}$").Success)
{
// ^(\d+\-\d+){1}$ Matches: [any digit]-[any digit]
string[] range = schedulePart.Split('-');
int lowRange = Convert.ToInt32(range[0]);
int highRange = Convert.ToInt32(range[1]);
if (lowRange < highRange && lowRange >= minValue && highRange <= maxValue)
{
m_valueTextSyntax = SchedulePartTextSyntax.Range;
PopulateValues(lowRange, highRange, 1);
return true;
}
}
else if (Regex.Match(schedulePart, "^((\\d+,?)+){1}$").Success)
{
// ^((\d+,?)+){1}$ Matches: [any digit] AND [any digit], ..., [any digit]
m_valueTextSyntax = SchedulePartTextSyntax.Specific;
int value;
foreach (string part in schedulePart.Split(','))
{
if (int.TryParse(part, out value))
{
if (!(value >= minValue && value <= maxValue))
{
return false;
}
else
{
if (!m_values.Contains(value))
m_values.Add(value);
}
}
else
{
return false;
}
}
return true;
}
return false;
}
private void PopulateValues(int fromValue, int toValue, int stepValue)
{
for (int i = fromValue; i <= toValue; i += stepValue)
{
m_values.Add(i);
}
}
#endregion
}
}