|
using System;
using System.Collections.Generic;
using System.Text;
namespace Idaligo.Time
{
public class ShiftedAnchor : IAnchor
{
private Scale scale;
private Anchor anchor;
private int number;
public ShiftedAnchor(Scale baseScale, Scale scale, int number)
: this(new Anchor(baseScale), scale, number)
{
}
protected ShiftedAnchor(Anchor @base, Scale scale, int number)
{
if (@base == null) throw new ArgumentNullException("@base");
if (number < 0) throw new ArgumentOutOfRangeException("number", number, "Must be 0 or greater.");
Validate(@base, scale, number);
this.anchor = @base;
this.scale = scale;
this.number = number;
}
private void Validate(Anchor @base, Scale scale, int number)
{
#warning Left undone: ShiftedAnchor.ValidateScaleAndNumber
}
public bool AtPoint(DateTime at)
{
bool result;
if (this.scale == Scale.Week)
{
DateTime starts = (this.anchor.AtPoint(at)) ? at : this.anchor.Previous(at);
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
if (this.number == 0)
{
result = starts == at;
}
else
{
result = at == this.Next(starts);
}
}
else
{
if (this.number == 0)
{
result = this.anchor.AtPoint(at);
}
else
{
result = at == this.Next(this.anchor.Previous(at));
}
}
return result;
}
public IEnumerable<DateTime> Walk(DateTime from)
{
if (this.AtPoint(from))
{
yield return from;
}
while (true)
{
from = this.Next(from);
yield return from;
}
}
public DateTime Next(DateTime from)
{
return this.Go((this.anchor.AtPoint(from)) ? from : this.anchor.Previous(from), from, true);
}
private DateTime Go(DateTime starts, DateTime from, bool forward)
{
DateTime result;
if (this.scale == Scale.Year)
{
throw new InvalidProgramException();
}
else if (this.scale == Scale.Month)
{
if (this.anchor.Scale == Scale.Year)
{
if (this.number > 11)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddMonths(this.number);
}
}
else
{
throw new InvalidOperationException();
}
}
else if (this.scale == Scale.Week)
{
#region Week
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
if (this.anchor.Scale == Scale.Year)
{
if (this.number > 51)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddDays(this.number * 7);
while ((result.DayOfYear - 1) / 7 != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
result = starts.AddDays(this.number * 7);
}
}
}
else if (this.anchor.Scale == Scale.Month)
{
if (this.number > 4)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddDays(this.number * 7);
while (result.Day / 7 != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
result = starts.AddDays(this.number * 7);
}
}
}
else
{
throw new InvalidOperationException();
}
#endregion
}
else if (this.scale == Scale.Day)
{
#region Day
if (this.anchor.Scale == Scale.Year)
{
if (this.number > 365)
{
throw new InvalidOperationException();
}
else if (this.number > 364)
{
// 365 (366th - leap year)
result = starts.AddDays(this.number);
while (result.DayOfYear != 366)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddDays(this.number);
}
}
else
{
// 364 (365th - usual year)
result = starts.AddDays(this.number);
}
}
else if (this.anchor.Scale == Scale.Month)
{
if (this.number > 30)
{
throw new InvalidOperationException();
}
else if (this.number > 27)
{
// 30 (31th)
// 29 (30th)
// 28 (29th)
result = starts.AddDays(this.number);
while (result.Date.Day != this.number + 1)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddDays(this.number);
}
}
else
{
result = starts.AddDays(this.number);
}
}
else if (this.anchor.Scale == Scale.Week)
{
if (this.number > 6)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddDays(this.number);
}
}
else
{
throw new InvalidOperationException();
}
#endregion
}
else if (this.scale == Scale.Hour)
{
#region Hour
if (this.anchor.Scale == Scale.Year)
{
if (this.number > 8783 /* 366x24 - 1 */)
{
throw new InvalidOperationException();
}
else if (this.number > 8759 /* 365x24 - 1 */)
{
result = starts.AddHours(this.number);
while ((result.DayOfYear - 1) * 24 + result.Hour != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddHours(this.number);
}
}
else
{
result = starts.AddHours(this.number);
}
}
else if (this.anchor.Scale == Scale.Month)
{
if (this.number > 773 /* 31x24 - 1*/)
{
throw new InvalidOperationException();
}
else if (this.number > 671 /* 28x24 - 1 */)
{
result = starts.AddHours(this.number);
while ((result.Day - 1) * 24 + result.Hour != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddHours(this.number);
}
}
else
{
result = starts.AddHours(this.number);
}
}
else if (this.anchor.Scale == Scale.Week)
{
if (this.number > 167)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddHours(this.number);
}
}
else if (this.anchor.Scale == Scale.Day)
{
if (this.number > 23)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddHours(this.number);
}
}
else
{
throw new InvalidOperationException();
}
#endregion
}
else if (this.scale == Scale.Minute)
{
#region Minute
if (this.anchor.Scale == Scale.Year)
{
if (this.number > 527039 /* 366x24x60 - 1*/)
{
throw new InvalidOperationException();
}
else if (this.number > 525599 /* 365x24x60 - 1*/)
{
result = starts.AddMinutes(this.number);
while ((result.DayOfYear - 1) * 24 * 60 + result.Hour * 60 + result.Minute != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddMinutes(this.number);
}
}
else
{
result = starts.AddMinutes(this.number);
}
}
else if (this.anchor.Scale == Scale.Month)
{
if (this.number > 44639 /* 31x24x60 - 1 */)
{
throw new InvalidOperationException();
}
else if (this.number > 40319 /* 28x24x60 - 1 */)
{
result = starts.AddMinutes(this.number);
while ((result.Day - 1) * 24 * 60 + result.Hour * 60 + result.Minute != this.number)
{
starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
result = starts.AddMinutes(this.number);
}
}
else
{
result = starts.AddMinutes(this.number);
}
}
else if (this.anchor.Scale == Scale.Week)
{
if (this.number > 8399 /* 24x7x60 -1 */)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddMinutes(this.number);
}
}
else if (this.anchor.Scale == Scale.Day)
{
if (this.number > 1439 /* 24x60 - 1*/)
{
throw new InvalidOperationException();
}
else
{
result = starts.AddMinutes(this.number);
}
}
else if (this.anchor.Scale == Scale.Hour)
{
if (this.number > 59)
{
throw new NotSupportedException();
}
else
{
result = starts.AddMinutes(this.number);
}
}
else
{
throw new InvalidOperationException();
}
#endregion
}
else if (this.scale == Scale.Second)
{
result = starts.AddSeconds(this.number);
}
else
{
throw new NotSupportedException(this.scale.ToString());
}
if (forward)
{
if (result <= from)
{
if (this.scale == Scale.Week)
{
starts = this.anchor.Next(starts);
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
}
else
{
starts = this.anchor.Next(starts);
}
result = this.Go(starts, from, forward);
}
}
else
{
if (result >= from)
{
if (this.scale == Scale.Week)
{
starts = this.anchor.Previous(starts);
if (starts.DayOfWeek != DayOfWeek.Sunday)
{
starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
}
}
else
{
starts = this.anchor.Previous(starts);
}
result = this.Go(starts, from, forward);
}
}
return result;
}
public DateTime Previous(DateTime from)
{
return this.Go((this.anchor.AtPoint(from)) ? from : this.anchor.Previous(from), from, false);
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.