define([ 'jquery', 'knockout', 'tools/tools', 'tools/urls', 'tools/messaging', 'config' ], function() {
	'use strict';

	var $ = require('jquery');
	var tools = require('tools/tools');
	var urls = require('tools/urls');
	var messaging = require('tools/messaging');
	var config = require('config');
	var handleMessageGlobal = null;
	function handleMessage(message, event, handler) {
		tools.log('GLOBAL new message:', message);

		if (message.type && message.type === "keepalive") {
				messaging.sendTo(event.source, { type:"keepalive", message: "yes" });
				return;
		}

		if ((handleMessageGlobal) && (message !== "templateReady")) {
			handleMessageGlobal(message, event, handler);
		}
	}

	messaging.registerHandler(handleMessage);

	function sendMessageToTemplate(template, message) {
		var frame = template.$frame[0];
		messaging.sendToFrame(frame, message);
	}

	require(['jqDragAndMove', 'sammy', 'tools/jq-tools', 'tnc/tnc-transition', 'tools/tools-3d', "lib/socket.io"], function () {
		var Sammy = require('sammy');
		var jqTools = require('tools/jq-tools');
		var TncTransition = require('tnc/tnc-transition');
		var limitOpacity = tools.limitOpacity;
		var log = tools.log;
		var waitFor = tools.waitFor;
		var $new = jqTools.$new;
		var io = require("lib/socket.io");

		function tncModule() {
			var module = {};
			window.TNC = module;
			module.$overlay = $new('div', $('body'));
			module.$overlay.css({
				position: 'absolute',
				left:0, top: 0, width: '100vw', height: '100vh',
				backgroundColor:'#000',
				zIndex: 10000
			});

			module.params = urls.getQueryParams();
			var debug = module.params['debug'];
			module.debugging = (debug && window.console && window.console.info);
			module.enableEdit = false;
			module.exampleItems = false;
			module.selectLayer = false;
			module.stillPlaying = true;
			module.templateCounter = 0;
			module.getTemplateId = function() {
				module.templateCounter++;
				return 'template' + module.templateCounter;
			};
			module.templates = {};
			module.currentTemplateId = null;
			module.previousTemplateId = null;
			module.subTemplateListening = false;
			module.wait = false;

			handleMessageGlobal = function(message, event, handler) {
				if (message.url) {
					module.sendQueue.push(message);
					processSendQueue();
				}

				if (message.templateListening) {
					module.subTemplateListening = true;
				}

				if (message.templateLoaded) {

					if (message.templateId != module.currentTemplateId)
					{
						var transition = new TncTransition(message.transition);
						switchTemplates(transition);
					}
					else
					{
						log('Same template id, not switching templates', message.templateId);
					}
				}
			};

			function getNextTemplate() {
				return module.templates[module.nextTemplateId] || null;
			}

			function getCurrentTemplate() {
				return module.templates[module.currentTemplateId] || null;
			}
			function getPreviousTemplate() {
				return module.templates[module.previousTemplateId] || null;
			}

			function switchTemplates(transition) {
				if (module.nextTemplateId)
				{
					module.previousTemplateId = module.currentTemplateId;
					module.currentTemplateId = module.nextTemplateId;
					module.nextTemplateId = null;

					var $new = getCurrentTemplate().$frame;
					var $old = null;
					var prevTemplate = getPreviousTemplate();
					if (prevTemplate) {
						$old = prevTemplate.$frame;
					}

					var transitionComplete = function() {
						log('template transition complete');

						// unload template
						var prevTemplate = getPreviousTemplate();
						if (prevTemplate) {
						    // remove any templates older and not removed:
						    var prevTemplateTime = prevTemplate.$template.data("created");

							Object.keys(module.templates).forEach(function(key) {
								if (key != module.currentTemplateId && key != module.nextTemplateId) {
									delete module.templates[key];
								}
							});

							if (prevTemplateTime) {
						        $('.tncTemplate').each(function (i, e) {
						            if ($(e).data('created') <= prevTemplateTime) {
						                $(e).remove();
						            }
						        });
						    }

							module.previousTemplateId = null;
							prevTemplate = undefined;
						}
					};

					setTimeout(function() {
						transition.applyTransition(null, null, $new, $old, transitionComplete);
					}, 100);
				}
			}

			function initSocketIO() {
			    // connect to server (self)
			    var socket = io.connect(window.location.origin + '/view-client');
			    var templateIndex = 0;
			    messaging.registerHandler(function (message) {
			        if (message === "templateReady") {
			            if (socket && socket.emit) {
			                socket.emit("playerReady", { index: templateIndex });
			            }
			        }
			    });
			    socket.on("connect", function () {
			        setTimeout(function () {
			            socket.emit("playerReady", { index: templateIndex });
			        }, 1000);

			    });
			    socket.on("playTemplate", function (templateInfo) {
			        var page = "index";
			        var folder = templateInfo.template;
			        templateIndex = templateInfo.index;
			        module.$overlay.hide();
			        loadTemplateFrame(page, folder);
			    });
			};

			function initSammy() {
				var sammy = new Sammy.Application();
				module.sammy = sammy;

				sammy.get('#/off', function() {
					module.$overlay.show();

					// unload template
					var curTemplate = getCurrentTemplate();
					if (curTemplate) {
						curTemplate.$template.remove();
						delete module.templates[module.currentTemplateId];
						module.currentTemplateId = null;
						curTemplate = undefined;
					}
				});

				sammy.get('#/blank', function() {
					module.$overlay.hide();
					module.path = window.location.hash;
					loadTemplateFrame(null, null, true);
				});

				sammy.get(/\#\/page\/(.*)/, function () {
					var qry = urls.getQueryParams(window.location.hash);
					if (qry.target == 'play') {
						receiveMessage('template', 'play');
					} else {
						module.wait = qry.target == 'preload';
						module.$overlay.hide();
						var parts = this.params['splat'].pop().split('/');
						var page = parts.pop();
						var folder = parts.join('/');
						module.path = window.location.hash;
						log('Sammy new route', folder, page);
						loadTemplateFrame(page, folder);
					}
				});

				sammy.notFound = function(context) {
					var path = window.location.hash;

					if (!path || path === '' || path === '/' || path === '#/') {
						log('Sammy: Empty route, to default');
						sammy.setLocation('#/page/templates/example/index');
					} else {
						log('Sammy: Route not found\n' + path);
					}
				};

				sammy.run();
			}

			function loadTemplateFrameFromSettings(settings) {
				log('loadTemplateFrameFromSettings');

				function createParent() {
					var $parent = $new('div', module.$body, {
						class : 'tncFrameParent'
					});
					$parent.css({
						border : 0,
						width : '100vw',
						height : '100vh',
						margin : 0,
						padding : 0
					});
					return $parent;
				}

				function ensureParent() {
					module.$html = module.$html || $('html');
					module.$html.css({
						border : 0,
						margin : 0,
						padding : 0,
						overflow : 'hidden'
					});
					module.$body = module.$body || $('body');
					module.$body.css({
						border : 0,
						margin : 0,
						padding : 0,
						overflow : 'hidden',
						backgroundColor : '#000'
					});

					module.$parent = module.$parent || createParent();
				}

				function createTemplateParent(url) {
					var $template = $new('div', module.$parent, {
						class : 'tncTemplate'
					});

					$template.data("created", new Date().getTime());

					$template.css({
						position : 'absolute',
						border : 0,
						width : '100vw',
						height : '100vh'
					});

					var frameTag = 'iframe'; // 'iframe' /
					// 'webview';
					var $frame = $new(frameTag, $template, {
						class : 'tncFrame',
						src : url,
						border : 0,
						allowtransparency : 'true'
					});
					$frame.css({
						position : 'absolute',
						border : 0,
						width : '100vw',
						height : '100vh',
						opacity : limitOpacity(0)
					});

					var templateId = module.getTemplateId();
					module.templates[templateId] = {
						id : templateId,
						$template : $template,
						$frame : $frame
					};
					module.nextTemplateId = templateId;

					tools.log('templates', module.templates);
					return $template;
				}
				ensureParent();

				var debug = module.params['debug'];
				var wait = module.wait;
				var edit = module.params['edit'];
				var exampleitems = module.params['exampleitems'];
                var resolution = module.params['resolution'];
                var novideo = module.params['novideo'];

				var url = 'template.htm';

				if (debug) {
					url = urls.updateQueryString(url, 'debug', '1');
				}
				if (wait) {
					url = urls.updateQueryString(url, 'wait', '1');
				}
				if (edit) {
					url = urls.updateQueryString(url, 'edit', '1');
				}
				if (exampleitems) {
					url = urls.updateQueryString(url, 'exampleitems', '1');
				}
                if (resolution) {
					url = urls.updateQueryString(url, 'resolution', resolution);
				}
                if (novideo) {
					url = urls.updateQueryString(url, 'novideo', novideo);
				}

				url = url + (module.path || "");

				tools.log(url);
				createTemplateParent(url);

					waitFor(function() {
						return module.subTemplateListening;
					}, function() {
						var nextTemplate = getNextTemplate();
						if (nextTemplate)
						{
							module.subTemplateListening = false;
							sendMessageToTemplate(nextTemplate, {
							    templateId : nextTemplate.id,
							    folder: module.folder,
							    //settings: settings,
                                page : module.page
							});
						}
					}, 200);
			}

			function loadTemplateFrame(page, folder, blank) {
				var path = page;

				if (blank) {
					page = 'blank';
					folder = 'theme';
				}

				if (folder) {
					path = folder + '/' + page;
				}

				module.page = page;
				module.folder = folder;

				function loadTemplateFrameFromResponse(response) {
					try {
						var settings = JSON.parse(response);
						settings.css = path + '.css';
						loadTemplateFrameFromSettings(settings);
					} catch (e) {
						log(e);
						console.trace();
					}
				}

				var r = $.ajax({
					url : path + '.json',
					cache : false
				});
				r.always(function() {
					if (r.responseText) {
						loadTemplateFrameFromResponse(r.responseText);
					} else {
						log('Page not found: ' + path);
					}
				});
			}

			module.sendQueue = module.sendQueue || [];
			module.sending = false;

			function processSendQueue() {
				// log('processSendQueue', module.sending);
				if (!module.sending) {
					var message = module.sendQueue.pop();
					if (message) {
						module.sending = true;
						try {
							$.ajax(message.url, {
								data : message.data,
								cache : false
							});

							setTimeout(function() {
								module.sending = false;
								processSendQueue();
							}, 100);
						} catch (e) {
							module.sending = false;
							log(e);
						}
					}
				}
			}

			function receiveMessage(type, object) {
				var currentTemplate = null;
				waitFor(function() {
					currentTemplate = getCurrentTemplate();
					return currentTemplate;
				}, function() {
					sendMessageToTemplate(currentTemplate, {
						cef : {
							type : type,
							object : object
						}
					});
				}, 200);
			}

			window.GetCefMessage = receiveMessage;

			function documentReady() {
			    tools.log('document ready!');
			    if (config.isDesktop) {
			        initSammy();
			    } else {
			        initSocketIO();
			    }
			}
			$(document).ready(documentReady);
		}
		tncModule();
	});
});
