///<reference path="dialogcommon.js" />
///<reference path="membership.js" />
///<reference path="webtoolkit.base64.js" />

/*	Widget routines for Trafikkflyt.no  */
if (Widget == null || typeof(Widget) != "object") { var Widget = new Object(); }
if (Grid == null || typeof(Grid) != "object") { var Grid = new Object(); }
if (Cookie == null || typeof(Cookie) != "object") { var Cookie = new Object(); }

Widget.Options = {
	Narrow: {
		maximizeButtonImage: "/images/gfx/btn_maximize.gif",
		minimizeButtonImage: "/images/gfx/btn_minimize.gif",
		maximizeButtonTooltip: "Maksimer",
		minimizeButtonTooltip: "Minimer",
		minimizedBackground: "/images/gfx/widget_head_narrow_closed.png",
		maximizedBackground: "/images/gfx/widget_head_narrow.png"
	}, 
	Wide : {
		maximizeButtonImage: "/images/gfx/btn_maximize.gif",
		minimizeButtonImage: "/images/gfx/btn_minimize.gif",
		maximizeButtonTooltip: "Maksimer",
		minimizeButtonTooltip: "Minimer",
		minimizedBackground: "/images/gfx/widget_head_wide_closed.png",
		maximizedBackground: "/images/gfx/widget_head_wide.png"
	}
}

