Light12306/TrainInfomationProviderService/TrainInfo/Entities/TrainTransitOnceResultCollection.cs

337 lines
9.8 KiB
C#
Raw Normal View History

2014-11-27 23:25:36 +08:00
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
}
}