define(function (require, exports, module) {
	var ajax = require("../platform/webRequest.js");
	var param = require("../data.js");
	var parser = require("../platform/parser.js");
	var ev = require("../platform/EventObject.js");
	var dynamicjs = require("../otn/dynamicjs.js");
	var sessmgr = require("../account/sessionMgr.js");
	var stationData = require("../station/station_data.js");
	var utility = require('../utility.js');

	var extensionVersion = parseInt(document.body.dataset["targetExtensionVersion"].replace(/\./g, ""));

	exports.events = new ev();

	//最后二十次的查询平均时间
	var lastQueryTimes = [];
	var averageQueryTime = null;
	var calculateQueryTime = function (time) {
		lastQueryTimes.push(time);

		while (lastQueryTimes.length > 20)
			lastQueryTimes.shift();

		averageQueryTime = lastQueryTimes.length > 0 ? _.reduce(lastQueryTimes, function (x, y) {
			return x + y;
		}) / lastQueryTimes.length : 0;
	};
	Object.defineProperty(exports, "averageQueryTime", {
		get: function () {
			return averageQueryTime;
		}
	});

	//记录参数
	var queryTicketUrl = null;
	var lastLogTime = null;
	var isLogOpen = false;

	var detectSuggest = function (result) {
		result.suggestTransit = result.available.length > 0 && result.available.length <= 3;
		var notFeCount = _.count(result.available, function (t) {
			return t.from.endpoint && t.to.endpoint;
		});
		result.suggestMoreStat = notFeCount < 4 && notFeCount < result.available.length / 3;

		result.hasSuggest = result.suggestMoreStat | result.suggestTransit;
	};

	var getTicketInfo = function (v) {
		var data = [], info = v.indexOf("#") === -1 ? v : /getSelected\(['"](.*?)['"]\)/i.exec(v)[1].split('#')[11],
			match = info.match(/([A-Z\d])0*?([\*\d]{5})0*?(\d{4})/gi);

		for (var j in match) {
			if (match.hasOwnProperty(j)) {
				var m = /([A-Z\d])0*?([\*\d]{5})0*?(\d{4})/i.exec(match[j]);
				var sc = m[1];
				var sp = m[2][0] === '*' ? null : parseInt(m[2], 10);
				var st = parseInt(m[3], 10);
				var seat = { code: sc, name: param.toSeatTypeName(sc), price: sp, selected: false };
				if (st < 3000) {
					seat.count = st;

					//TODO 二等软座提交是否和二等座一样都用的MO?
					//一等软座 7, 二等软座 8
					if (sc === "7") {
						data.push({ code: "M", name: param.toSeatTypeName("M"), price: sp, count: st, selected: false });
					} else if (sc === "8") {
						data.push({ code: "O", name: param.toSeatTypeName("O"), price: sp, count: st, selected: false });
					} else {
						data.push(seat);
					}
				} else {
					seat.count = st - 3000;
					seat.code = '0';
					seat.name = "无座";
					data.push(seat);
				}
			}
		}
		;
		return data;
	};

	var transferData = function (query, data, noProcess, noAction) {
		var result = data;
		if (!Array.isArray(result.data) || !result.data.length || !result.data[0].queryLeftNewDTO) {
			exports.events.fireEvent("requestFailed");
		}
		;

		var date = query.date;
		var trainData = {
			query: query,
			raw: result,
			rawTrainMap: {},
			trainMap: {},
			auto: null,
			nextTime: null,
			noProcess: noProcess,
			noAction: noAction
		};
		var messages = (result.messages || []).join("");

		trainData.notInSellTime = messages.indexOf("在预售日期范围") !== -1;
		_.each(result.data, function (t) {
			var train = {
				id: t.queryLeftNewDTO.train_no,
				code: t.queryLeftNewDTO.station_train_code,
				available: t.queryLeftNewDTO.canWebBuy === 'Y' ? 1 : 0,
				start: {
					code: t.queryLeftNewDTO.start_station_telecode,
					name: t.queryLeftNewDTO.start_station_name
				},
				from: {
					code: t.queryLeftNewDTO.from_station_telecode,
					fromStationNo: t.queryLeftNewDTO.from_station_no,
					name: t.queryLeftNewDTO.from_station_name,
					endpoint: t.queryLeftNewDTO.from_station_telecode === t.queryLeftNewDTO.start_station_telecode,
					time: t.queryLeftNewDTO.start_time
				},
				to: {
					code: t.queryLeftNewDTO.to_station_telecode,
					toStationNo: t.queryLeftNewDTO.to_station_no,
					name: t.queryLeftNewDTO.to_station_name,
					endpoint: t.queryLeftNewDTO.end_station_telecode === t.queryLeftNewDTO.to_station_telecode,
					time: t.queryLeftNewDTO.arrive_time
				},
				elapsedTime: {
					days: t.queryLeftNewDTO.day_difference,
					total: t.queryLeftNewDTO.lishi
				},
				end: {
					code: t.queryLeftNewDTO.end_station_telecode,
					name: t.queryLeftNewDTO.end_station_name
				},
				ypinfo: t.queryLeftNewDTO.yp_info,
				ypinfo_ex: t.queryLeftNewDTO.yp_ex,
				locationCode: t.queryLeftNewDTO.location_code,
				controlDay: t.queryLeftNewDTO.control_day,
				supportCard: t.queryLeftNewDTO.is_support_card,
				saleTime: t.queryLeftNewDTO.sale_time,
				secureStr: t.secretStr,
				selltime: null,
				date: date,
				limitSellInfo: t.buttonTextInfo && t.buttonTextInfo.indexOf("暂售") !== -1 ? t.buttonTextInfo.replace(/<[^>]+>/i, "") : null,
				controlFlag: parseInt(t.queryLeftNewDTO.controlled_train_flag || "0", 10),
				controlMessage: t.queryLeftNewDTO.controlled_train_message,
				maybeIllegal: !t.queryLeftNewDTO.controlled_train_flag
			};
			var kp = getTicketInfo(t.queryLeftNewDTO.yp_info);
			train.tickets = kp;
			train.ticketMap = _.mapObject(kp, function (e) {
				return e.code;
			});

			//起售时间
			var selltimem = /(0*(\d+)月0*(\d+)日)?(\d+)\s*点\s*((\d+)分)?\s*起售/i.exec(t.buttonTextInfo.replace(/<.*?>/g, ''));
			if (selltimem) {
				train.available = -1;
				train.selltime = new Date();
				train.selltime.setHours(parseInt(selltimem[4]));
				train.selltime.setMinutes(parseInt(selltimem[6] || "0", 10));
				train.selltime.setSeconds(0);
				if (selltimem[1]) {
					//带日期
					train.selltime.setDate(parseInt(selltimem[3]));
					train.selltime.setMonth(parseInt(selltimem[2]) - 1);
					if (train.selltime.getMonth() < new Date().getMonth()) {
						train.selltime.setFullYear(train.selltime.getFullYear() + 1);
					}
				}
			}

			trainData.rawTrainMap[train.id] = t;
			trainData.trainMap[train.id] = train;
		});
		trainData.original = _.values(trainData.trainMap);
		trainData.available = trainData.original;
		trainData.trainCodes = _.pluck(trainData.original, "code");
		trainData.filtered = [];
		trainData.include = trainData.available;

		if (!noProcess) {
			//执行车次预过滤。过滤内容:出发地,目标地,时间
			exports.events.fireEvent("filterTrains", trainData);
			//处理车次
			exports.events.fireEvent("processTrains", trainData);

			//过滤数据
			if (trainData.filtered && trainData.filtered.length) {
				//从原始数据中删除
				var orgMap = _.mapObject(result.data, function (e) {
					return e.queryLeftNewDTO.train_no;
				});
				var filtered = _.map(trainData.filtered, function (t) {
					return orgMap[t.id];
				});
				trainData.rawDataFiltered = _.without.apply(null, [result.data].concat(filtered));
				result.data = trainData.rawDataFiltered;
			}
		}

		//处理跨站购票预售提醒
		_.each(trainData.available, function (t) {
			//非预售,或预售的非当天的,始发站的,则跳过
			if (!t.selltime || Math.floor(new Date().getTime() / 86400000) !== Math.floor(t.selltime.getTime() / 86400000))
				return;
			//相同的,跳过
			if (t.start.code === t.from.code)
				return;

			//查询始发站起售时间
			var firstStationSellTime = stationData.sellTime[t.start.code];
			if (!firstStationSellTime)
				return;

			//判断始发站和当前站时间间隔。如果间隔超过指定的时间,则放弃建议
			var spanSellCurrent = Math.floor((t.selltime.getTime() % 86400000) / 1000) + 8 * 3600;	//需要加上时区
			var spanSellNow = Math.floor((new Date().getTime() % 86400000) / 1000) + 8 * 3600;
			var spanSellStart = utility.toTimeSpan(firstStationSellTime, true);
			var timeDifference = Math.abs((spanSellCurrent - spanSellStart) / 60);
			var isEarly = spanSellStart < spanSellCurrent;
			var isStartInSell = spanSellNow >= spanSellStart;
			var tCode = t.code[0];

			//if (
			//	(tCode === 'G' && timeDifference > 120)	//高铁,超过2小时
			//	||
			//	(tCode === 'D' && timeDifference > 180)	//动车,超过3小时
			//	||
			//	((tCode === 'Z' || tCode === 'T') && timeDifference > 360)	//直达/特快,超过6小时
			//	||
			//	timeDifference > 600	//其它类型车次大于10小时
			//	)
			//	return;

			t.preStationInfo = "<span class='train-nostarttip train-nostarttip-" + (isStartInSell ? "insell" : isEarly ? "early" : "later") + "'>";
			t.preStationInfo += "始发站【<a href='javascript:;' data-ts-code='" + t.start.code + "' data-train-code='" + t.code + "' data-command='suggest-swtichrelate'>" + t.start.name + "</a>】起售时间为【" + firstStationSellTime + "】," + (isStartInSell ? "已经在售" : isEarly ? "比当前车站起售时间早,可先去看看" : "可稍后留意");
			t.preStationInfo += "</span>";
		});
		detectSuggest(trainData);

		return trainData;
	};

	exports.queryTicket = function (from, fromName, to, toName, date, student, resign, noProcess, noAction, byAuto) {
		var def = new $.Deferred();
		var queryCount = 0;
		var queryLogSubmited = false;
		var queryStartTime, queryEndTime;

		def.fail(function () {
			exports.events.fireEvent("requestFailed");
		});

		//before query event.
		if (!noAction && !noProcess) {
			var evdata = {
				from: from,
				fromName: fromName,
				to: to,
				toName: toName,
				auto: byAuto || false
			};
			exports.events.fireEvent("beforeQueryTicket", evdata);
			from = evdata.from;
			to = evdata.to;
			fromName = evdata.fromName;
			toName = evdata.toName;
		}

		var queryFail = function () {
			if (queryCount++ < 5) {
				def.notify({ action: "requery" });
				//def.notify("12306出问题了,正在第 " + queryCount + " 次重连...");
				setTimeout(sendQueryRequest, 2000);
			} else {
				def.reject("12306出问题了,请稍后重试...");
			}
		};

		var sendQueryRequest = function () {
			var p = {
				"leftTicketDTO.train_date": date,
				"leftTicketDTO.from_station": from,
				"leftTicketDTO.to_station": to,
				"purpose_codes": student ? "0X00" : "ADULT"
			};
			var cookie = (function (obj) {
				var arr = [];
				_.forEach(obj, function (v, k) {
					arr.push(k + '=' + v);
				});
				return arr.join("; ");
			})(extensionVersion >= 720 ? {
				"_jc_save_fromStation": escape(fromName + "," + from),
				"_jc_save_toStation": escape(toName + "," + to),
				"_jc_save_fromDate": date,
				"_jc_save_toDate": date,
				"_jc_save_wfdc_flag": resign ? "gc" : "dc"
			} : {});
			if (isLogOpen) {
				exports.log(p, cookie, true);
			}
			queryStartTime = new Date().getTime();
			ajax.sendGet(queryTicketUrl, "leftTicket/init", p, "json", function () {
				if (!this.model) {
					queryFail();
					return;
				}
				//url changed?
				if (!this.model.status && this.model.c_url) {
					queryTicketUrl = this.model.c_url;
					sendQueryRequest();
				} else if (!this.model.status) {
					var error = parser.getError(this.model);
					if (error && error.message && error.message.indexOf("查询失败") !== -1) {
						exports.log(p, cookie, true).always(queryFail);
						return;
					}

					queryFail();
				} else {
					queryEndTime = new Date().getTime();
					calculateQueryTime(queryEndTime - queryStartTime);

					var data = transferData({
						from: from,
						fromName: fromName,
						to: to,
						toName: toName,
						auto: byAuto || false,
						date: date,
						resign: resign,
						student: student || false
					}, this.model, noProcess, noAction);
					def.resolveWith(data);
				}
			}, queryFail, false, {
				"Cookie": cookie,
				"If-Modified-Since": "0"
			});
		};
		var fetchTicketUrl = function () {
			ajax.sendGet("leftTicket/init", "/otn/", null, "text")
				.done(function () {
					var html = this.model;

					dynamicjs.checkDynamicJs(html, "leftTicket/init");

					var r = /(CLeftTicketUrl|isSaveQueryLog)\s*=\s*['"]([^'"]+)['"]/gi;
					var m;
					while (m = r.exec(html)) {
						if (m[1] === "CLeftTicketUrl")
							queryTicketUrl = m[2];
						else if (m[1] === "isSaveQueryLog")
							isLogOpen = m[2] === "Y";
					}
					if (!queryTicketUrl) {
						//document.dispatchEvent(new CustomEvent("platformError"));
						def.reject("由于12306访问故障,未能初始化查询, 请重试");
					}
					else postFetchTicketUrl();
				}).fail(function () {
					def.reject("网络错误");
				});
		};
		var postFetchTicketUrl = function () {
			//加载查询页之后,必须要加载一次联系人,否则妥妥地出票失败。这傻逼逻辑啊。。
			if (sessmgr.isLogined) {
				sessmgr.reloadPassengers();
				sessmgr.getPassengers().always(sendQueryRequest);
			} else {
				sendQueryRequest();
			}
		};

		if (queryTicketUrl) {
			sendQueryRequest();
		}
		else {
			fetchTicketUrl();
		}

		return def.promise();
	};

	exports.log = function (data, cookies, force) {
		var def = new $.Deferred();

		if (!isLogOpen || ((lastLogTime && (new Date() - lastLogTime) < 5000) && !force)) {
			def.reject();
			return def.promise();
		}
		lastLogTime = new Date();
		ajax.sendGet("leftTicket/log", "leftTicket/init", data, "json", function () {
			def.resolve();
		}, function () {
			def.reject();
		}, false, {
			"Cookie": cookies
		});
		return def.promise();
	};

	exports.queryTrainStop = function (id, from, to, date) {
		var data = {
			train_no: id,
			from_station_telecode: from,
			to_station_telecode: to,
			depart_date: date
		};
		var def = new $.Deferred();
		ajax.sendGet("czxx/queryByTrainNo", "leftTicket/init", data, "json", function (json) {
			if (!json || !json.data || !json.data.data) {
				def.reject((parser.getError(json) || { message: "查询失败" }).message);
			} else {
				def.resolve(json.data.data);
			}
		}, function () {
			def.reject("网络错误");
		});

		return def.promise();
	};
});