Light12306/Web12306/TrainSuggestion.cs

925 lines
24 KiB
C#
Raw Normal View History

2014-08-19 16:07:39 +08:00
using System;
using System.Collections.Generic;
2014-08-26 21:29:58 +08:00
using System.Drawing;
2014-08-19 16:07:39 +08:00
using System.Linq;
2014-08-26 21:29:58 +08:00
using System.Text.RegularExpressions;
2014-08-19 16:07:39 +08:00
using System.Web;
2014-08-27 23:05:50 +08:00
using System.Web.Helpers;
2014-08-26 21:29:58 +08:00
using Newtonsoft.Json;
2014-08-27 23:05:50 +08:00
using Newtonsoft.Json.Serialization;
2014-08-19 16:07:39 +08:00
namespace Web12306
{
2014-08-26 21:29:58 +08:00
public class TrainSuggestion : IHttpHandler
2014-08-19 16:07:39 +08:00
{
2014-08-26 21:29:58 +08:00
#region Implementation of IHttpHandler
/// <summary>
/// 通过实现 <see cref="T:System.Web.IHttpHandler"/> 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。
/// </summary>
/// <param name="context"><see cref="T:System.Web.HttpContext"/> 对象,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session 和 Server的引用。</param>
public void ProcessRequest(HttpContext context)
{
var request = context.Request;
2014-09-01 20:24:57 +08:00
context.Response.StatusCode = 404;
2014-08-30 23:22:48 +08:00
if (request.UrlReferrer == null || !Regex.IsMatch(request.UrlReferrer.Host, @"^.*?\.(fishlee\.net|liebao\.cn)$"))
return;
//check code
var r = request.QueryString["r"];
if (string.IsNullOrEmpty(r))
return;
2014-08-26 21:29:58 +08:00
var data = request.Form["data"];
if (string.IsNullOrEmpty(data))
return;
2014-08-30 23:22:48 +08:00
var crc = GetTextCrc(data);
if (!r.EndsWith(crc + ""))
2014-09-01 20:24:57 +08:00
{
context.Response.Write(crc);
2014-08-30 23:22:48 +08:00
return;
2014-09-01 20:24:57 +08:00
}
2014-08-30 23:22:48 +08:00
2014-08-30 01:32:27 +08:00
var origin = request.Headers["Origin"];
var callback = request.QueryString["calllback"];
if (!string.IsNullOrEmpty(origin))
{
if (Regex.IsMatch(origin, @"^(https?://.*?\.(fishlee\.net|liebao\.cn)|chrome-extension://.*)$"))
context.Response.AddHeader("Access-Control-Allow-Origin", origin);
else
{
//非法提交
return;
}
}
else
{
return;
}
context.Response.ContentType = string.IsNullOrEmpty(callback) ? "application/json" : "application/javascript";
context.Response.BufferOutput = false;
2014-09-01 20:24:57 +08:00
context.Response.StatusCode = 200;
2014-08-30 01:32:27 +08:00
2014-08-26 21:29:58 +08:00
try
{
var ri = JsonConvert.DeserializeObject<RequestInfo>(data);
var suggestion = GetSuggestionResponseContent(ri);
2014-08-27 23:05:50 +08:00
if (!string.IsNullOrEmpty(callback))
{
context.Response.Write(callback + "(");
}
context.Response.Write(suggestion);
if (!string.IsNullOrEmpty(callback))
{
context.Response.Write(callback + ");");
}
2014-08-26 21:29:58 +08:00
}
catch (Exception ex)
{
return;
}
}
2014-08-30 23:22:48 +08:00
int GetTextCrc(string txt)
{
var crc = 0;
for (var i = 0; i < txt.Length - 1; i += 2)
{
crc += txt[i] ^ txt[i + 1];
if (crc > 48360)
crc -= 36048;
}
if (txt.Length % 2 == 1)
crc += txt[txt.Length - 1];
if (crc > 48360)
crc -= 36048;
crc = crc ^ 5299;
return crc;
}
2014-08-26 21:29:58 +08:00
/// <summary>
/// 获取一个值,该值指示其他请求是否可以使用 <see cref="T:System.Web.IHttpHandler"/> 实例。
/// </summary>
/// <returns>
/// 如果 <see cref="T:System.Web.IHttpHandler"/> 实例可再次使用,则为 true否则为 false。
/// </returns>
public bool IsReusable { get { return true; } }
#endregion
#region
2014-08-27 23:05:50 +08:00
static JsonSerializerSettings _camelJsonSetting = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string GetSuggestionResponseContent(RequestInfo ri)
{
if (ri.CheckIllegal())
return string.Empty;
2014-08-30 01:32:27 +08:00
return JsonConvert.SerializeObject(GetSuggestionResponseContentCore(ri), Formatting.None, _camelJsonSetting);
2014-08-27 23:05:50 +08:00
}
2014-08-30 01:32:27 +08:00
SuggestionResponse GetSuggestionResponseContentCore(RequestInfo ri)
2014-08-27 23:05:50 +08:00
{
2014-08-30 01:32:27 +08:00
//预处理
PreProcessRequestData(ri);
2014-08-27 23:05:50 +08:00
//获得所有的可替换站点
2014-08-30 01:32:27 +08:00
var alllines = ri.Stops.Values.SelectMany(s => GetAlternativeLines(s, ri.Date)).ToArray();
2014-08-27 23:05:50 +08:00
//对线路进行分组排序
2014-08-30 01:32:27 +08:00
var lineGrouped = alllines.GroupBy(s => s.LineName).Select(s =>
{
var list = s.ToList();
var f = list[0];
return new AlternativeLineGroup(f.From.Name, f.To.Name, f.Date, list, f.IsCrossDate);
}).ToList();
2014-08-27 23:05:50 +08:00
//过滤
FilteAlternativeLine(ri, lineGrouped);
//填充数据
FillExtraInfo(ri, lineGrouped);
//排序
SortLineRecommand(ri, lineGrouped);
2014-08-30 01:32:27 +08:00
return new SuggestionResponse()
{
Key = "盗用可耻鄙视无耻的各个国产IT同行",
Accepted = true,
Groups = lineGrouped
};
}
void PreProcessRequestData(RequestInfo ri)
{
ri.PreprocessData();
2014-08-27 23:05:50 +08:00
}
2014-08-30 01:32:27 +08:00
void FilteAlternativeLine(RequestInfo ri, List<AlternativeLineGroup> line)
2014-08-27 23:05:50 +08:00
{
for (var i = line.Count - 1; i >= 0; i--)
{
2014-08-30 01:32:27 +08:00
var train = ri.Stops[line[i].Lines[0].TrainCode];
2014-08-27 23:05:50 +08:00
var maxAllowElapsedTime = train.TrainInfo.elapsedTime.Value.Add(train.TrainInfo.elapsedTime.MaxAddTime);
2014-08-30 01:32:27 +08:00
for (var j = line[i].Lines.Count - 1; j >= 0; j--)
2014-08-27 23:05:50 +08:00
{
2014-08-30 01:32:27 +08:00
var current = line[i].Lines[j];
2014-08-27 23:05:50 +08:00
//如果同时是发站和到站,则删除不推荐
if (current.From.IsOriginal && current.To.IsOriginal)
2014-08-30 01:32:27 +08:00
line[i].Lines.RemoveAt(j);
2014-08-27 23:05:50 +08:00
//如果时间会超过原来最大的允许值,则排除
else if (current.ElapsedTime > maxAllowElapsedTime)
2014-08-30 01:32:27 +08:00
line[i].Lines.RemoveAt(j);
2014-08-27 23:05:50 +08:00
}
2014-08-30 01:32:27 +08:00
if (line[i].Lines.Count == 0)
2014-08-27 23:05:50 +08:00
{
line.RemoveAt(i);
}
}
}
/// <summary>
/// 根据停靠站获得权重
/// </summary>
/// <param name="lineList"></param>
/// <returns></returns>
int GetLineStationEndpointWeight(List<AlternativeLine> lineList)
{
var point = 0;
foreach (var line in lineList)
{
if (line.From.IsEndPoint && line.To.IsEndPoint)
point += 2;
else if (line.From.IsEndPoint || line.To.IsEndPoint)
point += 1;
}
return point;
}
2014-08-26 21:29:58 +08:00
2014-08-30 01:32:27 +08:00
void SortLineRecommand(RequestInfo ri, List<AlternativeLineGroup> line)
2014-08-27 23:05:50 +08:00
{
line.Sort((x, y) =>
{
2014-08-30 01:32:27 +08:00
var ceo1 = GetLineStationEndpointWeight(x.Lines);
var ceo2 = GetLineStationEndpointWeight(y.Lines);
2014-08-27 23:05:50 +08:00
if (ceo1 != ceo2)
return ceo2 - ceo1;
2014-08-30 01:32:27 +08:00
if (x.Lines.Count != y.Lines.Count)
return y.Lines.Count - x.Lines.Count;
2014-08-27 23:05:50 +08:00
//再看停靠时间
2014-08-30 01:32:27 +08:00
var ep1 = (int)x.Lines.Min(s => s.From.StopTime + s.To.StopTime).TotalSeconds;
var ep2 = (int)y.Lines.Min(s => s.From.StopTime + s.To.StopTime).TotalSeconds;
2014-08-27 23:05:50 +08:00
if (ep1 != ep2)
return ep2 - ep1;
//再看价格
2014-08-30 01:32:27 +08:00
var ap1 = (int)x.Lines.Min(s => s.ExtraPrice);
var ap2 = (int)y.Lines.Min(s => s.ExtraPrice);
2014-08-27 23:05:50 +08:00
if (ap1 != ap2)
return ap1 - ap2;
return 0;
});
//再对组内排序
foreach (var current in line)
{
2014-08-30 01:32:27 +08:00
current.Lines.Sort((x, y) =>
2014-08-27 23:05:50 +08:00
{
//再看停靠时间
var ep1 = (int)(x.From.StopTime + x.To.StopTime).TotalSeconds;
var ep2 = (int)(y.From.StopTime + y.To.StopTime).TotalSeconds;
if (ep1 != ep2)
return ep2 - ep1;
//再看价格
var ap1 = (int)x.ExtraPrice;
var ap2 = (int)y.ExtraPrice;
if (ap1 != ap2)
return ap1 - ap2;
return 0;
});
}
}
2014-08-30 01:32:27 +08:00
void FillExtraInfo(RequestInfo ri, List<AlternativeLineGroup> line)
2014-08-27 23:05:50 +08:00
{
for (var i = line.Count - 1; i >= 0; i--)
{
2014-08-30 01:32:27 +08:00
for (var j = line[i].Lines.Count - 1; j >= 0; j--)
2014-08-27 23:05:50 +08:00
{
2014-09-01 20:24:57 +08:00
var train = ri.Stops[line[i].Lines[j].TrainCode];
2014-08-30 01:32:27 +08:00
var current = line[i].Lines[j];
2014-09-01 20:24:57 +08:00
var originalTime = train.TrainInfo.elapsedTime.Value;
2014-08-27 23:05:50 +08:00
//如果时间会超过原来最大的允许值,则排除
var priceExtraRadio = ((current.ElapsedTime - originalTime).TotalSeconds / (1.0 * originalTime.TotalSeconds));
current.BasePriceSeat = Cn12306SuggestionUtility.BaseSeatCodes.First(s => train.TrainInfo.ticketMap.ContainsKey(s));
current.BasePrice = train.TrainInfo.ticketMap[current.BasePriceSeat].price / 10.0;
current.ExtraPrice = Math.Round(priceExtraRadio * current.BasePrice, 2);
2014-08-30 01:32:27 +08:00
current.Radio = (int)(priceExtraRadio * 100);
2014-08-27 23:05:50 +08:00
}
}
}
2014-08-30 01:32:27 +08:00
List<AlternativeLine> GetAlternativeLines(TrainInfoItem train, DateTime requestDate)
2014-08-27 23:05:50 +08:00
{
var info = train.TrainInfo;
var stops = train.StopInfos;
var indexFrom = Array.FindIndex(stops, s => s.station_name == info.from.name);
var indexTo = Array.FindIndex(stops, indexFrom + 1, s => s.station_name == info.to.name);
if (indexFrom == -1 || indexTo == -1)
return null;
var altFrom = new List<AlternativeStation>();
var altTo = new List<AlternativeStation>();
2014-08-30 01:32:27 +08:00
var maxAddTime = train.TrainInfo.elapsedTime.MaxAddTime;
2014-08-27 23:05:50 +08:00
if (indexFrom != 0)
{
2014-08-30 01:32:27 +08:00
var stopTimeFrom = stops[indexFrom].StopTime;
var arriveTime = stops[indexFrom].ArriveTime;
2014-08-27 23:05:50 +08:00
for (var i = 0; i < indexFrom; i++)
{
//如果isEnabled为true则说明会停靠这个站点。不能推荐更短的。
//如果时间过久,则不做推荐
2014-08-30 01:32:27 +08:00
if (stops[i].isEnabled || stops[i].StartTime - arriveTime > maxAddTime)
2014-08-27 23:05:50 +08:00
continue;
2014-08-30 01:32:27 +08:00
var stopTime = i == 0 ? TimeSpan.Zero : stops[i].StopTime;
2014-08-27 23:05:50 +08:00
if (i != 0)
{
//对于非始发站,停靠时间相同或更短,则不做推荐。
if (stopTime <= stopTimeFrom)
continue;
}
//添加到推荐列表中
altFrom.Add(new AlternativeStation()
{
2014-08-30 01:32:27 +08:00
ArriveTime = stops[i].StartTime,
2014-08-27 23:05:50 +08:00
IsEndPoint = i == 0,
IsFromStation = true,
Name = stops[i].station_name,
StopTime = stopTime,
2014-08-30 01:32:27 +08:00
TrainCode = info.code,
Date = stops[i].StartTime,
IsCrossDate = requestDate != stops[i].StartTime.Date
2014-08-27 23:05:50 +08:00
});
}
//排序
altFrom.Sort(new AlternativeStationComparer());
if (altFrom.Count > 3)
altFrom.RemoveRange(altFrom.Count - 3, 3);
}
if (indexTo != stops.Length - 1)
{
2014-08-30 01:32:27 +08:00
var stopTimeTo = stops[indexTo].StopTime;
var startTime = stops[indexTo].StartTime;
2014-08-27 23:05:50 +08:00
for (var i = stops.Length - 1; i >= indexTo; i--)
{
//如果isEnabled为true则说明会停靠这个站点。不能推荐更短的。
//如果时间过久,则不做推荐
2014-08-30 01:32:27 +08:00
if (stops[i].isEnabled || stops[i].ArriveTime - startTime > maxAddTime)
2014-08-27 23:05:50 +08:00
continue;
2014-08-30 01:32:27 +08:00
var stopTime = i == 0 ? TimeSpan.Zero : stops[i].StopTime;
2014-08-27 23:05:50 +08:00
if (i != stops.Length - 1)
{
//对于非终到站,停靠时间相同或更短,则不做推荐。
if (stopTime <= stopTimeTo)
continue;
}
//添加到推荐列表中
altTo.Add(new AlternativeStation()
{
2014-08-30 01:32:27 +08:00
ArriveTime = stops[i].ArriveTime,
2014-08-27 23:05:50 +08:00
IsEndPoint = i == stops.Length - 1,
IsFromStation = false,
Name = stops[i].station_name,
StopTime = stopTime,
TrainCode = info.code
});
}
altTo.Sort(new AlternativeStationComparer());
if (altTo.Count > 3)
altTo.RemoveRange(altFrom.Count - 3, 3);
}
//plus 原始线路
altFrom.Add(new AlternativeStation
{
2014-08-30 01:32:27 +08:00
ArriveTime = stops[indexFrom].StartTime,
2014-08-27 23:05:50 +08:00
IsEndPoint = indexFrom == 0,
IsFromStation = true,
Name = stops[indexFrom].station_name,
2014-08-30 01:32:27 +08:00
StopTime = indexFrom == 0 ? TimeSpan.Zero : stops[indexFrom].StopTime,
2014-08-27 23:05:50 +08:00
TrainCode = info.code,
2014-08-30 01:32:27 +08:00
IsOriginal = true,
IsCrossDate = false,
Date = stops[indexFrom].StartTime
2014-08-27 23:05:50 +08:00
});
altTo.Add(new AlternativeStation
{
2014-08-30 01:32:27 +08:00
ArriveTime = stops[indexTo].ArriveTime,
2014-08-27 23:05:50 +08:00
IsEndPoint = indexTo == stops.Length - 1,
IsFromStation = false,
Name = stops[indexTo].station_name,
2014-08-30 01:32:27 +08:00
StopTime = indexTo == stops.Length - 1 ? TimeSpan.Zero : stops[indexFrom].StopTime,
2014-08-27 23:05:50 +08:00
TrainCode = info.code,
IsOriginal = true
});
2014-08-30 01:32:27 +08:00
var lines = altFrom.CrossJoin(altTo).Where(s => !s.Key.IsOriginal || !s.Value.IsOriginal).Select(s => new AlternativeLine(s.Key, s.Value, s.Key.Date, s.Key.IsCrossDate) { TrainCode = s.Key.TrainCode }).ToList();
2014-08-27 23:05:50 +08:00
return lines;
}
#endregion
}
public static class Cn12306SuggestionUtility
{
public static double TimeRangeLimitRadio = double.Parse(System.Configuration.ConfigurationManager.AppSettings["12306_trainsuggestion_maxradio"]);
public static readonly char[] BaseSeatCodes = "O219PM6430".ToArray();
public static TimeSpan GetTimeSpace(TimeSpan t1, TimeSpan t2)
{
var t = t2 - t1;
if (t.Ticks < 0)
t = t.Add(new TimeSpan(1, 0, 0, 0));
return t;
}
/// <summary>
/// 生成两个序列的交叉
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t1"></param>
/// <param name="t2"></param>
/// <returns></returns>
public static IEnumerable<KeyValuePair<T, T>> CrossJoin<T>(this IEnumerable<T> t1, IEnumerable<T> t2)
{
foreach (var t in t1)
{
foreach (var tt in t2)
{
yield return new KeyValuePair<T, T>(t, tt);
}
}
}
public static int GetStopTime(string stopTimeStr)
2014-08-26 21:29:58 +08:00
{
var m = Regex.Match(stopTimeStr, @"(\d+)分钟");
return m.Success ? int.Parse(m.Groups[1].Value) : 0;
}
2014-08-27 23:05:50 +08:00
public static TimeSpan GetStopTimeSpan(string stopTimeStr)
{
var m = Regex.Match(stopTimeStr, @"(\d+)分钟");
return m.Success ? new TimeSpan(0, int.Parse(m.Groups[1].Value), 0) : TimeSpan.Zero;
}
public static int GetTimeValue(string time)
2014-08-26 21:29:58 +08:00
{
var m = Regex.Match(time, @"0?(\d+):0?(\d+)");
return m.Success ? int.Parse(m.Groups[1].Value) * 60 + int.Parse(m.Groups[2].Value) : 0;
}
2014-08-27 23:05:50 +08:00
public static TimeSpan GetTimeValueSpan(string time)
{
var m = Regex.Match(time, @"0?(\d+):0?(\d+)");
return m.Success ? new TimeSpan(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value), 0) : TimeSpan.Zero;
}
2014-08-26 21:29:58 +08:00
2014-08-27 23:05:50 +08:00
public static int GetTimeSpace(string time1, string time2)
2014-08-26 21:29:58 +08:00
{
var x1 = GetTimeValue(time1);
var x2 = GetTimeValue(time2);
return x1 <= x2 ? x2 - x1 : x2 + 24 * 60 - x1;
}
2014-08-27 23:05:50 +08:00
}
2014-08-30 01:32:27 +08:00
public class SuggestionResponse
{
public bool Accepted { get; set; }
public string Key { get; set; }
public List<AlternativeLineGroup> Groups { get; set; }
}
public class AlternativeLineGroup
{
public string FromText { get; set; }
public string ToText { get; set; }
public string Date { get; set; }
public List<AlternativeLine> Lines { get; set; }
public bool IsCrossDate { get; set; }
/// <summary>
/// 创建 <see cref="AlternativeLineGroup" /> 的新实例(AlternativeLineGroup)
/// </summary>
/// <param name="fromText"></param>
/// <param name="toText"></param>
/// <param name="date"></param>
/// <param name="lines"></param>
public AlternativeLineGroup(string fromText, string toText, string date, List<AlternativeLine> lines, bool isCrossDate)
{
FromText = fromText;
ToText = toText;
Date = date;
Lines = lines;
IsCrossDate = isCrossDate;
}
}
2014-08-27 23:05:50 +08:00
public class AlternativeStation
{
public string TrainCode { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool IsFromStation { get; set; }
public bool IsEndPoint { get; set; }
2014-08-30 01:32:27 +08:00
public DateTime ArriveTime { get; set; }
2014-08-26 21:29:58 +08:00
2014-08-27 23:05:50 +08:00
public TimeSpan StopTime { get; set; }
2014-08-26 21:29:58 +08:00
2014-08-27 23:05:50 +08:00
public bool IsOriginal { get; set; }
2014-08-30 01:32:27 +08:00
/// <summary>
/// 是否跨天
/// </summary>
public bool IsCrossDate { get; set; }
/// <summary>
/// 日期
/// </summary>
public DateTime Date { get; set; }
2014-08-27 23:05:50 +08:00
}
public class AlternativeLine
{
public AlternativeStation From { get; private set; }
public AlternativeStation To { get; private set; }
public string LineName { get; private set; }
public string TrainCode { get; set; }
TimeSpan? _elTimeSpan;
public double ExtraPrice { get; set; }
public char BasePriceSeat { get; set; }
public double BasePrice { get; set; }
2014-08-26 21:29:58 +08:00
2014-08-30 01:32:27 +08:00
public int Radio { get; set; }
public string Date { get; set; }
public bool IsCrossDate { get; set; }
2014-08-27 23:05:50 +08:00
public TimeSpan ElapsedTime
{
get
{
if (!_elTimeSpan.HasValue)
{
_elTimeSpan = To.ArriveTime - From.ArriveTime;
if (_elTimeSpan.Value.Ticks < 0)
_elTimeSpan = _elTimeSpan.Value.Add(new TimeSpan(1, 0, 0, 0));
}
return _elTimeSpan.Value;
}
2014-08-26 21:29:58 +08:00
}
2014-08-27 23:05:50 +08:00
/// <summary>
/// 创建 <see cref="AlternativeLine" /> 的新实例(AlternativeLine)
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
2014-08-30 01:32:27 +08:00
public AlternativeLine(AlternativeStation from, AlternativeStation to, DateTime date, bool isCrossDate)
2014-08-27 23:05:50 +08:00
{
From = from;
To = to;
2014-08-30 01:32:27 +08:00
IsCrossDate = isCrossDate;
Date = date.ToString("yyyy-MM-dd");
2014-08-26 21:29:58 +08:00
2014-08-30 01:32:27 +08:00
LineName = From.Name + ";" + To.Name + (isCrossDate ? ";" + Date : "");
2014-08-27 23:05:50 +08:00
}
}
2014-08-26 21:29:58 +08:00
2014-08-27 23:05:50 +08:00
public class AlternativeStationComparer : IComparer<AlternativeStation>
{
#region Implementation of IComparer<in AlternativeStation>
/// <summary>
/// 比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。
/// </summary>
/// <returns>
/// 一个有符号整数,指示 <paramref name="x"/> 与 <paramref name="y"/> 的相对值,如下表所示。 值 含义 小于零 <paramref name="x"/> 小于 <paramref name="y"/>。 零 <paramref name="x"/> 等于 <paramref name="y"/>。 大于零 <paramref name="x"/> 大于 <paramref name="y"/>。
/// </returns>
/// <param name="x">要比较的第一个对象。</param><param name="y">要比较的第二个对象。</param>
public int Compare(AlternativeStation x, AlternativeStation y)
{
if (x.IsEndPoint ^ y.IsEndPoint)
return x.IsEndPoint ? -1 : 1;
return x.StopTime < y.StopTime ? -1 : 1;
}
#endregion
2014-08-19 16:07:39 +08:00
}
2014-08-26 21:29:58 +08:00
public class SuggestItemComparer : IComparer<SuggestItem>
{
#region Implementation of IComparer<in StopInfo>
/// <summary>
/// 比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。
/// </summary>
/// <returns>
/// 一个有符号整数,指示 <paramref name="x"/> 与 <paramref name="y"/> 的相对值,如下表所示。 值 含义 小于零 <paramref name="x"/> 小于 <paramref name="y"/>。 零 <paramref name="x"/> 等于 <paramref name="y"/>。 大于零 <paramref name="x"/> 大于 <paramref name="y"/>。
/// </returns>
/// <param name="x">要比较的第一个对象。</param><param name="y">要比较的第二个对象。</param>
public int Compare(SuggestItem x, SuggestItem y)
{
if (x.EndPoint ^ y.EndPoint)
return x.EndPoint ? -1 : 1;
return x.StopTime - y.StopTime;
}
2014-08-19 16:07:39 +08:00
2014-08-26 21:29:58 +08:00
#endregion
}
public class SuggestItem
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("ep")]
public bool EndPoint { get; set; }
[JsonProperty("st")]
public int StopTime { get; set; }
}
2014-08-19 16:07:39 +08:00
public class RequestInfo
{
2014-08-27 23:05:50 +08:00
public string Key { get; set; }
2014-08-26 21:29:58 +08:00
public string From { get; set; }
public string To { get; set; }
2014-08-30 01:32:27 +08:00
public DateTime Date { get; set; }
2014-08-27 23:05:50 +08:00
2015-02-08 23:31:05 +08:00
[JsonProperty("tt")]
public string[] SelectedTrain { get; set; }
[JsonProperty("ts")]
public string[] SelectedSeats { get; set; }
2014-08-27 23:05:50 +08:00
public Dictionary<string, TrainInfoItem> Stops { get; set; }
2014-08-26 21:29:58 +08:00
/// <summary>
/// 检测是否有非法请求有则返回true
/// </summary>
/// <returns></returns>
public bool CheckIllegal()
{
2014-08-27 23:05:50 +08:00
if (Key != "stupid360")
return true;
if (Stops.Values.Any(s => (s.TrainInfo.code == s.TrainInfo.from.code && s.TrainInfo.to.code == s.TrainInfo.end.code) || s.TrainInfo.available < 0))
2014-08-26 21:29:58 +08:00
return true;
2015-02-08 23:31:05 +08:00
//add 2014年9月4日 - 检测非法席别
if (SelectedSeats == null)
return true;
if (SelectedSeats.Length > 0)
{
if (Stops.Values.Any(s => !SelectedSeats.Any(x => s.TrainInfo.ticketMap.ContainsKey(x[0]))))
return true;
}
2014-08-26 21:29:58 +08:00
return false;
}
2014-08-30 01:32:27 +08:00
public void PreprocessData()
{
foreach (var trainInfoItem in Stops.Values)
{
trainInfoItem.PreprocessData(Date);
}
}
2014-08-19 16:07:39 +08:00
}
2014-08-27 23:05:50 +08:00
public class TrainInfoItem
{
[JsonProperty("info")]
public TrainInfo TrainInfo { get; set; }
[JsonProperty("stops")]
public StopInfo[] StopInfos { get; set; }
2014-08-30 01:32:27 +08:00
public void PreprocessData(DateTime requestDate)
{
TrainInfo.from.TimePoint = requestDate.Date.Add(Cn12306SuggestionUtility.GetTimeValueSpan(TrainInfo.from.time));
//查找开始站
var startIndex = Array.FindIndex(StopInfos, s => s.isEnabled);
TrainInfo.from.Index = startIndex;
TrainInfo.to.Index = Array.FindIndex(StopInfos, startIndex + 1, s => !s.isEnabled);
if (TrainInfo.to.Index == -1)
TrainInfo.to.Index = StopInfos.Length - 1;
StopInfos[startIndex].StartTime = TrainInfo.from.TimePoint;
if (startIndex > 0)
{
StopInfos[startIndex].ArriveTime = requestDate.Add(StopInfos[startIndex].ArriveTimePoint);
if (StopInfos[startIndex].ArriveTime > StopInfos[startIndex].StartTime)
StopInfos[startIndex].ArriveTime = StopInfos[startIndex].ArriveTime.AddDays(-1);
}
var tempDate = requestDate;
for (var i = startIndex - 1; i >= 0; i--)
{
var sto = StopInfos[i];
var stn = StopInfos[i + 1];
sto.StartTime = tempDate.Add(sto.StartTimePoint);
if (sto.StartTime > stn.StartTime)
{
tempDate = tempDate.AddDays(-1);
sto.StartTime = sto.StartTime.AddDays(-1);
}
if (i > 0)
{
sto.ArriveTime = tempDate.Add(sto.ArriveTimePoint);
if (sto.ArriveTime > sto.StartTime)
{
tempDate = tempDate.AddDays(-1);
sto.ArriveTime = sto.ArriveTime.AddDays(-1);
}
}
}
tempDate = requestDate;
for (var i = startIndex + 1; i < StopInfos.Length; i++)
{
var sto = StopInfos[i];
var stn = StopInfos[i - 1];
sto.ArriveTime = tempDate.Add(sto.ArriveTimePoint);
if (sto.ArriveTime < stn.StartTime)
{
tempDate = tempDate.AddDays(1);
sto.ArriveTime = sto.ArriveTime.AddDays(1);
}
if (i < StopInfos.Length - 1)
{
sto.StartTime = tempDate.Add(sto.StartTimePoint);
if (sto.StartTime < sto.ArriveTime)
{
tempDate = tempDate.AddDays(1);
sto.StartTime = sto.StartTime.AddDays(1);
}
}
}
var startTime = StopInfos.Select(s => s.StartTime).ToArray();
var stopTime = StopInfos.Select(s => s.StopTime).ToArray();
}
2014-08-27 23:05:50 +08:00
}
2014-08-26 21:29:58 +08:00
public class StopInfo
{
public string start_station_name { get; set; }
public string arrive_time { get; set; }
public string station_train_code { get; set; }
public string station_name { get; set; }
public string train_class_name { get; set; }
public string service_type { get; set; }
public string start_time { get; set; }
public string stopover_time { get; set; }
public string end_station_name { get; set; }
public string station_no { get; set; }
public bool isEnabled { get; set; }
2014-08-30 01:32:27 +08:00
/// <summary>
/// 到达时间
/// </summary>
public DateTime ArriveTime { get; set; }
/// <summary>
/// 发车时间
/// </summary>
public DateTime StartTime { get; set; }
TimeSpan? _stopTimeSpan;
public TimeSpan StopTime
{
get
{
if (!_stopTimeSpan.HasValue)
{
_stopTimeSpan = Cn12306SuggestionUtility.GetStopTimeSpan(stopover_time);
}
return _stopTimeSpan.Value;
}
}
TimeSpan? _arriveTime, _startTime;
public TimeSpan ArriveTimePoint
{
get { return (_arriveTime ?? (_arriveTime = Cn12306SuggestionUtility.GetTimeValueSpan(arrive_time))).Value; }
}
public TimeSpan StartTimePoint
{
get { return (_startTime ?? (_startTime = Cn12306SuggestionUtility.GetTimeValueSpan(start_time))).Value; }
}
2014-08-26 21:29:58 +08:00
}
public class SeatTicketInfo
{
public string code { get; set; }
public string name { get; set; }
public int price { get; set; }
public int count { get; set; }
}
public class SimpleStationInfo
{
public string code { get; set; }
public string name { get; set; }
}
public class DetailStationInfo : SimpleStationInfo
{
public string fromStationNo { get; set; }
public bool endpoint { get; set; }
public string time { get; set; }
2014-08-30 01:32:27 +08:00
/// <summary>
/// 具体时间
/// </summary>
public DateTime TimePoint { get; set; }
/// <summary>
/// 在停靠站中的索引
/// </summary>
public int Index { get; set; }
2014-08-26 21:29:58 +08:00
}
public class TrainInfo
{
public string id { get; set; }
public string code { get; set; }
public int available { get; set; }
public SimpleStationInfo start { get; set; }
public DetailStationInfo from { get; set; }
public DetailStationInfo to { get; set; }
public Elapsedtime elapsedTime { get; set; }
public SimpleStationInfo end { get; set; }
public string ypinfo { get; set; }
public string ypinfo_ex { get; set; }
public string locationCode { get; set; }
public int controlDay { get; set; }
public string supportCard { get; set; }
public string saleTime { get; set; }
public string secureStr { get; set; }
2014-08-27 23:05:50 +08:00
public DateTime? selltime { get; set; }
2014-08-26 21:29:58 +08:00
public string date { get; set; }
2014-08-27 23:05:50 +08:00
public string limitSellInfo { get; set; }
2014-08-26 21:29:58 +08:00
public SeatTicketInfo[] tickets { get; set; }
2014-08-27 23:05:50 +08:00
2014-08-26 21:29:58 +08:00
public Dictionary<char, SeatTicketInfo> ticketMap { get; set; }
}
public class Elapsedtime
{
public string days { get; set; }
public string total { get; set; }
2014-08-27 23:05:50 +08:00
TimeSpan? _elTimeSpan;
[JsonIgnore]
public TimeSpan Value
{
get
{
if (_elTimeSpan == null)
{
_elTimeSpan = Cn12306SuggestionUtility.GetTimeValueSpan(total);
}
return _elTimeSpan.Value;
}
}
TimeSpan? _maxAddTime;
/// <summary>
/// 最大允许加时
/// </summary>
[JsonIgnore]
public TimeSpan MaxAddTime
{
get
{
if (_maxAddTime == null)
{
_maxAddTime = new TimeSpan(0, 0, 0, (int)(Value.TotalSeconds * Cn12306SuggestionUtility.TimeRangeLimitRadio));
}
return _maxAddTime.Value;
}
}
2014-08-26 21:29:58 +08:00
}
2014-08-19 16:07:39 +08:00
}