Light12306/TrainInfomationProviderService/TrainInfo/Entities/TrainTransitOnceResultCollection.cs
2014-11-27 23:25:36 +08:00

337 lines
9.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TrainInfomationProviderService.StationInfo;
using TrainInfomationProviderService.StationInfo.Entities;
namespace TrainInfomationProviderService.TrainInfo.Entities
{
public class TrainTransitOnceResultCollection : ICollection<TrainTransitOnceResult>
{
List<TrainTransitOnceResult> _list = new List<TrainTransitOnceResult>();
TrainTransitSearchOptions _options;
/// <summary>
/// 日期
/// </summary>
public DateTime Date { get; private set; }
/// <summary>
/// 出发城市编码
/// </summary>
public string FromCode { get; private set; }
/// <summary>
/// 到达城市编码
/// </summary>
public string ToCode { get; private set; }
/// <summary>
/// 出发城市信息
/// </summary>
public StationDetailInfo From { get; private set; }
/// <summary>
/// 到达城市信息
/// </summary>
public StationDetailInfo To { get; private set; }
/// <summary>
/// 创建 <see cref="TrainTransitOnceResultCollection"/> 的新实例(TrainTransitOnceResultCollection)
/// </summary>
/// <param name="options"></param>
/// <param name="date"></param>
/// <param name="fromCode"></param>
/// <param name="toCode"></param>
public TrainTransitOnceResultCollection(DateTime date, TrainTransitSearchOptions options, string fromCode, string toCode)
{
ToCode = toCode;
FromCode = fromCode;
Date = date;
_options = options;
From = StationManager.Instance.Storage.Stations.GetValue(fromCode);
To = StationManager.Instance.Storage.Stations.GetValue(toCode);
}
#region Implementation of IEnumerable
/// <summary>
/// 返回一个循环访问集合的枚举器。
/// </summary>
/// <returns>
/// 可用于循环访问集合的 <see cref="T:System.Collections.Generic.IEnumerator`1"/>。
/// </returns>
public IEnumerator<TrainTransitOnceResult> GetEnumerator()
{
return _list.GetEnumerator();
}
/// <summary>
/// 返回一个循环访问集合的枚举数。
/// </summary>
/// <returns>
/// 一个可用于循环访问集合的 <see cref="T:System.Collections.IEnumerator"/> 对象。
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region Implementation of ICollection<TrainTransitOnceResult>
/// <summary>
/// 将某项添加到 <see cref="T:System.Collections.Generic.ICollection`1"/> 中。
/// </summary>
/// <param name="item">要添加到 <see cref="T:System.Collections.Generic.ICollection`1"/> 的对象。</param><exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
public void Add(TrainTransitOnceResult item)
{
if (item == null || !CheckTransitLineAvailable(item))
return;
_list.Add(item);
}
/// <summary>
/// 从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除所有项。
/// </summary>
/// <exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
public void Clear()
{
_list.Clear();
}
/// <summary>
/// 确定 <see cref="T:System.Collections.Generic.ICollection`1"/> 是否包含特定值。
/// </summary>
/// <returns>
/// 如果在 <see cref="T:System.Collections.Generic.ICollection`1"/> 中找到 <paramref name="item"/>,则为 true否则为 false。
/// </returns>
/// <param name="item">要在 <see cref="T:System.Collections.Generic.ICollection`1"/> 中定位的对象。</param>
public bool Contains(TrainTransitOnceResult item)
{
return _list.Contains(item);
}
/// <summary>
/// 从特定的 <see cref="T:System.Array"/> 索引开始,将 <see cref="T:System.Collections.Generic.ICollection`1"/> 的元素复制到一个 <see cref="T:System.Array"/> 中。
/// </summary>
/// <param name="array">作为从 <see cref="T:System.Collections.Generic.ICollection`1"/> 复制的元素的目标的一维 <see cref="T:System.Array"/>。 <see cref="T:System.Array"/> 必须具有从零开始的索引。</param><param name="arrayIndex"><paramref name="array"/> 中从零开始的索引,从此索引处开始进行复制。</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> 为 null。</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> 小于 0。</exception><exception cref="T:System.ArgumentException">源 <see cref="T:System.Collections.Generic.ICollection`1"/> 中的元素数目大于从 <paramref name="arrayIndex"/> 到目标 <paramref name="array"/> 末尾之间的可用空间。</exception>
public void CopyTo(TrainTransitOnceResult[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
/// <summary>
/// 从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除特定对象的第一个匹配项。
/// </summary>
/// <returns>
/// 如果已从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中成功移除 <paramref name="item"/>,则为 true否则为 false。 如果在原始 <see cref="T:System.Collections.Generic.ICollection`1"/> 中没有找到 <paramref name="item"/>,该方法也会返回 false。
/// </returns>
/// <param name="item">要从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除的对象。</param><exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
public bool Remove(TrainTransitOnceResult item)
{
return _list.Remove(item);
}
/// <summary>
/// 获取 <see cref="T:System.Collections.Generic.ICollection`1"/> 中包含的元素数。
/// </summary>
/// <returns>
/// <see cref="T:System.Collections.Generic.ICollection`1"/> 中包含的元素个数。
/// </returns>
public int Count { get { return _list.Count; } }
/// <summary>
/// 获取一个值,该值指示 <see cref="T:System.Collections.Generic.ICollection`1"/> 是否为只读。
/// </summary>
/// <returns>
/// 如果 <see cref="T:System.Collections.Generic.ICollection`1"/> 为只读,则为 true否则为 false。
/// </returns>
public bool IsReadOnly { get { return false; } }
public TrainTransitSearchOptions Options
{
get { return _options; }
}
#endregion
#region
static int GetMinimalSpace(Train train, bool notRecommand)
{
var extraTime = notRecommand ? 60 : 0;
switch (train.TrainClass)
{
case 'C':
case 'G':
return 30+extraTime;
case 'D':
return 30 + extraTime;
case 'Z':
return 60 + extraTime;
case 'T':
return 60 + extraTime;
default:
return 60 + extraTime;
}
}
static int GetMaxiumSpace(Train train, bool notRecommand)
{
var extraTime = notRecommand ? 60 : 0;
switch (train.TrainClass)
{
case 'C':
case 'G':
return 150 + extraTime;
case 'D':
return 150 + extraTime;
case 'Z':
return 180 + extraTime;
case 'T':
return 180 + extraTime;
default:
return 240 + extraTime;
}
}
/// <summary>
/// 获得比较理想中位时间
/// </summary>
/// <param name="train"></param>
/// <returns></returns>
static int GetHighQualityTimeSpace(Train train, bool notRecommand)
{
var extraTime = notRecommand ? 60 : 0;
switch (train.TrainClass)
{
case 'C':
case 'G':
return 60 + extraTime;
case 'D':
return 60 + extraTime;
case 'Z':
return 120 + extraTime;
case 'T':
return 120 + extraTime;
default:
return 120 + extraTime;
}
}
#endregion
#region
bool CheckTransitLineAvailable(TrainTransitOnceResult item)
{
//总共时间
if (item.First.CalculatedMinutesBase + item.Second.CalculatedMinutesBase > _options.MaxExtraMinutes)
//时间过久
return false;
//时间衔接
var arriveFirst = Date.Add(item.First.To.Arrive.Value);
var leftSecond = arriveFirst.Date.Add(item.Second.From.Left.Value);
//早于发车
if (leftSecond <= arriveFirst)
return false;
var space = (int)(leftSecond - arriveFirst).TotalMinutes;
if (space < GetMinimalSpace(item.First.Train, item.NotRecommand) || space > GetMaxiumSpace(item.Second.Train, item.NotRecommand))
return false;
return true;
}
#endregion
#region
/// <summary>
/// 二次优化,排除小站等。
/// </summary>
internal void SecondaryAnalyze()
{
//对于前车进行分组优化
RemoveSmallStation();
//排序
ProcessPriority();
}
/// <summary>
/// 移除小站
/// </summary>
void RemoveSmallStation()
{
var groups = this.GroupBy(s => s.First.Train.Code).Select(s => new { s.Key, Array = s.ToArray() }).ToArray();
foreach (var g in groups)
{
if (g.Array.Length < 2)
continue;
Array.Sort(g.Array, (s1, s2) =>
{
var st1 = s1.First.To.StopTime.TotalMinutes;
var st2 = s2.First.To.StopTime.TotalMinutes;
if (st1 < st2) return 1;
if (st1 > st2) return -1;
return 0;
});
foreach (var line in g.Array.Skip(Options.SameLineMaxKeepStations))
{
_list.Remove(line);
}
}
groups = this.GroupBy(s => s.Second.Train.Code).Select(s => new { s.Key, Array = s.ToArray() }).ToArray();
foreach (var g in groups)
{
if (g.Array.Length < 2)
continue;
Array.Sort(g.Array, (s1, s2) =>
{
var st1 = s1.Second.From.StopTime.TotalMinutes;
var st2 = s2.Second.From.StopTime.TotalMinutes;
if (st1 < st2) return 1;
if (st1 > st2) return -1;
return 0;
});
foreach (var line in g.Array.Skip(Options.SameLineMaxKeepStations))
{
_list.Remove(line);
}
}
}
#endregion
#region
void ProcessPriority()
{
}
#endregion
}
}