Cookie.Create = function(name, value, days) {
	///<summary>Creates a cookie</summary>
	///<param name="name">Cookie name</param>
	///<param name="value">Cookie value</param>
	///<param name="days">Number of days before the cookie expires</param>
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
Cookie.Read = function(name) {
	///<summary>Gets the value of a cookie</summary>
	///<param name="name">Cookie name</param>
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}
Cookie.Erase = function(name) {
	///<summary>Erases the value of a cookie</summary>
	///<param name="name">Cookie name</param>
	Cookie.Create(name, "", -1);
}
Grid.InitSortables = function() {
	///<summary>Initiates the sortable widgets</summary>
	try {
		var narrowZones = $$(".widgetzone-narrow");
		narrowZones.each ( function(zone) {
			zone.identify();
			Sortable.create(zone, 
				{ 
					tag:"div", 
					only:"widget_narrow", 
					dropOnEmpty:true,
					containment:narrowZones, 
					constraint:false, 
					handle:'header', 
					hoverclass:'hover-narrow',
					scroll:window
				}
			);
		});
		Draggables.addObserver( { onEnd: function() { Grid.Save(); } });
		// Cancel move on anchors within draggable headers
		$$(".widget_narrow .header a").each( function(link) {
			Event.observe(link, "mousedown", function(e) {
				e.cancelBubble = true;
			});
		});
	} catch (e) { reportError(e, "initSortables"); }
}
Grid.Save = function() {
	///<summary>Saves the state of the grid into a cookie</summary>
	try {
		var state = Grid.Serialize();
		Cookie.Create("gridState", Base64.Encode(Object.toJSON(state)), 365);
	} catch (e) { reportError(e, "Grid.Save"); }
}
Grid.Load = function() {
	///<summary>Loads the grid</summary>
	var savedState = Grid.GetSavedState();
	if (savedState) {
		try {
			Grid.Deserialize(savedState);
		} catch (e) { reportError(e, "Grid.Load"); }
	}	
}
Grid.GetSavedState = function() {
	///<summary>Gets the saved grid state</summary>
	try {
		var state = Cookie.Read("gridState");
		if (!!state) {
			try {
				state = Base64.Decode(state).evalJSON(true);
			} catch (e) {
				state = Grid.Serialize();
			}
		} else {
			state = Grid.Serialize();
		}
		return state;
	} catch (e) { reportError(e, "Grid.GetSavedState"); }
}
Grid.Serialize = function() {
	///<summary>Serializes the grid and saves it in a cookie</summary>
	///<returns>An object describing the grid state</returns>
	var state = { rows: new Array() }
	$$("div.columnzone").each(function(cz) {
		var row = { columns: new Array() };
		var narrowZones = cz.select("div.widgetzone-narrow");
		row.mode = narrowZones.length > 0 ? "narrow" : "wide";
		cz.select("div.widgetzone-" + row.mode).each( function(wz) {
			var col = { widgets: new Array() };
			wz.select("div.widget_" + row.mode).each( function(w) {
				col.widgets.push({ id: w.id, state: w.getAttribute("state") });
			});
			row.columns.push(col);
		}); 
		state.rows.push(row);
	});
	return state;
}
Grid.Deserialize = function deserializeGrid(state) {
	///<summary>Deserializes the grid from a state object</summary>
	///<param name="state">object containing a saved grid state</param>
	var gridRows = $$("div.columnzone");
	for (var i=0; i < state.rows.length; i++) {
		var row = state.rows[i];
		// ensure correct widgetzone
		var widgetZones = gridRows[i].select("div.widgetzone-" + row.mode);
		if (widgetZones.length < row.columns.length) {
			(row.columns.length - widgetZones.length).times( function() {
				// create required widget zone
				var newZone = Builder.build("div", { "class": "widgetzone-" + row.mode });
				newZone.identity();
				gridRows[i].appendChild(newZone);
			});
		}
		
		// ensure correct widgets in each column
		for (var x=0; x < row.columns.length; x++) {
			var col = row.columns[x];
			var widgetZone = gridRows[i].select("div.widgetzone-" + row.mode)[x];
			for (var y=0; y < col.widgets.length; y++) {
				var widget = col.widgets[y];
				var probe = widgetZone.select("div.widget_" + row.mode)[y];
				if (!probe || probe.id != widget.id) {
					// Move widget here
					var targetWidget = $(widget.id);
					if (targetWidget) {
						targetWidget.remove();
						if (y == widgetZone.select("div.widget_" + row.mode).length)
							widgetZone.appendChild(targetWidget);
						widgetZone.insertBefore(targetWidget, widgetZone.select("div.widget_" + row.mode)[y]);
					}
				}
				var domWidget = widgetZone.select("div.widget_" + row.mode)[y];
				if (domWidget) {
					if (widget.state == "minimized") {
						new __WidgetElement(domWidget).Minimize(true);
					} else if (widget.state == "hidden") {
						new __WidgetElement(domWidget).Remove(true);
					} else {
						// Normal widget
						if (domWidget.OnClientLoad) {
							eval(domWidget.OnClientLoad);
						}
						if (domWidget.UpdateInterval && domWidget.UpdateInterval > 0) {
							window.setInterval("Widget.Reload('" + domWidget.identify() + "', null);", domWidget.UpdateInterval * 1000);
						}
					}
				}
			}
		}
	}
}
Grid.ReloadUserWidgets = function() {
	///<summary>Reloads the widgets with user defined settings</summary>
	if (Membership.CurrentUser && Membership.CurrentUser.Widgets) {
		for (var widget in Membership.CurrentUser.Widgets) {
			var w = Widget.Find(widget);
			var params = Membership.CurrentUser.Widgets[widget];
			if (w && params)
				w.Reload(params);
		}
		// Reload MyAlerts
		var w = Widget.Find("MyAlerts");
		if (w) w.Reload();
	}
	// Turn on editor
	Widget.GetAll().each( function (w) {
		new __WidgetElement(w).ShowEditorButton();
	});
}

Widget.Maximize = function(widget) {
	///<summary>Maximizes a widget</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		new __WidgetElement(widget).Maximize(false, true);
		Grid.Save();
	} catch(e) { reportError(e, "Widget.Maximize") }
}
Widget.Minimize = function(widget) {
	///<summary>Minimizes a widget</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		new __WidgetElement(widget).Minimize(false, true);
		Grid.Save();
	} catch(e) { reportError(e, "Widget.Minimize") }
}
Widget.Close = function(widget) {
	///<summary>Closes a widget</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		widget = new __WidgetElement(widget);
		if (confirm("Vil du virkelig fjerne " + widget.Title + "?")) {
			widget.Remove(false, true);
		}
		Grid.Save();
	} catch(e) { reportError(e, "Widget.Close") }
}
Widget.OpenEditor = function(widget) {
	///<summary>Opens the editor for a widget</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		new __WidgetElement(widget).ShowEditor();
	} catch(e) { reportError(e, "Widget.OpenEditor") }
}
Widget.CancelEditor = function(widget) {
	///<summary>Closes the editor for a widget</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		new __WidgetElement(widget).CancelEditor();
	} catch(e) { reportError(e, "Widget.CancelEditor") }
}
Widget.SaveEditor = function(widget) {
	///<summary>Saves the settings from the widget editor</summary>
	///<param name="widget">Widget element (or id)</param>
	try {
		new __WidgetElement(widget).SaveEditor();
	} catch(e) { reportError(e, "Widget.SaveEditor") }
}
Widget.Reload = function(widget, params) {
	///<summary>Reloads the widget with the specified parameters</summary>
	///<param name="widget">Widget element or sub-element (or id)</param>
	///<param name="params">Parameters for the widget</param>
	widget = $(widget);
	if ((!widget.hasClassName("widget_wide")) && (!widget.hasClassName("widget_narrow"))) {
        widget = widget.up("div.widget_wide,div.widget_narrow,div.widget_partner");
	}
	try {
		widget = new __WidgetElement(widget).Reload(params);
	} catch(e) { reportError(e, "Widget.Load") }
}
Widget.Find = function(widgetClass) {
	///<summary>Finds a widget by class name</summary>
	///<parameter name="widgetClass">Class name of the widget to find</param>
	///<returns type="__WidgetElement">The found widget, or null</returns>
	var foundElement = Widget.GetAll().find( function(elm) {
		return elm.WidgetClass == widgetClass;
	});
	if (foundElement)
		return new __WidgetElement(foundElement);
}
Widget.GetAll = function() {
	///<summary>Gets all widgets on the page</summary>
	return $$("div.widget_wide,div.widget_narrow");
}
Widget._parameterCache = {};
Widget._GetParameterCache = function(widget) {
	///<summary>Gets the last parameter set the widget was loaded with</summary>
	///<param name="widget" type="__WidgetElement">Widget element</param>
	if (widget.hasOwnProperty) {
		if (Widget._parameterCache.hasOwnProperty(widget.WidgetClass)) {
			return Widget._parameterCache[widget.WidgetClass];
		}
	}
}
Widget._SetParameterCache = function(widget, params) {
	///<summary>Sets the parameter cache content for a widget</summary>
	///<param name="widget" type="__WidgetElement">Widget element</param>
	///<param name="params">Parameters</param>
	Widget._parameterCache[widget.WidgetClass] = params;
}

