"use strict";

var jQuery = require("jquery");
var Utility = require("./Utility.js");
var handleMouseEvent = require("./MouseEvent.js");
var getStats = require("./getStats");
var Condicio = require("condicio");

function StreamDisplayer(session, viewID, parentElem, turnServer, callback) {
    var _this = this;

	this.session = session;
	this.viewID = viewID;
	this.parentElem = parentElem;
	
	// 创建播放div元素
	this.displayElem = this.createDisplayElem();
	
	// 创建流播放器
	this.video = this.createVideo();
	
	// 处理大小变化
    this.handleDisplayElemSizeChange();
	
	// 处理鼠标事件
	handleMouseEvent(session, viewID, this.displayElem);
	
	// 创建P2P连接
	this.createP2PCommunication(turnServer, callback);
};

StreamDisplayer.prototype.release = function(){
	this.parentElem.removeChild(this.displayElem);
};

// 创建显示元素
StreamDisplayer.prototype.createDisplayElem = function() {
	var displayElem = document.createElement('div');
	this.parentElem.appendChild(displayElem);
	
	// TODO:目标是让外部能够区分显示的div,这里应该由外部想办法区分,而不应该内部处理
	jQuery(this.displayElem).attr("id","bcd"); 
	
	// 不让选中,避免引起闪屏
	displayElem.onselectstart = function(){ return false; };
	
	return displayElem;
};

// 创建视频播放器
StreamDisplayer.prototype.createVideo = function() {
	var video = document.createElement("video");
	video.autoplay = true;	// 自动播放
	video.muted = true; 	// 不输出音频
	
	this.displayElem.appendChild(video);
	
	//阻止默认事件,保证不影响上层事件,目的是保证最上层能正确获取鼠标消息
	jQuery(video).on('mousedown', function (e){
		e.preventDefault();	
	});
	
	return video;
};

// 处理DispalyElem的大小变化
StreamDisplayer.prototype.handleDisplayElemSizeChange = function() {
	var _this = this;
	
	// 处理大小变化
    var resizeListener = function () {
        var w = jQuery(_this.parentElem).width();
        var h = jQuery(_this.parentElem).height();

        if (_this.video.width !== w || _this.video.height !== h) {
            _this.video.width = w;
            _this.video.height = h;

            _this.session.request(_this.viewID, "resize", { width: w, height: h });
       }

        setTimeout(resizeListener, 200)
    }
    resizeListener();
};

// 创建PeerConnetion
function createPeerConnection(turnServer) {
	var iceServer = {
		"iceServers":[
			{
				"urls": ["turn:"+turnServer.ip+":"+ turnServer.port +"?transport=udp",
						 "turn:"+turnServer.ip+":"+ turnServer.port +"?transport=tcp"],
				"username":turnServer.userName,
				"credential":turnServer.password
			}
		]
	};	
	
	return new RTCPeerConnection(iceServer);
};

// 向服务器注册ICE协商函数
function registerIceCandidateCallback(session, viewID, peerConnection, callback){
	var callbackWrapper = function (error, result) {	
		if(!error) {
			var candidate = new RTCIceCandidate(result.sdpObj);
			peerConnection.addIceCandidate(candidate);
		}
		else {
			callback(error);
		}
	};
	
	var callbackID = Utility.genGUID();
	session.registerCallback(callbackID, callbackWrapper, "IceCandidateCallback", true);
	session.request(viewID, "registerIceCandidateCallback", {"callbackID": callbackID});
}

// 向服务器请求SDP
function requestSDPOffer(session, viewID, peerConnection, callback){
	var callbackWrapper = function (error, offerSDP) {	
		if (error)
			callback(error);
		else {
			peerConnection.setRemoteDescription(new RTCSessionDescription(offerSDP.sdpObj));
			
			var createAnswerSucced = function(answer) {
				peerConnection.setLocalDescription(answer);
				
				var callbackError = function (error) {
					if(error)
						callback(error);
				};
				var callbackID = Utility.genGUID();
				session.registerCallback(callbackID, callbackError);
				
				session.request(viewID,  "sendSDPAnswer", {"sdpObj": answer,"callbackID": callbackID});
			};
			peerConnection.createAnswer(createAnswerSucced, function (error) {
				callback(error);
			});
		}
	};
	
	var callbackID = Utility.genGUID();
	session.registerCallback(callbackID, callbackWrapper);
	session.request(viewID,  "requestSDPOffer", {"callbackID": callbackID});
}

// 向服务器发送状态信息
function loopSendStatsInfos(session, viewID, peerConnection) {
	
	var preStatsInfo = "";
	var handleStatsFunc = function(result) {
		var results = result.results;
		
		for (var i = 0; i < results.length; i++) {
			if (results[i].type == 'ssrc' && !Condicio.isUndefined(results[i].googTimingFrameInfo)) {
				var statsInfo = {};
				
				var timeInfos = results[i].googTimingFrameInfo.split(",");
				statsInfo.encodeTime = Number(timeInfos[3]) - Number(timeInfos[2]);
				statsInfo.packetTime = Number(timeInfos[4]) - Number(timeInfos[3]);
				statsInfo.sendTime = Number(timeInfos[5]) - Number(timeInfos[4]);
				statsInfo.receiveTime = Number(timeInfos[9]) - Number(timeInfos[8]);
				statsInfo.bufferTime = Number(timeInfos[10]) - Number(timeInfos[9]);
				statsInfo.decodeTime = Number(timeInfos[11]) - Number(timeInfos[10]);
				
				if (preStatsInfo != JSON.stringify(statsInfo)) {				
					session.request(viewID, "sendStatsInfo", { "statsInfo": statsInfo });
					
					preStatsInfo = JSON.stringify(statsInfo);
				}
			}
		}
	};
	
	getStats(peerConnection, handleStatsFunc, 50);  
};

// 建立P2P通信
StreamDisplayer.prototype.createP2PCommunication = function(turnServer, callback) {
	var _this = this;
	
	var peerConnection = createPeerConnection(turnServer);
	
	peerConnection.onaddstream = function(event) {
        _this.video.srcObject = event.stream;

        loopSendStatsInfos(_this.session, _this.viewID, peerConnection);
	};
	
	peerConnection.oniceconnectionstatechange = function(ev) {
		var connection = ev.target;
		switch(connection.iceConnectionState) {
			case "connected":
				callback(null);
				break;
			case "failed":
				callback("create view3D failed: webrtc connect failed");
				break;
		}
	}
	
	registerIceCandidateCallback(this.session, this.viewID, peerConnection, callback);
	
	peerConnection.onicecandidate = function(event) {
		if (event.candidate !== null) {
			
			var callbackError = function (error) {
				if(error)
					callback(error);
			};
			var callbackID = Utility.genGUID();
			_this.session.registerCallback(callbackID, callbackError);
			
			_this.session.request(_this.viewID,  "sendIceCandidate", {"candidate": event.candidate,"callbackID": callbackID});
		}
	};
	
	requestSDPOffer(this.session, this.viewID, peerConnection, callback);
};

module.exports = StreamDisplayer;