/* WebRTC PubNub Controller
 * Author: Kevin Gleason
 * Date: July 15, 2015
 * Description: A wrapper library for the PubNub WebRTC SDK to make simple video
 *              functions a breeze to implement.
 *
 * TODO: make getVideoElement a native non-jQuery function
 *
 */

(function(){
	
	
var CONTROLLER = window.CONTROLLER = function(phone){
	if (!window.phone) window.phone = phone;
	var ctrlChan  = controlChannel(phone.number());
	var pubnub    = phone.pubnub;
	var userArray = [];
	subscribe();
	
	var CONTROLLER = function(){};
	
	// Get the control version of a users channel
	function controlChannel(number){
		return number + "-ctrl";
	}
	
	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
	// Setup Phone and Session callbacks.
	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
	var readycb   = function(){};
	var unablecb  = function(){};
    var receivecb = function(session){};
    var videotogglecb = function(session, isEnabled){};
    var audiotogglecb = function(session, isEnabled){};
    
    CONTROLLER.ready   = function(cb) { readycb   = cb };
    CONTROLLER.unable  = function(cb) { unablecb  = cb };
    CONTROLLER.receive = function(cb) { receivecb = cb };
    CONTROLLER.videoToggled = function(cb) { videotogglecb = cb };
    CONTROLLER.audioToggled = function(cb) { audiotogglecb = cb };
	
	phone.ready(function(){ readycb() });
	phone.unable(function(){ unablecb() });
	phone.receive(function(session){
		manage_users(session);
		receivecb(session);
	});
	
	/* Require some boolean form of authentication to accept a call
	var authcb    = function(){};
	CONTROLLER.answerCall = function(session, auth, cb){
		auth(acceptCall(session, cb), session);
	}
	
	function acceptCall(session, cb){ // Return function bound to session that needs a boolean.
		return function(accept) {
			if (accept) cb(session);
			else phone.hangup(session.number); 
		}
	}*/
	
	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
	// Setup broadcasting, your screen to all.
	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
	var streamreceivecb = function(m){}; 
	var streamprescb    = function(m){};
	var stream_name = "";
	
	
	CONTROLLER.streamPresence = function(cb){ streamprescb    = cb; }
	CONTROLLER.streamReceive  = function(cb){ streamreceivecb = cb; }
	
	function broadcast(vid){
	    var video = document.createElement('video');
        video.src    = URL.createObjectURL(phone.mystream);
        video.volume = 0.0;
        video.play();
	    video.setAttribute( 'autoplay', 'autoplay' );
	    video.setAttribute( 'data-number', phone.number() );
	    vid.style.cssText ="-moz-transform: scale(-1, 1); \
						 	-webkit-transform: scale(-1, 1); -o-transform: scale(-1, 1); \
							transform: scale(-1, 1); filter: FlipH;";
		vid.appendChild(video);
    };
    
    function stream_subscribe(name){
	    var ch = (name ? name : phone.number()) + "-stream";
	    pubnub.subscribe({
            channel    : ch,
            message    : streamreceivecb,
            presence   : streamprescb,
            connect    : function() { stream_name = ch; console.log("Streaming channel " + ch); }
        });
    }
    
    CONTROLLER.stream = function(){
	    stream_subscribe();
    }
    
    CONTROLLER.joinStream = function(name){
	    stream_subscribe(name);
	    publishCtrl(controlChannel(name), "userJoin", phone.number());
    }
    
    CONTROLLER.leaveStream = function(name){
	    var ch = (name ? name : phone.number()) + "-stream";
	    pubnub.unsubscribe({
            channel    : ch,
        });
    }
    
    CONTROLLER.send = function( message, number ) {
        if (phone.oneway) return stream_message(message);
        phone.send(message, number);
    };
    
    function stream_message(message){
	    if (!stream_name) return; // Not in a stream
		pubnub.publish({ 
			channel: stream_name,
			message: msg,
			callback : function(m){console.log(m)}
		});
    }
    
    
    // Give it a div and it will set up the thumbnail image
    CONTROLLER.addLocalStream = function(streamHolder){
	    broadcast(streamHolder);
    };
	
	CONTROLLER.dial = function(number){ // Authenticate here??
		var session = phone.dial(number, get_xirsys_servers()); // Dial Number
		if (!session) return; // No Duplicate Dialing Allowed
	};
	
	CONTROLLER.hangup = function(number){
		if (number) {
			if (phone.oneway) CONTROLLER.leaveStream(number);
			phone.hangup(number);
			return publishCtrl(controlChannel(number), "userLeave", phone.number())
		} 
		if (phone.oneway) CONTROLLER.leaveStream();
		phone.hangup();
		for (var i=0; i < userArray.length; i++) {
			var cChan = controlChannel(userArray[i].number);
			publishCtrl(cChan, "userLeave", phone.number());
		}
	};
	
	CONTROLLER.toggleAudio = function(){
		var audio = false;
		var audioTracks = window.phone.mystream.getAudioTracks();
		for (var i = 0, l = audioTracks.length; i < l; i++) {
			audioTracks[i].enabled = !audioTracks[i].enabled;
			audio = audioTracks[i].enabled;
		}
		publishCtrlAll("userAudio", {user : phone.number(), audio:audio}); // Stream false if paused
		return audio;
	};
	
	CONTROLLER.toggleVideo = function(){
		var video = false;
		var videoTracks = window.phone.mystream.getVideoTracks();
		for (var i = 0, l = videoTracks.length; i < l; i++) {
			videoTracks[i].enabled = !videoTracks[i].enabled;
			video = videoTracks[i].enabled;
		}
		publishCtrlAll("userVideo", {user : phone.number(), video:video}); // Stream false if paused
		return video;
	};
	
	CONTROLLER.isOnline = function(number, cb){
		pubnub.here_now({
			channel : number,
				cb(m.occupancy != 0);
			}
		});
	};
	
	CONTROLLER.isStreaming = function(number, cb){
		CONTROLLER.isOnline(number+"-stream", cb);
	};
	
	CONTROLLER.getVideoElement = function(number){
		return $('*[data-number="'+number+'"]');
	}
	
	function manage_users(session){
		if (session.number == phone.number()) return; 	// Do nothing if it is self.
		var idx = findWithAttr(userArray, "number", session.number); // Find session by number
		if (session.closed){
			if (idx != -1) userArray.splice(idx, 1)[0]; // User leaving
		} else {  				// New User added to stream/group
			if (idx == -1) {  	// Tell everyone in array of new user first, then add to array. 
				if (!phone.oneway) publishCtrlAll("userJoin", session.number);
				userArray.push(session);
			}
		}
		userArray = userArray.filter(function(s){ return !s.closed; }); // Clean to only open talks
		// console.log(userArray);
	}
	
	function add_to_stream(number){
		phone.dial(number);
	}
	
	function add_to_group(number){
		var session = phone.dial(number, get_xirsys_servers()); // Dial Number
		if (!session) return; 	// No Dupelicate Dialing Allowed
	}
	
	function publishCtrlAll(type, data){
		for (var i=0; i < userArray.length; i++) {
			var cChan = controlChannel(userArray[i].number);
			publishCtrl(cChan, type, data);
		}
	}
	
	function publishCtrl(ch, type, data){
		// console.log("Pub to " + ch);
		var msg = {type: type, data: data};
		pubnub.publish({ 
			channel: ch,
			message: msg,
			callback : function(m){console.log(m)}
		});
	}
	
	function subscribe(){
		pubnub.subscribe({
            channel    : ctrlChan,
            message    : receive,
            connect    : function() {} // console.log("Subscribed to " + ctrlChan); }
        });
	}
	
	function receive(m){
		switch(m.type) {
		case "userCall":
			callAuth(m.data);
			break;
		case "userJoin":
			if (phone.oneway){ add_to_stream(m.data); }// JOIN STREAM HERE!
			else add_to_group(m.data);
			break;
		case "userLeave":
			var idx = findWithAttr(userArray, "number", m.data);
			if (idx != -1) userArray.splice(idx, 1)[0];
			break;
		case "userVideo":
			var idx = findWithAttr(userArray, "number", m.data.user);
			var vidEnabled = m.data.video;
			if (idx != -1) videotogglecb(userArray[idx], vidEnabled);
			break;
		case "userAudio":
			var idx = findWithAttr(userArray, "number", m.data.user);
			var audEnabled = m.data.audio;
			if (idx != -1) audiotogglecb(userArray[idx], audEnabled);
			break;
		}
		// console.log(m);
	}
	
	function findWithAttr(array, attr, value) {
	    for(var i = 0; i < array.length; i += 1) {
	        if(array[i][attr] === value) {
	            return i;
	        }
	    }
	    return -1;
	}
	
	return CONTROLLER;
}

})();

// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Request fresh TURN servers from XirSys - Need to explain.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function get_xirsys_servers() {
    var servers;
    $.ajax({
        type: 'POST',
        url: 'https://api.xirsys.com/getIceServers',
        data: {
            room: 'default',
            application: 'default',
            domain: 'www.pubnub-example.com',
            ident: 'pubnub',
            secret: 'dec77661-9b0e-4b19-90d7-3bc3877e64ce',
        },
        success: function(res) {
            res = JSON.parse(res);
            if (!res.e) servers = res.d.iceServers;
        },
        async: false
    });
    return servers;
}
			callback : function(m){
				console.log(m);  // TODO Comment out