function __WidgetElement(widgetElement) {
	///<summary>Widget support object</summary>
	///<param name="widgetElement">Element (or id) to wrap as wigdet</param>
	this._w = $(widgetElement);
	this._namingContainerId = this._w.id.replace(/_frame/, "");
	this._getElement = function(id) { return $(this._namingContainerId + "_" + id); }
	this.isWide = this._w.hasClassName("widget_wide");
	this._header = this._getElement("header");
	this._headerTextNode = this._getElement("headerText");
	this._contentNode = this._getElement("content");
	this._bottomNode = this._getElement("bottom");
	this._options = this.isWide ? Widget.Options.Wide : Widget.Options.Narrow;
	this._minimizeButton = this._getElement("btnMinimize");
	this._maximizeButton = this._getElement("btnMaximize");
	this._editor = function() { return this._getElement("editor"); }
	this._editorButton = function() { return this._getElement("lnkOpenEditor"); };
	
	this._hasContentNode = function() { return this._contentNode != null; };
	this._hasBottomNode = function() { return this._bottomNode != null; };
	this._hasTextNode = function() { return this._headerTextNode != null; };
	this.ShowEditorButton = function() {
		var btn = this._editorButton();
		if (btn) btn.show(); 
	};
	this.WidgetClass = this._w.WidgetClass;
	this.Title = this._hasTextNode() ? this._headerTextNode.innerHTML.strip() : "(ukjent)";
	this.Remove = function(skipEffect) {
		if (!skipEffect) {
			Effect.SwitchOff(this._w);
		} else {
			this._w.hide();
		}
		this._w.setAttribute("state", "hidden");
	};
	this.Minimize = function(skipEffect, runHandler) {
		var header = this._header;
		var options = this._options;
		if (!skipEffect) {
			Effect.BlindUp(this._contentNode, { duration:0.5,
				afterFinish: function() {
					header.setStyle({ 
						backgroundImage: "url(" + options.minimizedBackground + ")" , 
						backgroundRepeat:"no-repeat" });
				} });
			Effect.Fade(this._bottomNode, { duration:0.1, delay:0.3 });
		} else {
			this._contentNode.hide();
			this._bottomNode.hide();
			header.setStyle({ 
				backgroundImage: "url(" + options.minimizedBackground + ")" , 
				backgroundRepeat:"no-repeat" });
		}
		this._minimizeButton.hide();
		this._maximizeButton.show();
		this._w.setAttribute("state", "minimized");
		if (runHandler && this.OnClientUnload) {
			eval(this.OnClientUnload);
		}
	};
	this.Maximize = function(skipEffect, runHandler) {
		if (!skipEffect) {
			var content = this._contentNode;
			Effect.BlindDown(content, { duration:0.5, 
				afterFinish: function() {
					if (Prototype.Browser.IE)
						Effect.Appear(content, { duration:0.1 });
				} });
			Effect.Appear(this._bottomNode, { duration:0.1, delay:0.3 });
		} else {
			this._contentNode.show();
			this._bottomNode.show();
		}
		this._header.setStyle({ backgroundImage: "url(" + this._options.maximizedBackground + ")", backgroundRepeat:"no-repeat"  });
		this._minimizeButton.show();
		this._maximizeButton.hide();
		this._w.setAttribute("state", "maximized");
		if (runHandler && this.OnClientLoad) {
			eval(this.OnClientLoad);
		}
	};
	this.ShowEditor = function() {
		var editor = this._editor();
		try {
			var mySettings = this._getEditorSettings();			
			if (mySettings) {
				for (var field in mySettings) {
					var editorField = this._getEditorField(field);
					if (editorField) {
						editorField.value = mySettings[field];
					}
				}
			}
		} catch (e) { }
		var widgetOffset = this._w.cumulativeOffset();
		LightBox.Show(editor, { top:widgetOffset.top, left: widgetOffset.left, width:300 } );
	}
	this.CancelEditor = function() {
		LightBox.Hide(null, this._w);
	}
	this.SaveEditor = function() {
		var params = this._getParamsFromEditor();
		var callerParams = Object.clone(params);
		callerParams["WidgetClass"] = this.WidgetClass;
		callerParams["userId"] = Membership.CurrentUser.UserId;
		var thisWidgetElement = this._w;
		Dialog.InvokeUserHandler("savewidget", callerParams, 
			function() {
				LightBox.Hide(null, thisWidgetElement);
				Widget.Reload(thisWidgetElement, params);
				Membership.LoadCurrentUser();
			});
	}
	this.Reload = function(params) {
	    if (!params) {
	        params = Widget._GetParameterCache(this);
	    }

	    __LogWidgetHits(this.WidgetClass);

	    if (this.WidgetClass != undefined) {
	        new Ajax.Updater(
	            this._contentNode,
	            "/RenderWidget.aspx?widget=" + this.WidgetClass, 
	            { method: 'get', parameters: params });
	        Widget._SetParameterCache(this, params);
	    }
	}
	this._getEditorSettings = function() {
		var myWidgetClass = this.WidgetClass;
		if (Membership.CurrentUser && Membership.CurrentUser.Widgets) {
			return Membership.CurrentUser.Widgets[myWidgetClass];
		}
	}
	this._getEditorField = function(fieldName) {
		return $(this._namingContainerId + "_field_" + fieldName);
	}
	this._getParamsFromEditor = function() {
		var params = {};
		var panel = $(this._namingContainerId + "_editorpanel");
		var fieldsPrefix = this._namingContainerId + "_field_";
		if (panel) {
			panel.descendants().findAll( function(elm) {
				return elm.identify().startsWith(fieldsPrefix);
			}).each( function(field) {
				params[field.id.replace(fieldsPrefix, "")] = $F(field);
			});
		}
		return params;
	}
}
 
function __LogWidgetHits(widgetName) {
    new Ajax.Request('/logging.ashx', {
        method: 'get',
        parameters: 'm=h&c=' + widgetName
    });
}
 
