!function($, w, d, undefined) {
	'use strict';
	var
		ERROR_CLASS = 'danger',
		WARNING_CLASS = 'warning',
		SUCCESS_CLASS = 'success',
		notice_counter = 0,

		publisher,
		session,

		o = {
			apiKey: "",
			token: "",
			sessionId: "",
			debug: false,
			name: 'publisher',
			notificationHeight:113,
			publisher: {
				width: 320,
				height: 240,
			},
			subscriber: {
				width: 320,
				height: 240,
			},
			lang: {},
			autoResize: true,
			noticeTmpl: function() {},
		};

	var exceptionHandler = {
		handlers: {
			"code === 1006 || code === 1008 || code === 1014" : "reconnect",
		},

		reconnect: function(event) {
			raiseNotification(o.lang.error_connection, ERROR_CLASS);
			session.connect(o.apiKey, o.token);
		},

		defaultHandler: function(event) {
			raiseNotification(event.message, ERROR_CLASS);
		},

		route: function(event) {
			var
				handlers = exceptionHandler.handlers,
				condition,
				code = event.code;

			for(var i in handlers) {
				condition = eval(i);
				if(condition === true) {
					exceptionHandler[handlers[i]](event);
					return true;
				}
			}
			exceptionHandler.defaultHandler(event);
		},
	}

	function modifiyNoticeHeight() {
		if($('#notification').height() >= o.maxNotificationHeight) {
			$('#notification').css("overflow-y", "scroll");
		}
	}

	function raiseNotification(msg, type) {
		var
			delayMS = 16000,
			fadeOutMS = 500;
		$('#notification').prepend(o.noticeTmpl.call(this, notice_counter, type, msg));
		modifiyNoticeHeight();
		$('#notice-'+ notice_counter).show().delay(delayMS).fadeOut(fadeOutMS, function(){
			$(this).remove();
			modifiyNoticeHeight();
		});
		notice_counter++;
	}

	function streamPropertyChangedHandler(event) {
		console.log(event);
	}

	function sessionConnectedHandler(event) {
		/*for(var i = 0; i < event.connections.length; i++) {
			if (event.connections[i].connectionId != session.connection.connectionId) {
				var data = $.parseJSON(event.connections[i].data);
				//raiseNotification(t("is_waiting", {"{name}": data.name }), SUCCESS_CLASS);
			}
		}*/
		//console.log(event);
		publishVideo();
		//Subscribe to streams that were in the session when we connected
		subscribeToStreams(event.streams);
		$('#disconnectLink').show();
	}

	function sessionDisconnectedHandler(event) {
		publisher = null;
		raiseNotification(t("disconnected_by_yourself"), ERROR_CLASS);
	}

	function connectionCreatedHandler(event) {}

	function connectionDestroyedHandler(event) {
		for(var i = 0; i < event.connections.length; i++) {
			var data = $.parseJSON(event.connections[i].data);
			raiseNotification(t("disconnect", {"{name}": data.name }), ERROR_CLASS);
		}
	}

	function streamCreatedHandler(event) {
		subscribeToStreams(event.streams);
	}

	function streamDestroyedHandler(event) {
		for(var i = 0; i < event.streams.length; i++) {
			if (event.streams[i].connection.connectionId != session.connection.connectionId) {
				//console.log(event.streams[i].connection.connectionId + ' ' + session.connection.connectionId);
				var data = $.parseJSON(event.streams[i].connection.data);
				raiseNotification(t("unpublish_stream", {"{name}":data.name}), WARNING_CLASS);
			}
		}
	}

	function subscribeToStreams(streams) {
		for (var i = 0; i < streams.length; i++) {
			// Make sure we don't subscribe to ourself
			if (streams[i].connection.connectionId == session.connection.connectionId) {
				return;
			}
			var data = $.parseJSON(streams[i].connection.data);
			raiseNotification(t("publish_stream", {"{name}":data.name}), SUCCESS_CLASS);
			var subscriberID = 'stream' + streams[i].streamId;
			var subscriberDiv = $(document.createElement('div')).attr('id', subscriberID).appendTo('#subscriber');
			var subscriberProps = { width: o.subscriber.width, height: o.subscriber.height };
			session.subscribe(streams[i], subscriberID, subscriberProps);
		}
	}

	function publishVideo() {
		if($.trim($("#publisher").html()).length > 0) {
			$('#unpublishVideo').show();
			$('#publishVideo').hide();
			return false;
		}

		if(!publisher) {
			var
				publisherID = 'opentok_publisher',
				publisherDiv = $(document.createElement('div')).attr('id', publisherID).appendTo('#publisher'),
				publisherProps = { width: o.publisher.width, height: o.publisher.height, name: o.name };

			publisher = TB.initPublisher(o.apiKey, publisherID, publisherProps);
			session.publish(publisher);
			$('#unpublishVideo').show();
			$('#publishVideo').hide();
			raiseNotification(t("start_stream_publeshing"), SUCCESS_CLASS);
		}
	}

	function unpublishVideo() {
		if (publisher) {
			session.unpublish(publisher);
		}
		publisher = null;
		raiseNotification(t("finish_stream_publeshing"), WARNING_CLASS);
		$('#unpublishVideo').hide();
		$('#publishVideo').show();
	}

	function connect() {
		session.connect(o.apiKey, o.token);
	}

	function disconnect() {
		if(session) {
			session.disconnect();
			window.open('','_parent','');
			window.close();
			//$('#disconnectLink').hide();
			//$('#unpublishVideo').hide();
			//$('#publishVideo').hide();
		}
	}

	function addInterfaceEventListeners() {
		$('#publishVideo').on({ click: publishVideo });
		$('#unpublishVideo').on({ click: unpublishVideo });
		//$('#connectLink').on({ click: connect });
		$('#disconnectLink').on({ click: disconnect });
	}

	$.jOpenTok = function(options) {
		o = $.extend({}, o, options);
		TB.addEventListener('exception', exceptionHandler.route);
		if(o.debug)
			TB.setLogLevel(TB.DEBUG);
		if (TB.checkSystemRequirements() != TB.HAS_REQUIREMENTS) {
			raiseNotification(t("has_not_requirements"), ERROR_CLASS);
		} else {
			if(o.autoResize) {
				calculateBlocksSize();
			}
			// Initialize session
			session = TB.initSession(o.sessionId);
			//Add event listeners to the session
			session.addEventListener('sessionConnected', sessionConnectedHandler);
			session.addEventListener('sessionDisconnected', sessionDisconnectedHandler);
			//session.addEventListener('connectionCreated', connectionCreatedHandler);
			//session.addEventListener('streamPropertyChanged', streamPropertyChangedHandler);
			session.addEventListener('connectionDestroyed', connectionDestroyedHandler);
			session.addEventListener('streamCreated', streamCreatedHandler);
			session.addEventListener('streamDestroyed', streamDestroyedHandler);

			addInterfaceEventListeners();
			// Automatically start new video conversation
			connect();
		}
	}

	function t(key, replacement) {
		var phrase = o.lang[key];
		if(typeof(phrase) == "undefined")
			return key;
		if(typeof(replacement) !== "object")
			return phrase;
		for (var i in replacement) {
			phrase = phrase.replace(i, replacement[i]);
		}
		return phrase;
	}

	// 4:3
	function calculateBlocksSize() {
		var pubWidth = Math.round(parseInt($('#publisher').width()));
		var pubHeight = Math.round(pubWidth - (pubWidth * 0.25));
		var subWidth = Math.round(parseInt($('#subscriber').width()));
		var subHeight = Math.round(subWidth - (subWidth * 0.25));

		$('#subscriber').css('height', subHeight);
		$('#publisher').css('height', pubHeight);

		o.publisher.width = pubWidth;
		o.publisher.height = pubHeight;
		o.subscriber.width = subWidth;
		o.subscriber.height = subHeight
	}

}(jQuery, window, document);