define(
       ['scripts/knockout-3.3.0','scripts/jquery-2.1.1.min','scripts/jquery-ui.min', 'scripts/ACTUtils.js',
       'jqx/jqxknockout','jqx/jqxcore', 'jqx/jqxwindow', 'jqx/jqxnotification'],
       function(ko, jquery, jquery_ui, ACTUtils, jqxKnockout, jqxCore, jqxWindow) {

// no multiple initialisation
if (typeof _socket !== 'undefined' && _socket)
	return _socket;

var ACTPort = 0;
var ACTSocketName = "";
var _webSockets = {};
var _sockets_loaded = false;

function ACTSocket() {
	this.socket = null;
	this.send = null;
	this.services = {};
	this.waitingSevices = {};
	this.messageId = ko.observable(0);
	this.messageId.extend({ rateLimit: 0, notify: 'always' });
	this.currentMessageId = 0;
	this.lastMessageId = 0;
	this.messages = {};

	this.registerService = function(name, fct) {
		this.services[name] = fct;
		var waitingService = this.waitingSevices[name];
		if (typeof waitingService !== "undefined") {
			for (var index = 0; index < waitingService.length; index++)
				fct(waitingService[index])
			delete this.waitingSevices[name];
		}
	}.bind(this);
}

_socket = new ACTSocket();
ACTUtils.ACTSocket = _socket;

var $errorDialog = $(".errorDialog");
$errorDialog.jqxWindow({
	autoOpen         : false,
	keyboardCloseKey : '',
	animationType    : 'none',
	width            : 'auto',
	height           : 'auto',
	resizable        : false,
	showCloseButton  : true,
	draggable        : false,
	isModal          : true,
});

var $notification = $(".actNotification");
$notification.jqxNotification({
	width: "auto",                 // to have a notification that fit the text
	opacity: 0.9,
	autoOpen: false,
	animationOpenDelay: 800,
	autoClose: true,
	autoCloseDelay: 3000,
});

$(document).ready(function () {

	ACTPort = 0;
	ACTServer = "localhost";
	if (typeof Params === "undefined") {
		var QueryString = function () {
			// This function is anonymous, is executed immediately and 
			// the return value is assigned to QueryString!
			var query_string = {};
			var query = window.location.search.substring(1);
			var vars = query.split("&");
			for (var i = 0; i < vars.length; i++) {
				var pair = vars[i].split("=");
				// If first entry with this name
				if (typeof query_string[pair[0]] === "undefined") {
					query_string[pair[0]] = pair[1];
					// If second entry with this name
				} else if (typeof query_string[pair[0]] === "string") {
					var arr = [query_string[pair[0]], pair[1]];
					query_string[pair[0]] = arr;
					// If third or later entry with this name
				} else {
					query_string[pair[0]].push(pair[1]);
				}
			}
			return query_string;
		}();
		if (typeof QueryString.ACTPort === "undefined") {
			ACTPort = 0;
		} else {
			ACTPort = QueryString.ACTPort;
		}
		if (typeof QueryString.ACTSocketName === "undefined") {
			ACTSocketName = 0;
		} else {
			ACTSocketName = QueryString.ACTSocketName;
		}
		if (typeof QueryString.ACTServer === "undefined") {
			ACTServer = "localhost";
		} else {
			ACTServer = QueryString.ACTServer;
		}
	}
	else {
		if (typeof Params.ACTPort !== "undefined") {
			ACTPort = Params.ACTPort;
			ACTSocketName = Params.ACTSocketName;
		}
		else {
			ACTPort = Params.getPropertyValue("ACTPort");
			ACTSocketName = Params.getPropertyValue("ACTSocketName");
		}
		//ACTServer = Params.getPropertyValue("ACTServer");
	}

	s = _socket;
	var InitSocket = function(s, firstConnection) {
		s.socket = new WebSocket("ws://"+ACTServer+":" + ACTPort + "/ACT/"+ACTSocketName);
        s.dontReconnect = false;
		ACTUtils.Log("Create socket: "+ACTSocketName, 3);

		s.socket.onopen = function() {
			if (firstConnection) {
				s.send("FirstConnection");
			} else {
				s.send("Reconnection", null, s.lastReceivedId);
			}
		}

		s.socket.onmessage = function (msg) {
			this.currentMessageId++;
			this.messages[this.currentMessageId] = msg;
			this.messageId(this.currentMessageId)
		}.bind(s);
		
		s.messageId.subscribe(function(id) {
			var i=this.lastMessageId+1;
			var msg = this.messages[i];
			if (msg)
			{
				data = JSON.parse(msg.data);
				var obj = data.Obj;
				var service = data.Service;

				ACTUtils.Log("Access service: "+service, 2);
				if (service=="errorService") {
					$errorDialog.jqxWindow({
						content: obj.Message,
						position:"center",
						zIndex: 999999,  // always at top of others
					});
					$errorDialog.jqxWindow("open");
				} else if (service=="notification") {
					$notification.jqxNotification("template", obj.TypeNotification.toLowerCase());

					// cause the enum is TopXXX or BottomXXX and we want bot-XXX and top-XXX
					var pos = obj.Position.toLowerCase();
					if (pos[0] == "t") pos = "top-"    + pos.slice(3);
					if (pos[0] == "b") pos = "bottom-" + pos.slice(6);
					$notification.jqxNotification("position", pos);

					$notification.find(".jqx-notification-content").text(obj.Message);
					$notification.jqxNotification("open");
                }else if (service == "Deconnection"){
                    s.dontReconnect = true;
                    s.socket.close();
				} else if (typeof this.services[service] !== "undefined") {
					this.services[service](obj);
				} else {
					if (typeof this.waitingSevices[service] === "undefined")
						this.waitingSevices[service] = []
					this.waitingSevices[service].push(obj)
				}
				ACTUtils.Log("End access service: "+service, 2);
				this.lastMessageId = i;
				delete this.messages[i];

				s.lastReceivedId = data.SendId;
			}
			if (this.currentMessageId>i) {
				this.messageId(i+1);
			}
		}.bind(s));

		s.socket.onerror = function(error) {
			console.error("Socket error : " + error);
		}
		s.socket.onclose = function(event) {
            if (s.dontReconnect == true){
                console.warn("Socket closed ! Do not reconnect !!!");
            }else{
                console.warn("Socket close ! Reconnection ...");
                InitSocket(s, false);
            }
		}
	}

	InitSocket(s, true);
	s.send = function (serviceName, obj, sendId) {
		var data = {
			$type: "Ansys.ACT.Core.UI.ServiceWebObject, Ansys.ACT.Core, Culture=neutral, PublicKeyToken=null",
			Service: serviceName,
			Obj: obj,
			SendId: sendId,
		};
		var msg = JSON.stringify(data);
		
		if (this.socket.readyState>1) {
			location.reload();
		}
		
		setTimeout(function(){
			this.socket.send(msg);
		}.bind(this), 50);
	}.bind(s);
});

return _socket;
});
