﻿(function () {
    if (!window.console || !console.firebug) {
        window.console = {};
    }
    var methods = [
        "log", "debug", "info", "warn", "error", "assert",
        "dir", "dirxml", "group", "groupEnd", "time", "timeEnd",
        "count", "trace", "profile", "profileEnd"
    ];
    for (var i = 0; i < methods.length; i++) {
        if (window.console[methods[i]] == undefined) window.console[methods[i]] = function () { };
    }
})();


// We use DelawareCommons as a kind of namespace, we avoid global functions and variables

var DelawareCommons = {

	retrieveServerData: function (url, jsonObject, executeOnError) {
		var me = this;

		this.logToConsole(url);

		var startAjaxCall = me.startProfile();
		var retrievedData = j.ajax({
			type: "POST",
			url: url,
			// it must be sync call to return the retrieved data
			async: false,
			data: Object.toJSON ? Object.toJSON(jsonObject) : JSON.stringify(jsonObject),
			dataType: "html",
			success: function (data, textStatus) {

				me.endProfile(startAjaxCall, "sync j.ajax return from server");
			},

			error: function (XMLHttpRequest, textStatus, errorThrown) {

				if (XMLHttpRequest.status == 0) {
					// No error, ajax call was cancelled (example: FF back or F5)
					// => do nothing
					return;
				}

				DelawareCommons.showException(XMLHttpRequest, textStatus, errorThrown);

				if (executeOnError) {
					executeOnError();
				}

			}
		}).responseText;
		if (retrievedData == null) {
			return null;
		}

		return retrievedData == "" ? "" : eval('(' + retrievedData + ')');
	},

	retrieveServerDataAsync: function (sender, url, jsonObject, executeOnError, executeOnSuccess, callbackArgs) {
		var me = this;

		this.logToConsole(url);

		var startAjaxCall = this.startProfile();
		j.ajax({
			type: "POST",
			url: url,
			async: true,
			data: Object.toJSON ? Object.toJSON(jsonObject) : JSON.stringify(jsonObject),
			dataType: "html",
			success: function (data, textStatus) {
				me.endProfile(startAjaxCall, "async j.ajax return from server");

				if (data != null && data != "") data = eval("(" + data + ")");
				if (executeOnSuccess) executeOnSuccess(sender, data, callbackArgs);
			},
			error: function (XMLHttpRequest, textStatus, errorThrown) {
				if (XMLHttpRequest.status == 0) {
					// No error, ajax call was cancelled (example: FF back or F5)
					// -> do nothing
					return;
				}

				DelawareCommons.showException(XMLHttpRequest, textStatus, errorThrown);

				if (executeOnError) executeOnError();
			}
		});
	},

	// see defaultOptions to know which options you can add to this function
	executePartialUpdate: function (options) {
		var me = this;

		var defaultOptions = {
			updateUrl: null, //Ajax url to be called on server
			dataSource: DelawareCommons.getPageId(), // data source of item in Sitecore, which is used to set CurrentContentItem
			jsonObject: null, // parameter object used in the renderContext.RequestParameter of the Action
			withoutWaitPanel: false,
			executeOnValidationError: jQuery.noop,
			executeOnSuccess: jQuery.noop,
			executeOnError: jQuery.noop
		};
		var myOptions = j.extend(defaultOptions, options);

		DelawareCommons.debugAssert(myOptions.updateUrl != null, "updateUrl required");
		DelawareCommons.debugAssert(myOptions.dataSource != null, "dataSource required");

		var useWaitPanel = (myOptions.withoutWaitPanel != true);
		if (useWaitPanel)
			DelawareCommons.showWaitPanel();


		var startAjaxCall = this.startProfile();
		var finalUrl = myOptions.updateUrl;
		if (finalUrl.indexOf('?') > 0) {
			finalUrl = finalUrl + "&ds=" + myOptions.dataSource;
		}
		else {
			finalUrl = finalUrl + "?ds=" + myOptions.dataSource;
		}
		this.logToConsole(finalUrl);

		j.ajax({
			type: "POST",
			url: finalUrl,
			data: Object.toJSON ? Object.toJSON(myOptions.jsonObject) : JSON.stringify(myOptions.jsonObject),
			dataType: "html",
			success: function (data, textStatus) {

				me.endProfile(startAjaxCall, "j.ajax return from server");

				var result = data == "" ? "" : eval('(' + data + ')');

				me.logToConsole("Machine: " + result.MachineName);

				if (!result.IsValid && myOptions.executeOnValidationError) {

					// parse the data received from the server and see whether the data contains an error code
					myOptions.executeOnValidationError(result);
					if (useWaitPanel) DelawareCommons.hideWaitPanel();
					return;
				};

				DelawareCommons.updateDivs(result.Updates);

				if (myOptions.executeOnSuccess) {
					myOptions.executeOnSuccess(result);
				}

				if (useWaitPanel)
					DelawareCommons.hideWaitPanel();


				me.endProfile(startAjaxCall, "j.ajax completed");
			},
			error: function (XMLHttpRequest, textStatus, errorThrown) {

				if (useWaitPanel) DelawareCommons.hideWaitPanel();

				if (XMLHttpRequest.status == 0) {
					// No error, ajax call was cancelled (example: FF back or F5)
					// => do nothing
					return;
				}

				DelawareCommons.showException(XMLHttpRequest, textStatus, errorThrown);

				if (myOptions.executeOnError) {
					myOptions.executeOnError();
				}

			}
		});
	},

	getPageId: function () {
		return j('meta[name=scID]').attr("content");
	},

	startProfile: function () {
		return new Date();
	},

	endProfile: function (start, message) {

		if (!this.useDebugConsole()) {
			return;
		}
		var duration = new Date((new Date()) - start);
		var messageTxt = message == null ? "" : message + ": ";
		var logMessage = messageTxt + (duration.getSeconds() + (duration.getMilliseconds() / 1000)) + "s";
		this.logToConsole(logMessage);
	},

	useDebugConsole: function () {
		if (this.HasDebugConsole == null) {
			this.HasDebugConsole = j("#debugConsole").length > 0;
			this.DebugConsoleLineNr = 1;
		}
		return this.HasDebugConsole;
	},

	logToConsole: function (message) {
		if (this.useDebugConsole()) {
			var prefix = "<span style='color:grey;'>" + this.DebugConsoleLineNr + "&gt; </span>";
			j("#debugConsole").append("<div>" + prefix + message + "</div>");
			this.DebugConsoleLineNr++;
		}
	},
	showException: function (XMLHttpRequest, textStatus, errorThrown) {

		// Check if we are in a production environment!
		// Done server side + don't render the 'unhandledException' div
		var width = 300;
		var exceptionPanel = j("#unhandledException");
		if (exceptionPanel.length == 0) {
			// Show full debug info
			exceptionPanel = j("#debugUnhandledException");
			exceptionPanel.html(XMLHttpRequest.responseText);
			width = 800;
		}

		if (exceptionPanel.length > 0) {
			if (DelawareCommons.exceptionPanelInitialized == undefined || DelawareCommons.exceptionPanelInitialized == null || DelawareCommons.exceptionPanelInitialized == false) {
				DelawareCommons.initializeExceptionPanel();
			}

			exceptionPanel.overlay().load();
		}
	},

	showWaitPanel: function () {
		var waitPanel = j('#waitPanel');
		if (waitPanel.length > 0) {

			// Keep track of the waitPanel uses
			if (DelawareCommons.WaitPanelCount == null) {
				DelawareCommons.WaitPanelCount = 0;
			}
			// Counter < 0 ??
			if (DelawareCommons.WaitPanelCount < 0) {
				DelawareCommons.debugAssert(false, "hideWaitPanel without showWaitPanel");
				DelawareCommons.WaitPanelCount = 0;
			}
			DelawareCommons.WaitPanelCount++;

			// We already have a waitPanel?
			if (DelawareCommons.WaitPanelCount > 1) {
				// Make sure the height is correct, even after a partial update
				j("#waitPanelMask").css("height", j(document).height());
				return;
			}

			if (DelawareCommons.waitPanelInitialized == undefined || DelawareCommons.waitPanelInitialized == null || DelawareCommons.waitPanelInitialized == false) {
				DelawareCommons.initializeWaitPanel();
			}
			waitPanel.overlay().load();
		}
	},

	// hack based on http://stackoverflow.com/questions/6304560/jquery-tools-overlay-how-to-keep-mask-when-switching-overlays
	GetOverlayOptions: function (options) {

		// These are options required for all overlays.
		var requiredOptions = {
			mask: null,
			oneInstance: false,
			speed: 0
		};

		// User can also define onLoad and onClose functions. These will be executed after the expose-handling is done.
		var userOnClose = options.onClose == undefined ? jQuery.noop : options.onClose;
		var userOnBeforeLoad = options.onBeforeLoad == undefined ? jQuery.noop : options.onBeforeLoad;

		// Enforce required options on user defined options
		var myOptions = j.extend({}, options, requiredOptions);

		var jOldOverlay = null;
		var oldMaskZ = 9999;

		myOptions.onBeforeLoad = function () {
			this.getOverlay().addClass('dlwOverlay');

			if (j.mask.isLoaded()) {
				jOldOverlay = j.mask.getExposed();
				oldMaskZ = j.mask.getMask().css('z-index');

				j.mask.getMask().css('display', 'block');
				j.mask.getMask().css('z-index', oldMaskZ + 99);
				j.mask.fit();

				this.getOverlay().css('z-index', oldMaskZ + 100);
			} else {
				this.getOverlay().expose({
					color: '#666',
					loadSpeed: 200,
					opacity: 0.6,
					closeOnClick: false,
					closeOnEsc: false
				});

				j.mask.getMask().css('z-index', oldMaskZ);
				this.getOverlay().css('z-index', oldMaskZ + 1);
			}

			userOnBeforeLoad();
		};

		myOptions.onClose = function () {
			if (jOldOverlay == null) {

				// TODO: order by z-index
				// Find potentially still open dialogs on page
				var openedOverlays = [];
				var i = 0;
				j(".dlwOverlay").each(function () {
					if (j(this).data("overlay") != undefined && j(this).data("overlay") != null && j(this).overlay().isOpened()) {
						openedOverlays[i] = j(this);
					}
				});

				if (openedOverlays.length == 0) {
					j.mask.close();
				} else {
					j.mask.getMask().css('z-index', openedOverlays[0].css('z-index') - 1);
					j.mask.fit();
				}
			} else if (jOldOverlay.overlay().isOpened()) {
				jOldOverlay.css('z-index', oldMaskZ + 1);

				j.mask.getMask().css('z-index', oldMaskZ);
				j.mask.fit();
			} else {
				j.mask.close();
			}

			this.getOverlay().hide();

			userOnClose();
		};

		return myOptions;
	},

	// hack based on: http://sdevgame.wordpress.com/2011/01/26/modal-on-modal-with-jquery-tools/
	GetOverlayOptionsTryOut1: function (options) {

		// These are options required for all overlays.
		var requiredOptions = {
			mask: null,
			oneInstance: false,
			speed: 0
		};

		// User can also define onLoad and onClose functions. These will be executed after the expose-handling is done.
		var userOnLoad = options.onLoad == undefined ? jQuery.noop : options.onLoad;
		var userOnClose = options.onClose == undefined ? jQuery.noop : options.onClose;

		//var userMask = options.mask == undefined ? null : options.mask;

		// Enforce required options on user defined options
		var myOptions = j.extend({}, options, requiredOptions);

		var oldMaskConf = null;
		var joldMask = j(null);

		myOptions.onLoad = function () {
			if (j.mask.isLoaded()) {
				//this is a second overlay, get old settings
				oldMaskConf = j.mask.getConf();

				joldMask = j.mask.getExposed();

				// Close the currently shown mask. Do it instantly :)
				j.mask.getConf().closeSpeed = 0;
				j.mask.close();

				alert("Previous mask should be closed");

				var params = {
					color: '#666',
					loadSpeed: 0,
					zIndex: oldMaskConf.zIndex + 1,
					closeOnClick: false,
					closeOnEsc: false,
					opacity: 0.6
				};


				this.getOverlay().expose(params);

				// TODO: Set original jq overlay to closeonclick/esc false as well
			} else {
				this.getOverlay().expose({
					color: '#666',
					loadSpeed: 0,
					zIndex: 9999,
					closeOnClick: false,
					closeOnEsc: false,
					opacity: 0.6
				});
			}

			userOnLoad();
		};

		myOptions.onClose = function () {
			j.mask.close(); // This will close the currently shown expose, that, once actually closed, triggers the onClose-event that re-exposes the previous overlay.

			//re-expose previous overlay if there was one
			if (joldMask != null) {

				//oldMaskConf.zIndex = oldMaskConf.zIndex + 2;
				joldMask.expose(oldMaskConf);

				//				j("#exposeMask").show();
				//				j.mask.fit();
				//				alert(joldMask.css('z-index'));
				//				alert(joldMask.css('z-index') - 1);
				//				j("#exposeMask").css('z-index', joldMask.css('z-index') - 1);
			}

			userOnClose();
		};

		return myOptions;
	},

	initializeWaitPanel: function () {
		var waitPanel = j('#waitPanel');

		var options = DelawareCommons.GetOverlayOptions({
			//			mask: {
			//				color: '#666',
			//				loadSpeed: 200,
			//				opacity: 0.6,
			//				maskId: 'exposeMask'
			//			},
			zIndex: 10100,
			closeOnClick: false,
			closeOnEsc: false,
			fixed: true,
			top: "center",
			left: "center",
			speed: "fast"
		});

		waitPanel.overlay(options);

		DelawareCommons.waitPanelInitialized = true;
	},

	initializeExceptionPanel: function () {
		var width = 300;
		var exceptionPanel = j("#unhandledException");
		if (exceptionPanel.length == 0) {
			// Show full debug info
			exceptionPanel = j("#debugUnhandledException");
			width = 800;
		}

		if (exceptionPanel.length > 0) {
			exceptionPanel.width(width);

			var settings = DelawareCommons.GetOverlayOptions({
				closeOnClick: true,
				clonseOnEsc: true,
				fixed: true,
				top: "center",
				left: "center",
				speed: "fast"
			});

			exceptionPanel.overlay(settings);
		}

		DelawareCommons.exceptionPanelInitialized = true;
	},

	hideWaitPanel: function () {
		// Can we remove the waitpanel, or are there still processes using it
		if (--DelawareCommons.WaitPanelCount > 0) {
			return;
		}

		var waitPanel = j('#waitPanel');

		if (waitPanel.length > 0) {
			waitPanel.overlay().close();
		}
	},

	debugAssert: function (ok, message) {
		if (!ok) {
			DelawareCommons.logToConsole("<b>ASSERT FAIL: " + message + "</b>");
		}
	},

	updateDivs: function updateDivs(divUpdates) {

		if (divUpdates == null) {
			return;
		}

		DelawareCommons.logToConsole("updateDivs: start");
		var startProfile = DelawareCommons.startProfile();

		for (var i = 0; i < divUpdates.length; i++) {

			var update = divUpdates[i];

			// check if a div with id=divId exists
			var divElement = j("#" + update.ControlId);
			if (divElement.length > 0) {
				divElement.replaceWith(update.DivUpdate);
			}
			else {
				DelawareCommons.debugAssert(false, "updateDivs: unable to find div '" + update.ControlId + "'");
			}
		}

		DelawareCommons.endProfile(startProfile, "updateDivs x" + divUpdates.length);
	},

	ScrollToMessage: function (selector) {

		// ScrollToMessage when the message is no longer visible
		var jelement = j(selector);
		if (jelement.length == 0) {
			return;
		}

		var offset = jelement.offset();
		var jwindow = j(window);

		var doScroll = false;

		if (offset.top < jwindow.scrollTop()) {
			// We need to scroll up
			doScroll = true;
		}
		else if (offset.top > jwindow.scrollTop() + jwindow.height()) {
			// We need to scroll down
			doScroll = true;
		}

		if (doScroll) {
			j('html,body').stop().animate({ scrollTop: jelement.offset().top }, "slow");

			DelawareCommons.logToConsole("ScrollToMessage: scrolled");
		}
	},

	ParseDate: function (value) {
		return j.datepicker.parseDate('dd/mm/yy', value);
	},

	GetValue: function (field) {

		return (new DelawareCommons.ValueContainer(document)).GetValue(field);
	},

	GetIntValue: function (field) {
		return (new DelawareCommons.ValueContainer(document)).GetIntValue(field);
	},

	GetBooleanValue: function (field) {
		var retValue = (new DelawareCommons.ValueContainer(document)).GetValue(field);

		return retValue != null && typeof (retValue) == "boolean" ? retValue : false;
	},

	GetSelectText: function (field) {
		return (new DelawareCommons.ValueContainer(document)).GetSelectText(field);
	},

	GetFieldValue: function (inputField) {

		// Radio buttons
		if (inputField.is(":radio")) {
			return inputField.filter(":checked").val();
		}

		// Checkbox
		if (inputField.is(":checkbox")) {
			return inputField.filter(":checked").val() == "on";
		}

		// all form elements (input, select, textarea, button)
		if (inputField.is(":input")) {
			return inputField.val();
		}

		DelawareCommons.debugAssert(false, "Input field not supported: " + inputField.attr('id') + " " + inputField.attr('name'));
		return null;
	},

	// Calculates the week a date is in. E.g. week 1 or week 2. 
	GetWeekNumber: function (date) {
		//weeks start on a Monday and the first week of the year contains January 4.
		if (j.datepicker.iso8601Week(date) % 2 == 1)
			return 1;
		else
			return 2;
	},

	ConvertJsonDateToDate: function (date) {
		return new Date(parseInt(date.substr(6)));
	}
};


//////////////////////////////////////////////////////////////////////////////////

DelawareCommons.AjaxResponse = function (response) {
    // response should be of type: AjaxCallResponse
    this.Response = response;
};

DelawareCommons.AjaxResponse.prototype = {

    ContainsPattern: function (stringPattern) {
        if ((this.Response == null) || (this.Response.Updates == null)) {
            return false;
        }

        for (var i = 0; i < this.Response.Updates.length; i++) {
            if (this.Response.Updates[i].DivUpdate.indexOf(stringPattern) > -1) {
                return true;
            }
        }

        return false;
    }
};


