PageRenderTime 18ms CodeModel.GetById 2ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/src/DynamicDataDisplay/Charts/Axes/DateTime/TimePeriodTicksProvider.cs

#
C# | 269 lines | 227 code | 42 blank | 0 comment | 31 complexity | 054b8516de9405c9f146f9c0d261b0ff MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Text;
  5using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
  6
  7namespace Microsoft.Research.DynamicDataDisplay.Charts
  8{
  9	internal abstract class TimePeriodTicksProvider<T> : ITicksProvider<T>
 10	{
 11		public event EventHandler Changed;
 12		protected void RaiseChanged()
 13		{
 14			if (Changed != null)
 15			{
 16				Changed(this, EventArgs.Empty);
 17			}
 18		}
 19
 20		protected abstract T RoundUp(T time, DifferenceIn diff);
 21		protected abstract T RoundDown(T time, DifferenceIn diff);
 22
 23		private bool differenceInited = false;
 24		private DifferenceIn difference;
 25		protected DifferenceIn Difference
 26		{
 27			get
 28			{
 29				if (!differenceInited)
 30				{
 31					difference = GetDifferenceCore();
 32					differenceInited = true;
 33				}
 34				return difference;
 35			}
 36		}
 37		protected abstract DifferenceIn GetDifferenceCore();
 38
 39		private int[] tickCounts = null;
 40		protected int[] TickCounts
 41		{
 42			get
 43			{
 44				if (tickCounts == null)
 45					tickCounts = GetTickCountsCore();
 46				return tickCounts;
 47			}
 48		}
 49		protected abstract int[] GetTickCountsCore();
 50
 51		public int DecreaseTickCount(int ticksCount)
 52		{
 53			if (ticksCount > TickCounts[0]) return TickCounts[0];
 54
 55			for (int i = 0; i < TickCounts.Length; i++)
 56				if (ticksCount > TickCounts[i])
 57					return TickCounts[i];
 58
 59			return TickCounts.Last();
 60		}
 61
 62		public int IncreaseTickCount(int ticksCount)
 63		{
 64			if (ticksCount >= TickCounts[0]) return TickCounts[0];
 65
 66			for (int i = TickCounts.Length - 1; i >= 0; i--)
 67				if (ticksCount < TickCounts[i])
 68					return TickCounts[i];
 69
 70			return TickCounts.Last();
 71		}
 72
 73		protected abstract int GetSpecificValue(T start, T dt);
 74		protected abstract T GetStart(T start, int value, int step);
 75		protected abstract bool IsMinDate(T dt);
 76		protected abstract T AddStep(T dt, int step);
 77
 78		public ITicksInfo<T> GetTicks(Range<T> range, int ticksCount)
 79		{
 80			T start = range.Min;
 81			T end = range.Max;
 82			DifferenceIn diff = Difference;
 83			start = RoundDown(start, end);
 84			end = RoundUp(start, end);
 85
 86			RoundingInfo bounds = RoundingHelper.CreateRoundedRange(
 87				GetSpecificValue(start, start),
 88				GetSpecificValue(start, end));
 89
 90			int delta = (int)(bounds.Max - bounds.Min);
 91			if (delta == 0)
 92				return new TicksInfo<T> { Ticks = new T[] { start } };
 93
 94			int step = delta / ticksCount;
 95
 96			if (step == 0) step = 1;
 97
 98			T tick = GetStart(start, (int)bounds.Min, step);
 99			bool isMinDateTime = IsMinDate(tick) && step != 1;
100			if (isMinDateTime)
101				step--;
102
103			List<T> ticks = new List<T>();
104			T finishTick = AddStep(range.Max, step);
105			while (Continue(tick, finishTick))
106			{
107				ticks.Add(tick);
108				tick = AddStep(tick, step);
109				if (isMinDateTime)
110				{
111					isMinDateTime = false;
112					step++;
113				}
114			}
115
116			ticks = Trim(ticks, range);
117
118			TicksInfo<T> res = new TicksInfo<T> { Ticks = ticks.ToArray(), Info = diff };
119			return res;
120		}
121
122		protected abstract bool Continue(T current, T end);
123
124		protected abstract T RoundUp(T start, T end);
125
126		protected abstract T RoundDown(T start, T end);
127
128		protected abstract List<T> Trim(List<T> ticks, Range<T> range);
129
130		public ITicksProvider<T> MinorProvider
131		{
132			get { throw new NotSupportedException(); }
133		}
134
135		public ITicksProvider<T> MajorProvider
136		{
137			get { throw new NotSupportedException(); }
138		}
139	}
140
141	internal abstract class DatePeriodTicksProvider : TimePeriodTicksProvider<DateTime>
142	{
143		protected sealed override bool Continue(DateTime current, DateTime end)
144		{
145			return current < end;
146		}
147
148		protected sealed override List<DateTime> Trim(List<DateTime> ticks, Range<DateTime> range)
149		{
150			int startIndex = 0;
151			for (int i = 0; i < ticks.Count - 1; i++)
152			{
153				if (ticks[i] <= range.Min && range.Min <= ticks[i + 1])
154				{
155					startIndex = i;
156					break;
157				}
158			}
159
160			int endIndex = ticks.Count - 1;
161			for (int i = ticks.Count - 1; i >= 1; i--)
162			{
163				if (ticks[i] >= range.Max && range.Max > ticks[i - 1])
164				{
165					endIndex = i;
166					break;
167				}
168			}
169
170			List<DateTime> res = new List<DateTime>(endIndex - startIndex + 1);
171			for (int i = startIndex; i <= endIndex; i++)
172			{
173				res.Add(ticks[i]);
174			}
175
176			return res;
177		}
178
179		protected sealed override DateTime RoundUp(DateTime start, DateTime end)
180		{
181			bool isPositive = (end - start).Ticks > 0;
182			return isPositive ? SafelyRoundUp(end) : RoundDown(end, Difference);
183		}
184
185		private DateTime SafelyRoundUp(DateTime dt)
186		{
187			if (AddStep(dt, 1) == DateTime.MaxValue)
188				return DateTime.MaxValue;
189
190			return RoundUp(dt, Difference);
191		}
192
193		protected sealed override DateTime RoundDown(DateTime start, DateTime end)
194		{
195			bool isPositive = (end - start).Ticks > 0;
196			return isPositive ? RoundDown(start, Difference) : SafelyRoundUp(start);
197		}
198
199		protected sealed override DateTime RoundDown(DateTime time, DifferenceIn diff)
200		{
201			DateTime res = time;
202
203			switch (diff)
204			{
205				case DifferenceIn.Year:
206					res = new DateTime(time.Year, 1, 1);
207					break;
208				case DifferenceIn.Month:
209					res = new DateTime(time.Year, time.Month, 1);
210					break;
211				case DifferenceIn.Day:
212					res = time.Date;
213					break;
214				case DifferenceIn.Hour:
215					res = time.Date.AddHours(time.Hour);
216					break;
217				case DifferenceIn.Minute:
218					res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute);
219					break;
220				case DifferenceIn.Second:
221					res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second);
222					break;
223				case DifferenceIn.Millisecond:
224					res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second).AddMilliseconds(time.Millisecond);
225					break;
226				default:
227					break;
228			}
229
230			DebugVerify.Is(res <= time);
231
232			return res;
233		}
234
235		protected override DateTime RoundUp(DateTime dateTime, DifferenceIn diff)
236		{
237			DateTime res = RoundDown(dateTime, diff);
238
239			switch (diff)
240			{
241				case DifferenceIn.Year:
242					res = res.AddYears(1);
243					break;
244				case DifferenceIn.Month:
245					res = res.AddMonths(1);
246					break;
247				case DifferenceIn.Day:
248					res = res.AddDays(1);
249					break;
250				case DifferenceIn.Hour:
251					res = res.AddHours(1);
252					break;
253				case DifferenceIn.Minute:
254					res = res.AddMinutes(1);
255					break;
256				case DifferenceIn.Second:
257					res = res.AddSeconds(1);
258					break;
259				case DifferenceIn.Millisecond:
260					res = res.AddMilliseconds(1);
261					break;
262				default:
263					break;
264			}
265
266			return res;
267		}
268	}
269}