// JS file containing functions used for calling
// the correct JavaScript function when a price
// is clicked in the pricetable

// dependancy: /shared/Clientscript/Resources.aspx

// global variables
var boolPartyAvailableForPC;
var selectedPriceCellId;

// ====================================================
// Initialize the global variables and event listeners
// ====================================================
function InitPriceTable(partyAvailable) {
	var eventTargetObj;

	// set the global variable boolPartyAvailableForPC
	boolPartyAvailableForPC = partyAvailable;

	// add a click event to the pricetable div
	eventTargetObj = document.getElementById('PriceGrid');
	eventTargetObj.onclick = ProcessPriceTableClickEvent;
	eventTargetObj.onmouseover = ProcessPriceTableMouseOverEvent;
	eventTargetObj.onmouseout = ProcessPriceTableMouseOutEvent;
}

// ====================================================
// Process the Click Event
// ====================================================
function ProcessPriceTableClickEvent(e) {
	var srcElement = null;

	// if no event is provided by the browser, 
	// get it using window.event (this normaly
	// only happens in msie).
	if (!e) { var e = window.event; }

	// get the source element
	srcElement = (e.target) ? e.target : e.srcElement

	// retrieve the type of the requested node.
	// if it is a Text node (3), set the parentNode as the current srcElement
	// this is needed to defeat a known Safari bug
	if (srcElement.nodeType == 3) { srcElement = srcElement.parentNode; }

	// check if the srcElement is a <TD> element with the required class
	if (srcElement.tagName == 'TD' &&
       (srcElement.className == 'd' || srcElement.className == 'd hover' ||
        srcElement.className == 'r' || srcElement.className == 'r hover' ||
        srcElement.className == 'a' || srcElement.className == 'a hover' ||
        srcElement.className == 'v' || srcElement.className == 'v hover')) {
		// Indicate the current selection
		IndicateSelection(srcElement);

		// Scroll to the price calculation
		DoScrolling();
		// call pricecalculationupdate when a party is available
		if (boolPartyAvailableForPC == true) {

			if (typeof (priceCalcSiteVariation) != "undefined" && priceCalcSiteVariation != null && priceCalcSiteVariation != '') {
				var lServiceUrl = (priceCalcSiteVariation == 'jws')
						? "/wintersport/accommodation/WebServices/PriceTableService.asmx/HandlePriceTableCalculationRequestWinter"
						: "/accommodation/WebServices/PriceTableService.asmx/HandlePriceTableCalculationRequest";
								
				$.ajax({
					type: "POST",
					url: lServiceUrl,
					contentType: "application/json; charset=utf-8",
					data: JSON.stringify({spec: srcElement.id}),
					dataType: "json",
					success: function(json) {
						window.PriceCalcHandleCallbackServerResponse && window.PriceCalcHandleCallbackServerResponse(json.d, srcElement);
					}
				});							
			}
		}
		else if (boolPartyAvailableForPC == false)// otherwise open the party not available popup
		{
			OpenPartyNotAvailableEditor(srcElement.id);
		}
	}
}

// ====================================================
// Process the MouseOver Event
// ====================================================
function ProcessPriceTableMouseOverEvent(e) {
	var srcElement = null;

	// if no event is provided by the browser, 
	// get it using window.event (this normaly
	// only happens in msie).
	if (!e) { var e = window.event; }

	// get the source element
	srcElement = (e.target) ? e.target : e.srcElement;

	// retrieve the type of the requested node.
	// if it is a Text node (3), set the parentNode as the current srcElement
	// this is needed to defeat a known Safari bug
	if (srcElement.nodeType == 3) { srcElement = srcElement.parentNode; }

	// check if the srcElement is a <TD> element with the required class
	if (srcElement.tagName == 'TD' &&
       (srcElement.className == 'd' ||
        srcElement.className == 'r' ||
        srcElement.className == 'a' ||
        srcElement.className == 'v')) {
		srcElement.className = srcElement.className + ' hover';
	}
}

// ====================================================
// Process the MouseOut Event
// ====================================================
function ProcessPriceTableMouseOutEvent(e) {
	var srcElement = null;

	// if no event is provided by the browser, 
	// get it using window.event (this normaly
	// only happens in msie).
	if (!e) { var e = window.event; }

	// get the source element
	srcElement = (e.target) ? e.target : e.srcElement;

	// retrieve the type of the requested node.
	// if it is a Text node (3), set the parentNode as the current srcElement
	// this is needed to defeat a known Safari bug
	if (srcElement.nodeType == 3) { srcElement = srcElement.parentNode; }

	// check if the srcElement is a <TD> element with the required class
	if (srcElement.tagName == 'TD' && srcElement.className.indexOf('hover') > -1) {
		srcElement.className = srcElement.className.replace(/\s*hover/, '');
	}
}

// ====================================================
// Indicates the currently selected cell in the price grid.
// ====================================================
function IndicateSelection(clickedElement) {
	var PreviousCell;

	// set the style of the previously selected element back to normal
	if (selectedPriceCellId != null) {
		PreviousCell = document.getElementById(selectedPriceCellId)
		if (PreviousCell != null) {
			PreviousCell.className = PreviousCell.className.replace(/\s*selected/, '');
		}
	}
	// set the style of the clicked element to selected
	clickedElement.className = clickedElement.className + " selected";
	// remember the selected cell
	selectedPriceCellId = clickedElement.id;
}

// ====================================================
// Scroll to the price calculation container.
// ====================================================
function DoScrolling() {
	var PriceCalculationDiv;
	var ContentContainerDiv;
	var TabSetDiv;
	var ScrollingPosition;

	// get the price calculation div
	PriceCalculationDiv = document.getElementById('PriceCalculationContainer');
	ContentContainerDiv = document.getElementById('ContentContainer')
	TabSetDiv = document.getElementById('set1')

	// the several divs must exists
	if (PriceCalculationDiv != null && ContentContainerDiv != null && TabSetDiv != null) {
		// price calculation available
		ScrollingPosition = PriceCalculationDiv.offsetTop + TabSetDiv.offsetTop + ContentContainerDiv.offsetTop;

		// set the scroll position to the top position of the div 
		document.body.scrollTop = ScrollingPosition;
		document.documentElement.scrollTop = ScrollingPosition;
	}
}

/* 
PriceTable webservice functions
- OnServiceUnAvailable() is called when the price table service is not running
- OnRequestStart() is called before the price table service is called
- OnRequestTimeOut() is called on a webservice timeout
- OnRequestError() is called when an exception occurs in the webservice
-	OnRequestComplete() is called when the price table service successfully responds.
*/

function OnServiceUnAvailable() {
	SetPriceTableMessage(Resources.Prices.ServiceUnavailable);
}

function OnRequestStart() {
	// Hide the current price table
	TogglePriceTableVisibility(false);
	// Set a wait message
	SetPriceTableMessage(Resources.Prices.Loading);
	// Start tracking price table load time using google analitics.
	startTrackPriceTableLoadTime();
	
}

function OnRequestTimeOut() {
	SetPriceTableMessage(Resources.Prices.OnRequestTimeOut);
}

function OnRequestError(accomodationId, errorType, errorText) {
	if (errorType == "timeout") {
		OnRequestTimeOut();
	}
	else {
		SetPriceTableMessage(Resources.Prices.OnRequestError);
	}
	// Report error to google analytics.
	trackPriceTableError(accomodationId, errorType, errorText);
}

function OnRequestComplete(accomodationId, result) {
	// Set the inner html of the pricegrid
	var PriceGrid = document.getElementById('PriceGrid');
	PriceGrid.innerHTML = result;
	// Highlight the default price selected by the server if this exists
	if ('function' == typeof IndicateDefaultPrice)
		IndicateDefaultPrice();
	if ('function' == typeof AddMiniMidweekSkiTags)
		AddMiniMidweekSkiTags();
	// Hide the message panel and display the price table, with a short delay
	// so that the user knows that something has changed
	setTimeout('TogglePriceTableVisibility(true)', 300);
	// report price table loading time to google analitics.
	endTrackPriceTableLoadTime(accomodationId);
}

function SetPriceTableMessage(message) {
	var MessageElement = document.getElementById('PriceTableMessage');
	if (MessageElement) {
		MessageElement.innerHTML = message;
	}
}

function TogglePriceTableVisibility(visible) {
	var MessageElement = document.getElementById('PriceTableMessage');
	if (MessageElement) {
		MessageElement.style.display = (visible) ? 'none' : 'block';
	}
	var PriceGrid = document.getElementById('PriceGrid');
	if (PriceGrid) {
		PriceGrid.style.display = (visible) ? 'block' : 'none';
	}
	ResizeForPrices();
	if (visible) {
		InitPriceScrollbar();
	}
}

// ====================================================
//	Shows the price calculation and if needed resizes the tab containing it
// ====================================================
function ResizeForPrices() {
	var priceTabPaddingBottom = 10;
	var priceTableContainer = document.getElementById('priceTableContainer');
	var priceCalculationContainer = document.getElementById('PriceCalculationContainer');
	var priceCalculationMovable = document.getElementById('PriceCalculationMovable');
	var priceTableTab = document.getElementById('pricetable_data');

	// get the current height of the the tab
	var currentTabHeight;
	var requiredHeightCalculation;
	if (priceTableTab != null) {
		currentTabHeight = priceTableTab.offsetHeight;
	}
	else {
		return;
	}
	// get the new height that is required for the tab after displaying the pricecalculation
	if (priceCalculationMovable != null) {
		requiredHeightCalculation = priceCalculationMovable.offsetHeight + priceCalculationMovable.offsetTop;
	}
	else {
		return;
	}

	// resize the tab when the height of the pricecalculation > the height of the tab
	if (requiredHeightCalculation > currentTabHeight) {
		setHeight(priceTableTab, priceTabPaddingBottom, requiredHeightCalculation);
	}
	// resize the tab when the height of the pricecalculation < the height of the tab
	if (requiredHeightCalculation < currentTabHeight) {
		if (priceTableContainer != null) {
			// get the height required for the pricetable
			var requiredHeightPriceTable = priceTableContainer.offsetHeight;
			// if the height of the pricecalculation > the height of the pricetable,
			// set the pricetab height to the height of the pricecalculation
			if (requiredHeightCalculation > requiredHeightPriceTable) {
				setHeight(priceTableTab);

			}
			// if the height of the pricecalculation < the height of the pricetable,
			// set the pricetab height to the height of the pricetable
			if (requiredHeightCalculation < requiredHeightPriceTable) {
				setHeight(priceTableTab);
			}
		}
	}
}

function setHeight(div) {
	div.style.height = '100%';
}

function trackOnGooglePriceTableError(accomodationId, errorType, errorText, googlePageTracker) {
	if (errorType == "timeout") {
		errorText = errorType;
	}
	try {
		googlePageTracker._trackEvent("error", "pricetable not loaded", errorText, accomodationId);
	}
	catch (err) { }

}

var priceTableLoadTimeTracker;

function startTrackPriceTableLoadTime() {
	try {
		priceTableLoadTimeTracker = new TimeTracker();
		priceTableLoadTimeTracker._recordStartTime();
	}
	catch (err) { }
}

function endTrackOnGooglePriceTableLoadTime(accomodationId, googlePageTracker) {
	try {
		priceTableLoadTimeTracker._recordEndTime();
		priceTableLoadTimeTracker._track(googlePageTracker, "pricetable loadtime", accomodationId.toString());
	}
	catch (err) {}
	
}

var dw_Event = {

	add: function(obj, etype, fp, cap) {
		cap = cap || false;
		if (obj.addEventListener) obj.addEventListener(etype, fp, cap);
		else if (obj.attachEvent) obj.attachEvent("on" + etype, fp);
	},

	remove: function(obj, etype, fp, cap) {
		cap = cap || false;
		if (obj.removeEventListener) obj.removeEventListener(etype, fp, cap);
		else if (obj.detachEvent) obj.detachEvent("on" + etype, fp);
	},

	DOMit: function(e) {
		e = e ? e : window.event; // e IS passed when using attachEvent though ...
		if (!e.target) e.target = e.srcElement;
		if (!e.preventDefault) e.preventDefault = function() { e.returnValue = false; return false; }
		if (!e.stopPropagation) e.stopPropagation = function() { e.cancelBubble = true; }
		return e;
	},

	getTarget: function(e) {
		e = dw_Event.DOMit(e); var tgt = e.target;
		if (tgt.nodeType != 1) tgt = tgt.parentNode; // safari...
		return tgt;
	}

}

// Danny Goodman's version (DHTML def ref)
function addLoadEvent(func) {
	var oldQueue = window.onload ? window.onload : function() { };
	window.onload = function() {
		oldQueue();
		func();
	}
}

___handleVerticalContentScroll = false;

// horizId only needed for horizontal scrolling
function dw_scrollObj(wndoId, lyrId, horizId) {
	var wn = document.getElementById(wndoId);
	this.id = wndoId; dw_scrollObj.col[this.id] = this;
	this.animString = "dw_scrollObj.col." + this.id;
	this.load(lyrId, horizId);

	if (wn.addEventListener) {
		wn.addEventListener('DOMMouseScroll', dw_scrollObj.doOnMouseWheel, false);
	}
	wn.onmousewheel = dw_scrollObj.doOnMouseWheel;
}

// If set true, position scrolling content div's absolute in style sheet (see documentation)
// set false in download file with position absolute set in .load method due to support issues 
// (Too many people remove the specification and then complain that the code doesn't work!)
dw_scrollObj.printEnabled = false;

dw_scrollObj.defaultSpeed = dw_scrollObj.prototype.speed = 100; // default for mouseover or mousedown scrolling
dw_scrollObj.defaultSlideDur = dw_scrollObj.prototype.slideDur = 500; // default duration of glide onclick

dw_scrollObj.isSupported = function() {
	if (document.getElementById && document.getElementsByTagName
         && document.addEventListener || document.attachEvent) {
		return true;
	}
	return false;
}

dw_scrollObj.col = {}; // collect instances

// custom events 
dw_scrollObj.prototype.on_load = function() { } // when dw_scrollObj initialized or new layer loaded
dw_scrollObj.prototype.on_scroll = function() { }
dw_scrollObj.prototype.on_scroll_start = function() { }
dw_scrollObj.prototype.on_scroll_stop = function() { } // when scrolling has ceased (mouseout/up)
dw_scrollObj.prototype.on_scroll_end = function() { } // reached end
dw_scrollObj.prototype.on_update = function() { } // called in updateDims

dw_scrollObj.prototype.on_glidescroll = function() { }
dw_scrollObj.prototype.on_glidescroll_start = function() { }
dw_scrollObj.prototype.on_glidescroll_stop = function() { } // destination (to/by) reached
dw_scrollObj.prototype.on_glidescroll_end = function() { } // reached end

dw_scrollObj.prototype.load = function(lyrId, horizId) {
	var wndo, lyr;
	if (this.lyrId) { // layer currently loaded?
		lyr = document.getElementById(this.lyrId);
		lyr.style.visibility = "hidden";
	}

	this.lyr = lyr = document.getElementById(lyrId); // hold this.lyr?
	if (!dw_scrollObj.printEnabled) {
		this.lyr.style.position = 'absolute';
	}
	this.lyrId = lyrId; // hold id of currently visible layer
	this.horizId = horizId || null; // hold horizId for update fn
	wndo = document.getElementById(this.id);
	this.y = 0; this.x = 0; this.shiftTo(0, 0);
	this.getDims(wndo, lyr);
	lyr.style.visibility = "visible";
	this.ready = true; this.on_load();
}

dw_scrollObj.prototype.shiftTo = function(x, y) {
	if (this.lyr) {
		this.lyr.style.left = (this.x = x) + "px";
		this.lyr.style.top = (this.y = y) + "px";
	}
}


dw_scrollObj.prototype.getX = function() { return this.x; }
dw_scrollObj.prototype.getY = function() { return this.y; }

dw_scrollObj.prototype.getDims = function(wndo, lyr) {
	this.wd = this.horizId ? document.getElementById(this.horizId).offsetWidth : lyr.offsetWidth;
	this.maxX = (this.wd - wndo.offsetWidth > 0) ? this.wd - wndo.offsetWidth : 0;
	this.maxY = (lyr.offsetHeight - wndo.offsetHeight > 0) ? lyr.offsetHeight - wndo.offsetHeight : 0;
}

dw_scrollObj.prototype.updateDims = function() {
	var wndo = document.getElementById(this.id);
	var lyr = document.getElementById(this.lyrId);
	this.getDims(wndo, lyr);
	this.on_update();
}

// for mouseover/mousedown scrolling
dw_scrollObj.prototype.initScrollVals = function(deg, speed) {
	if (!this.ready) return;
	if (this.timerId) {
		clearInterval(this.timerId); this.timerId = 0;
	}
	this.speed = speed || dw_scrollObj.defaultSpeed;
	this.fx = (deg == 0) ? -1 : (deg == 180) ? 1 : 0;
	this.fy = (deg == 90) ? 1 : (deg == 270) ? -1 : 0;
	this.endX = (deg == 90 || deg == 270) ? this.x : (deg == 0) ? -this.maxX : 0;
	this.endY = (deg == 0 || deg == 180) ? this.y : (deg == 90) ? 0 : -this.maxY;
	this.lyr = document.getElementById(this.lyrId);
	this.lastTime = new Date().getTime();
	this.on_scroll_start(this.x, this.y);
	this.timerId = setInterval(this.animString + ".scroll()", 10);
}

dw_scrollObj.prototype.scroll = function() {
	var now = new Date().getTime();
	var d = (now - this.lastTime) / 1000 * this.speed;
	if (d > 0) {
		var x = this.x + Math.round(this.fx * d); var y = this.y + Math.round(this.fy * d);
		if ((this.fx == -1 && x > -this.maxX) || (this.fx == 1 && x < 0) ||
                (this.fy == -1 && y > -this.maxY) || (this.fy == 1 && y < 0)) {
			this.lastTime = now;
			this.shiftTo(x, y);
			this.on_scroll(x, y);
		} else {
			clearInterval(this.timerId); this.timerId = 0;
			this.shiftTo(this.endX, this.endY);
			this.on_scroll(this.endX, this.endY);
			this.on_scroll_end(this.endX, this.endY);
		}
	}
}

// when scrolling has ceased (mouseout/up)
dw_scrollObj.prototype.ceaseScroll = function() {
	if (!this.ready) return;
	if (this.timerId) {
		clearInterval(this.timerId); this.timerId = 0;
	}
	this.on_scroll_stop(this.x, this.y);
}

// glide onclick scrolling
dw_scrollObj.prototype.initScrollByVals = function(dx, dy, dur) {
	if (!this.ready || this.sliding) return;
	this.startX = this.x; this.startY = this.y;
	this.destX = this.destY = this.distX = this.distY = 0;
	if (dy < 0) {
		this.distY = (this.startY + dy >= -this.maxY) ? dy : -(this.startY + this.maxY);
	} else if (dy > 0) {
		this.distY = (this.startY + dy <= 0) ? dy : -this.startY;
	}
	if (dx < 0) {
		this.distX = (this.startX + dx >= -this.maxX) ? dx : -(this.startX + this.maxX);
	} else if (dx > 0) {
		this.distX = (this.startX + dx <= 0) ? dx : -this.startX;
	}
	this.destX = this.startX + this.distX; this.destY = this.startY + this.distY;
	this.glideScrollPrep(this.destX, this.destY, dur);
}

dw_scrollObj.prototype.initScrollToVals = function(destX, destY, dur) {
	if (!this.ready || this.sliding) return;
	this.startX = this.x; this.startY = this.y;
	this.destX = -Math.max(Math.min(destX, this.maxX), 0);
	this.destY = -Math.max(Math.min(destY, this.maxY), 0);
	this.distY = this.destY - this.startY;
	this.distX = this.destX - this.startX;
	this.glideScrollPrep(this.destX, this.destY, dur);
}

dw_scrollObj.prototype.glideScrollPrep = function(destX, destY, dur) {
	this.slideDur = (typeof dur == 'number') ? dur : dw_scrollObj.defaultSlideDur;
	this.per = Math.PI / (2 * this.slideDur); this.sliding = true;
	this.lyr = document.getElementById(this.lyrId);
	this.startTime = new Date().getTime();
	this.timerId = setInterval(this.animString + ".doGlideScroll()", 10);
	this.on_glidescroll_start(this.startX, this.startY);
}

dw_scrollObj.prototype.doGlideScroll = function() {
	var elapsed = new Date().getTime() - this.startTime;
	if (elapsed < this.slideDur) {
		var x = this.startX + Math.round(this.distX * Math.sin(this.per * elapsed));
		var y = this.startY + Math.round(this.distY * Math.sin(this.per * elapsed));
		this.shiftTo(x, y);
		this.on_glidescroll(x, y);
	} else {	// if time's up
		clearInterval(this.timerId); this.timerId = 0; this.sliding = false;
		this.shiftTo(this.destX, this.destY);
		this.on_glidescroll(this.destX, this.destY);
		this.on_glidescroll_stop(this.destX, this.destY);
		// end of axis reached ? 
		if (this.distX && (this.destX == 0 || this.destX == -this.maxX)
          || this.distY && (this.destY == 0 || this.destY == -this.maxY)) {
			this.on_glidescroll_end(this.destX, this.destY);
		}
	}
}

//  resource: http://adomas.org/javascript-mouse-wheel/
dw_scrollObj.handleMouseWheel = function(id, delta) {
	var wndo = dw_scrollObj.col[id];
	var x = wndo.x;
	var y = wndo.y;
	wndo.on_scroll_start(x, y);
	var ny;
	ny = 12 * delta + y
	ny = (ny < 0 && ny >= -wndo.maxY) ? ny : (ny < -wndo.maxY) ? -wndo.maxY : 0;
	wndo.shiftTo(x, ny);
	wndo.on_scroll(x, ny);
}

dw_scrollObj.doOnMouseWheel = function(e) {
	/***customized***/
	/*changed to support multiple horizontal scrollbars*/
	if (!e) e = window.event;
	if (___handleVerticalContentScroll) {
		var delta = 0;

		if (e.wheelDelta) { /* IE/Opera. */
			delta = e.wheelDelta / 120;
			if (window.opera) delta = -delta;
		} else if (e.detail) { // Mozilla 
			delta = -e.detail / 3;
		}
		if (delta) { // > 0 up, < 0 down
			dw_scrollObj.handleMouseWheel(this.id, delta);
		}
		if (e.preventDefault) e.preventDefault();
	}
	e.returnValue = false;

}

dw_scrollObj.GeckoTableBugFix = function() { } // no longer need old bug fix


// Get position of el within layer (oCont) sOff: 'left' or 'top'
// Assumes el is within oCont
function dw_getLayerOffset(el, oCont, sOff) {
	var off = "offset" + sOff.charAt(0).toUpperCase() + sOff.slice(1);
	var val = el[off];
	while ((el = el.offsetParent) != oCont)
		val += el[off];
	var clientOff = off.replace("offset", "client");
	if (el[clientOff]) val += el[clientOff];
	return val;
}
function dw_Slidebar(barId, trackId, axis, x, y) {
	var bar = document.getElementById(barId);
	var track = document.getElementById(trackId);
	this.barId = barId; this.trackId = trackId;
	this.axis = axis; this.x = x || 0; this.y = y || 0;
	dw_Slidebar.col[this.barId] = this;
	this.bar = bar; this.shiftTo(x, y);

	// hold for setBarSize  
	this.trkHt = track.offsetHeight;
	this.trkWd = track.offsetWidth;

	if (axis == 'v') {
		this.maxY = this.trkHt - bar.offsetHeight - y;
		this.maxX = x; this.minX = x; this.minY = y;
	} else {
		this.maxX = this.trkWd - bar.offsetWidth - x;
		this.minX = x; this.maxY = y; this.minY = y;
	}

	this.on_drag_start = this.on_drag = this.on_drag_end =
    this.on_slide_start = this.on_slide = this.on_slide_end = function() { }

	bar.onmousedown = dw_Slidebar.prepDrag;
	// pass barId to obtain instance from dw_Slidebar.col
	track.onmousedown = function(e) { dw_Slidebar.prepSlide(barId, e); }
	this.bar = bar = null; track = null;
}

dw_Slidebar.col = {}; // hold instances for global access
dw_Slidebar.current = null; // hold current instance

dw_Slidebar.prototype.slideDur = 500;

// track received onmousedown event
dw_Slidebar.prepSlide = function(barId, e) {
	var _this = dw_Slidebar.col[barId];
	dw_Slidebar.current = _this;
	var bar = _this.bar = document.getElementById(barId);

	if (_this.timer) { clearInterval(_this.timer); _this.timer = 0; }
	e = e ? e : window.event;

	e.offX = (typeof e.layerX != "undefined") ? e.layerX : e.offsetX;
	e.offY = (typeof e.layerY != "undefined") ? e.layerY : e.offsetY;
	_this.startX = parseInt(bar.style.left); _this.startY = parseInt(bar.style.top);

	if (_this.axis == "v") {
		_this.destX = _this.startX;
		_this.destY = (e.offY < _this.startY) ? e.offY : e.offY - bar.offsetHeight;
		_this.destY = Math.min(Math.max(_this.destY, _this.minY), _this.maxY);
	} else {
		_this.destX = (e.offX < _this.startX) ? e.offX : e.offX - bar.offsetWidth;
		_this.destX = Math.min(Math.max(_this.destX, _this.minX), _this.maxX);
		_this.destY = _this.startY;
	}
	_this.distX = _this.destX - _this.startX; _this.distY = _this.destY - _this.startY;
	_this.per = Math.PI / (2 * _this.slideDur);
	_this.slideStartTime = new Date().getTime();
	_this.on_slide_start(_this.startX, _this.startY);
	_this.timer = setInterval("dw_Slidebar.doSlide()", 10);
}

dw_Slidebar.doSlide = function() {
	var _this = dw_Slidebar.current;
	var elapsed = new Date().getTime() - _this.slideStartTime;
	if (elapsed < _this.slideDur) {
		var x = _this.startX + _this.distX * Math.sin(_this.per * elapsed);
		var y = _this.startY + _this.distY * Math.sin(_this.per * elapsed);
		/***customized***/
		/*changed to support multiple horizontal scrollbars*/

		_this.wndo.shiftTrackersTo(_this.destX, _this.destY);
		_this.on_slide(x, y);
	} else {	// if time's up
		clearInterval(_this.timer);

		/***customized***/
		/*changed to support multiple horizontal scrollbars*/

		_this.wndo.shiftTrackersTo(_this.destX, _this.destY);

		_this.on_slide(_this.destX, _this.destY);
		_this.on_slide_end(_this.destX, _this.destY);
		dw_Slidebar.current = null;
	}
}

dw_Slidebar.prepDrag = function(e) {
	var bar = this; // bar received onmousedown event
	var barId = this.id; // id of element mousedown event assigned to
	var _this = dw_Slidebar.col[barId]; // Slidebar instance
	dw_Slidebar.current = _this;
	_this.bar = bar;
	e = dw_Event.DOMit(e);
	if (_this.timer) { clearInterval(_this.timer); _this.timer = 0; }
	_this.downX = e.clientX; _this.downY = e.clientY;
	_this.startX = parseInt(bar.style.left);
	_this.startY = parseInt(bar.style.top);
	_this.on_drag_start(_this.startX, _this.startY);
	dw_Event.add(document, "mousemove", dw_Slidebar.doDrag, true);
	dw_Event.add(document, "mouseup", dw_Slidebar.endDrag, true);
	e.stopPropagation(); e.preventDefault();
}

dw_Slidebar.doDrag = function(e) {
	if (!dw_Slidebar.current) return; // avoid errors in ie if inappropriate selections
	var _this = dw_Slidebar.current;
	var bar = _this.bar;
	e = dw_Event.DOMit(e);
	var nx = _this.startX + e.clientX - _this.downX;
	var ny = _this.startY + e.clientY - _this.downY;
	nx = Math.min(Math.max(_this.minX, nx), _this.maxX);
	ny = Math.min(Math.max(_this.minY, ny), _this.maxY);
	/***customized***/
	/*changed to support multiple horizontal scrollbars*/
	_this.wndo.shiftTrackersTo(nx, ny);
	_this.on_drag(nx, ny);
	e.preventDefault(); e.stopPropagation();
}

dw_Slidebar.endDrag = function() {
	if (!dw_Slidebar.current) return; // avoid errors in ie if inappropriate selections
	var _this = dw_Slidebar.current;
	var bar = _this.bar;
	dw_Event.remove(document, "mousemove", dw_Slidebar.doDrag, true);
	dw_Event.remove(document, "mouseup", dw_Slidebar.endDrag, true);
	_this.on_drag_end(parseInt(bar.style.left), parseInt(bar.style.top));
	dw_Slidebar.current = null;
}

dw_Slidebar.prototype.shiftTo = function(x, y) {
	if (this.bar) {
		this.bar.style.left = x + "px";
		this.bar.style.top = y + "px";
	}
}
/*changed to support multiple horizontal scrollbars*/
dw_scrollObj.prototype.shiftTrackersTo = function(x, y) {
	dw_Scrollbar_Co.getBarRefs(this);
	if (this.hBars) {
		for (var idxHB = 0; idxHB < this.hBars.length; idxHB++) {
			this.hBars[idxHB].shiftTo(x, y);
		}
	}
}

/////////////////////////////////////////////////////////////////////
//  connect slidebar with scrollObj
dw_scrollObj.prototype.setUpScrollbar = function(barId, trkId, axis, offx, offy, bSize) {
	var scrollbar = new dw_Slidebar(barId, trkId, axis, offx, offy);
	if (axis == "v") {
		this.vBarId = barId;
	} else {
		/***customized***/
		/*changed to support multiple horizontal scrollbars*/
		if (typeof this.hBarIds == 'undefined') {
			this.hBarIds = [barId];
		} else {
			this.hBarIds = this.hBarIds.concat(barId);
		}
	}
	scrollbar.wndoId = this.id;
	scrollbar.bSizeDragBar = (bSize == false) ? false : true;
	if (scrollbar.bSizeDragBar) {
		dw_Scrollbar_Co.setBarSize(this, scrollbar);
	}
	dw_Scrollbar_Co.setEvents(this, scrollbar);
}

// Coordinates slidebar and scrollObj
dw_Scrollbar_Co = {

	// This function is called for each scrollbar attached to a scroll area (change from previous version)
	setBarSize: function(scrollObj, barObj) {
		var lyr = document.getElementById(scrollObj.lyrId);
		var wn = document.getElementById(scrollObj.id);
		if (barObj.axis == 'v') {
			var bar = document.getElementById(scrollObj.vBarId);
			bar.style.height = (lyr.offsetHeight > wn.offsetHeight) ?
                barObj.trkHt / (lyr.offsetHeight / wn.offsetHeight) + "px" :
                barObj.trkHt - (2 * barObj.minY) + "px";
			barObj.maxY = barObj.trkHt - bar.offsetHeight - barObj.minY;
		} else if (barObj.axis == 'h') {
			/***customized***/
			/*changed to support multiple horizontal scrollbars*/

			for (var idxH = 0; idxH < scrollObj.hBarIds.length; idxH++) {
				var bar = document.getElementById(scrollObj.hBarIds[idxH]);
				bar.style.width = (scrollObj.wd > wn.offsetWidth) ?
                barObj.trkWd / (scrollObj.wd / wn.offsetWidth) + "px" :
                barObj.trkWd - (2 * barObj.minX) + "px";
				barObj.maxX = barObj.trkWd - bar.offsetWidth - barObj.minX;
			}
		}
	},

	// Find bars associated with this scrollObj. if they have bSizeDragBar set true reevaluate size and reset position to top 
	resetBars: function(scrollObj) {
		var barObj, bar;
		if (scrollObj.vBarId) {
			barObj = dw_Slidebar.col[scrollObj.vBarId];
			bar = document.getElementById(scrollObj.vBarId);
			bar.style.left = barObj.minX + "px"; bar.style.top = barObj.minY + "px";
			if (barObj.bSizeDragBar) {
				dw_Scrollbar_Co.setBarSize(scrollObj, barObj);
			}
		}
		/***customized***/
		/*changed to support multiple horizontal scrollbars*/

		if (scrollObj.hBarIds) {
			for (var idxH = 0; idxH < scrollObj.hBarIds.length; idxH++) {
				barObj = dw_Slidebar.col[scrollObj.hBarIds[idxH]];
				bar = document.getElementById(scrollObj.hBarIds[idxH]);
				bar.style.left = barObj.minX + "px"; bar.style.top = barObj.minY + "px";
				if (barObj.bSizeDragBar) {
					dw_Scrollbar_Co.setBarSize(scrollObj, barObj);
				}
			}
		}
	},

	setEvents: function(scrollObj, barObj) {
		// scrollObj
		this.addEvent(scrollObj, 'on_load', function() { dw_Scrollbar_Co.resetBars(scrollObj); });
		this.addEvent(scrollObj, 'on_scroll_start', function() { dw_Scrollbar_Co.getBarRefs(scrollObj) });
		this.addEvent(scrollObj, 'on_glidescroll_start', function() { dw_Scrollbar_Co.getBarRefs(scrollObj) });
		this.addEvent(scrollObj, 'on_scroll', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y) });
		this.addEvent(scrollObj, 'on_glidescroll', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y) });
		this.addEvent(scrollObj, 'on_scroll_stop', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y); });
		this.addEvent(scrollObj, 'on_glidescroll_stop', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y); });
		this.addEvent(scrollObj, 'on_scroll_end', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y); });
		this.addEvent(scrollObj, 'on_glidescroll_end', function(x, y) { dw_Scrollbar_Co.updateScrollbar(scrollObj, x, y); });

		// barObj 
		this.addEvent(barObj, 'on_slide_start', function() { dw_Scrollbar_Co.getWndoLyrRef(barObj) });
		this.addEvent(barObj, 'on_drag_start', function() { dw_Scrollbar_Co.getWndoLyrRef(barObj) });
		this.addEvent(barObj, 'on_slide', function(x, y) { dw_Scrollbar_Co.updateScrollPosition(barObj, x, y) });
		this.addEvent(barObj, 'on_drag', function(x, y) { dw_Scrollbar_Co.updateScrollPosition(barObj, x, y) });
		this.addEvent(barObj, 'on_slide_end', function(x, y) { dw_Scrollbar_Co.updateScrollPosition(barObj, x, y); });
		this.addEvent(barObj, 'on_drag_end', function(x, y) { dw_Scrollbar_Co.updateScrollPosition(barObj, x, y); });

	},

	// Provide means to add functions to be invoked on pseudo events (on_load, on_scroll, etc) 
	// without overwriting any others that may already be set
	// by Mark Wubben (see http://simonwillison.net/2004/May/26/addLoadEvent/)
	addEvent: function(o, ev, fp) {
		var oldEv = o[ev];
		if (typeof oldEv != 'function') {
			//o[ev] = fp;
			// almost all the functions (on_scroll, on_drag, etc.) pass x,y
			o[ev] = function(x, y) { fp(x, y); }
		} else {
			o[ev] = function(x, y) {
				oldEv(x, y);
				fp(x, y);
			}
		}
	},

	// Keep position of dragBar in sync with position of layer when scrolled by other means (mouseover, etc.)
	updateScrollbar: function(scrollObj, x, y) { // 
		var nx, ny;
		if (scrollObj.vBar && scrollObj.maxY) {
			var vBar = scrollObj.vBar;
			ny = -(y * ((vBar.maxY - vBar.minY) / scrollObj.maxY) - vBar.minY);
			ny = Math.min(Math.max(ny, vBar.minY), vBar.maxY);
			if (vBar.bar) { // ref to bar el
				nx = parseInt(vBar.bar.style.left);
				/*???*/
				vBar.shiftTo(nx, ny);
			}
		}
		/***customized***/
		/*changed to support multiple horizontal scrollbars*/
		if (scrollObj.hBars && scrollObj.maxX) {
			for (var idxHB = 0; idxHB < scrollObj.hBars.length; idxHB++) {
				var hBar = scrollObj.hBars[idxHB];
				nx = -(x * ((hBar.maxX - hBar.minX) / scrollObj.maxX) - hBar.minX);
				nx = Math.min(Math.max(nx, hBar.minX), hBar.maxX);
				if (hBar.bar) {
					ny = parseInt(hBar.bar.style.top);
					hBar.shiftTo(nx, ny);
				}
			}
		}
	},

	updateScrollPosition: function(barObj, x, y) { // on scrollbar movement
		var nx, ny; var wndo = barObj.wndo;
		if (!wndo.lyr) {
			wndo.lyr = document.getElementById(wndo.lyrId);
		}
		if (barObj.axis == "v") {
			nx = wndo.x; // floating point values for loaded layer's position held in shiftTo method
			ny = -(y - barObj.minY) * (wndo.maxY / (barObj.maxY - barObj.minY)) || 0;
		} else {
			ny = wndo.y;
			nx = -(x - barObj.minX) * (wndo.maxX / (barObj.maxX - barObj.minX)) || 0;
		}
		wndo.shiftTo(nx, ny);
	},

	// Scroll area may have both vertical and horizontal bars 
	getBarRefs: function(scrollObj) { // References to Slidebar instance and dom element 
		if (scrollObj.vBarId) {
			scrollObj.vBar = dw_Slidebar.col[scrollObj.vBarId];
			scrollObj.vBar.bar = document.getElementById(scrollObj.vBarId);
		}
		/***customized***/
		/*changed to support multiple horizontal scrollbars*/

		if (scrollObj.hBarIds) {
			for (var idxH = 0; idxH < scrollObj.hBarIds.length; idxH++) {
				if (idxH == 0) {
					scrollObj.hBars = [dw_Slidebar.col[scrollObj.hBarIds[idxH]]];
					scrollObj.hBars[0].bar = document.getElementById(scrollObj.hBarIds[idxH]);
				}
				else {
					scrollObj.hBars = scrollObj.hBars.concat(dw_Slidebar.col[scrollObj.hBarIds[idxH]]);
					scrollObj.hBars[scrollObj.hBars.length - 1].bar = document.getElementById(scrollObj.hBarIds[idxH]);
				}
			}
		}
	},

	getWndoLyrRef: function(barObj) {
		var wndo = barObj.wndo = dw_scrollObj.col[barObj.wndoId];
		if (wndo && !wndo.lyr) {
			wndo.lyr = document.getElementById(wndo.lyrId);
		}
	}

}
/////////////////////////////////////////////////////////////////////
// two ways to add style sheet for capable browsers

// Nov 2008 revision adds screen as option
// (may want printed copy to appear as on screen?)
dw_writeStyleSheet = function(file, screen) {
	var css = '<link rel="stylesheet" href="' + file + '"';
	if (screen !== false) {
		css += ' media="screen"';
	}
	document.write(css + ' />');
}

// slower, may flash unstyled ?
function dw_addLinkCSS(file, screen) {
	if (!document.createElement) return;
	var el = document.createElement("link");
	el.setAttribute("rel", "stylesheet");
	el.setAttribute("type", "text/css");
	if (screen !== false) {
		el.setAttribute("media", "screen");
	}
	el.setAttribute("href", file);
	document.getElementsByTagName('head')[0].appendChild(el);
}
/////////////////////////////////////////////////////////////////////

// Example class names: load_wn_lyr1, load_wn_lyr2_t2
dw_scrollObj.prototype.setUpLoadLinks = function(controlsId) {
	var wndoId = this.id; var el = document.getElementById(controlsId);
	var links = el.getElementsByTagName('a');
	var cls, parts;
	for (var i = 0; links[i]; i++) {
		cls = dw_scrollObj.get_DelimitedClass(links[i].className);
		parts = cls.split('_');
		if (parts[0] == 'load' && parts[1] == wndoId && parts.length > 2) {
			// no checks on lyrId, horizId
			var lyrId = parts[2]; var horizId = parts[3] ? parts[3] : null;
			dw_Event.add(links[i], 'click', function(wndoId, lyrId, horizId) {
				return function(e) {
					dw_scrollObj.col[wndoId].load(lyrId, horizId);
					if (e && e.preventDefault) e.preventDefault();
					return false;
				}
			} (wndoId, lyrId, horizId)); // see Crockford js good parts pg 39
		}
	}
}

dw_scrollObj.prototype.setUpScrollControls = function(controlsId, autoHide, axis) {
	var wndoId = this.id; var el = document.getElementById(controlsId);
	if (autoHide && axis == 'v' || axis == 'h') {
		dw_scrollObj.handleControlVis(controlsId, wndoId, axis);
		dw_Scrollbar_Co.addEvent(this, 'on_load', function() { dw_scrollObj.handleControlVis(controlsId, wndoId, axis); });
		dw_Scrollbar_Co.addEvent(this, 'on_update', function() { dw_scrollObj.handleControlVis(controlsId, wndoId, axis); });
	}

	var links = el.getElementsByTagName('a'), cls, eType;
	for (var i = 0; links[i]; i++) {
		cls = dw_scrollObj.get_DelimitedClass(links[i].className);
		eType = dw_scrollObj.getEv_FnType(cls.slice(0, cls.indexOf('_')));
		switch (eType) {
			case 'mouseover':
			case 'mousedown':
				dw_scrollObj.handleMouseOverDownLinks(links[i], wndoId, cls);
				break;
			case 'scrollToId':
				dw_scrollObj.handleScrollToId(links[i], wndoId, cls);
				break;
			case 'scrollTo':
			case 'scrollBy':
			case 'click':
				dw_scrollObj.handleClick(links[i], wndoId, cls);
				break;
		}
	}
}

dw_scrollObj.handleMouseOverDownLinks = function(linkEl, wndoId, cls) {
	var parts = cls.split('_'); var eType = parts[0];
	var re = /^(mouseover|mousedown)_(up|down|left|right)(_[\d]+)?$/;

	if (re.test(cls)) {
		var eAlt = (eType == 'mouseover') ? 'mouseout' : 'mouseup';
		var dir = parts[1]; var speed = parts[2] || null;
		var deg = (dir == 'up') ? 90 : (dir == 'down') ? 270 : (dir == 'left') ? 180 : 0;

		dw_Event.add(linkEl, eType, function(e) { dw_scrollObj.col[wndoId].initScrollVals(deg, speed); });
		dw_Event.add(linkEl, eAlt, function(e) { dw_scrollObj.col[wndoId].ceaseScroll(); });

		if (eType == 'mouseover') {
			dw_Event.add(linkEl, 'mousedown', function(e) { dw_scrollObj.col[wndoId].speed *= 3; });
			dw_Event.add(linkEl, 'mouseup', function(e) {
				dw_scrollObj.col[wndoId].speed = dw_scrollObj.prototype.speed;
			});
		}
		dw_Event.add(linkEl, 'click', function(e) { if (e && e.preventDefault) e.preventDefault(); return false; });
	}
}

// scrollToId_smile, scrollToId_smile_100, scrollToId_smile_lyr1_100    
dw_scrollObj.handleScrollToId = function(linkEl, wndoId, cls) {
	var parts = cls.split('_'); var id = parts[1], lyrId, dur;
	if (parts[2]) {
		if (isNaN(parseInt(parts[2]))) {
			lyrId = parts[2];
			dur = (parts[3] && !isNaN(parseInt(parts[3]))) ? parseInt(parts[3]) : null;
		} else {
			dur = parseInt(parts[2]);
		}
	}
	dw_Event.add(linkEl, 'click', function(e) {
		dw_scrollObj.scrollToId(wndoId, id, lyrId, dur);
		if (e && e.preventDefault) e.preventDefault();
		return false;
	});
}

// doesn't checks if lyrId in wndo, el in lyrId
dw_scrollObj.scrollToId = function(wndoId, id, lyrId, dur) {
	var wndo = dw_scrollObj.col[wndoId];
	var el = document.getElementById(id);
	if (el) {
		if (lyrId) {
			if (document.getElementById(lyrId) && wndo.lyrId != lyrId) {
				wndo.load(lyrId);
			}
		}
		var lyr = document.getElementById(wndo.lyrId);
		var x = dw_getLayerOffset(el, lyr, 'left');
		var y = dw_getLayerOffset(el, lyr, 'top');
		wndo.initScrollToVals(x, y, dur);
	}
}

dw_scrollObj.handleClick = function(linkEl, wndoId, cls) {
	var wndo = dw_scrollObj.col[wndoId];
	var parts = cls.split('_'); var eType = parts[0];
	var dur_re = /^([\d]+)$/; var fn, re, x, y, dur;

	switch (eType) {
		case 'scrollTo':
			fn = 'scrollTo'; re = /^(null|end|[\d]+)$/;
			x = re.test(parts[1]) ? parts[1] : '';
			y = re.test(parts[2]) ? parts[2] : '';
			dur = (parts[3] && dur_re.test(parts[3])) ? parts[3] : null;
			break;
		case 'scrollBy': // scrollBy_m30_m40, scrollBy_null_m100, scrollBy_100_null
			fn = 'scrollBy'; re = /^(([m]?[\d]+)|null)$/;
			x = re.test(parts[1]) ? parts[1] : '';
			y = re.test(parts[2]) ? parts[2] : '';

			// negate numbers (m not - but vice versa) 
			if (!isNaN(parseInt(x))) {
				x = -parseInt(x);
			} else if (typeof x == 'string') {
				x = x.indexOf('m') != -1 ? x.replace('m', '') : x;
			}
			if (!isNaN(parseInt(y))) {
				y = -parseInt(y);
			} else if (typeof y == 'string') {
				y = y.indexOf('m') != -1 ? y.replace('m', '') : y;
			}

			dur = (parts[3] && dur_re.test(parts[3])) ? parts[3] : null;
			break;

		case 'click':
			var o = dw_scrollObj.getClickParts(cls);
			fn = o.fn; x = o.x; y = o.y; dur = o.dur;
			break;
	}
	if (x !== '' && y !== '') {
		if (x == 'end') { x = wndo.maxX; }
		if (y == 'end') { y = wndo.maxY; }
		if (x === 'null' || x === null) { x = wndo.x; }
		if (y === 'null' || y === null) { y = wndo.y; }

		x = parseInt(x); y = parseInt(y);
		dur = !isNaN(parseInt(dur)) ? parseInt(dur) : null;

		if (fn == 'scrollBy') {
			dw_Event.add(linkEl, 'click', function(e) {
				dw_scrollObj.col[wndoId].initScrollByVals(x, y, dur);
				if (e && e.preventDefault) e.preventDefault();
				return false;
			});
		} else if (fn == 'scrollTo') {
			dw_Event.add(linkEl, 'click', function(e) {
				dw_scrollObj.col[wndoId].initScrollToVals(x, y, dur);
				if (e && e.preventDefault) e.preventDefault();
				return false;
			});
		}
	}
}

// get info from className (e.g., click_down_by_100)
dw_scrollObj.getClickParts = function(cls) {
	var parts = cls.split('_');
	var re = /^(up|down|left|right)$/;
	var dir, fn = '', dur, ar, val, x = '', y = '';

	if (parts.length >= 4) {
		ar = parts[1].match(re);
		dir = ar ? ar[1] : null;

		re = /^(to|by)$/;
		ar = parts[2].match(re);
		if (ar) {
			fn = (ar[0] == 'to') ? 'scrollTo' : 'scrollBy';
		}

		val = parts[3]; // value on x or y axis
		re = /^([\d]+)$/;
		dur = (parts[4] && re.test(parts[4])) ? parts[4] : null;

		switch (fn) {
			case 'scrollBy':
				if (!re.test(val)) {
					x = ''; y = ''; break;
				}
				switch (dir) { // 0 for unspecified axis 
					case 'up': x = 0; y = val; break;
					case 'down': x = 0; y = -val; break;
					case 'left': x = val; y = 0; break;
					case 'right': x = -val; y = 0;
				}
				break;
			case 'scrollTo':
				re = /^(end|[\d]+)$/;
				if (!re.test(val)) {
					x = ''; y = ''; break;
				}
				switch (dir) { // null for unspecified axis 
					case 'up': x = null; y = val; break;
					case 'down': x = null; y = (val == 'end') ? val : -val; break;
					case 'left': x = val; y = null; break;
					case 'right': x = (val == 'end') ? val : -val; y = null;
				}
				break;
		}
	}
	return { fn: fn, x: x, y: y, dur: dur }
}

dw_scrollObj.getEv_FnType = function(str) {
	var re = /^(mouseover|mousedown|scrollBy|scrollTo|scrollToId|click)$/;
	if (re.test(str)) {
		return str;
	}
	return '';
}

// return class name with underscores in it 
dw_scrollObj.get_DelimitedClass = function(cls) {
	if (cls.indexOf('_') == -1) {
		return '';
	}
	var whitespace = /\s+/;
	if (!whitespace.test(cls)) {
		return cls;
	} else {
		var classes = cls.split(whitespace);
		for (var i = 0; classes[i]; i++) {
			if (classes[i].indexOf('_') != -1) {
				return classes[i];
			}
		}
	}
}

dw_scrollObj.handleControlVis = function(controlsId, wndoId, axis) {
	var wndo = dw_scrollObj.col[wndoId];
	var el = document.getElementById(controlsId);
	if ((axis == 'v' && wndo.maxY > 0) || (axis == 'h' && wndo.maxX > 0)) {
		el.style.visibility = 'visible';
	} else {
		el.style.visibility = 'hidden';
	}
};
function init_dw_Scroll() {
	var wndo = new dw_scrollObj('scrollContainer', 'scrollContent', 'priceTableGrid');
	wndo.setUpScrollbar("dragBar", "track", "h", 1, 1);
	wndo.setUpScrollbar("dragBar-low", "track-low", "h", 1, 1);
	wndo.setUpScrollControls('scrollbar');
}

//this function has to be called after the pricetble is loaded
function InitPriceScrollbar() {
	// if code supported, link in the style sheet and call the init function onload
	if (dw_scrollObj.isSupported()) {

		var scroll_container = document.getElementById("scrollContainer");
		var scroll_content = document.getElementById("scrollContent");
		var track = document.getElementById("track");
		var trackLow = document.getElementById("track-low");
		var scrollbar = document.getElementById("scrollbar");
		var scrollerLow = document.getElementById("scrollerLow");
		var dragBar = document.getElementById("dragBar");
		var dragBarLow = document.getElementById("dragBar-low");


		if (track != null && scroll_container.offsetWidth > 0) {

			track.style.width = (scroll_container.offsetWidth - 2 * 12) + "px";
			trackLow.style.width = (scroll_container.offsetWidth - 2 * 12) + "px";
			scrollbar.style.width = scroll_container.offsetWidth + "px"
			scrollerLow.style.width = scroll_container.offsetWidth + "px"
			init_dw_Scroll();
			//test if content fits in container the dragbar can be hidden
			if (scroll_container.offsetWidth >= scroll_content.offsetWidth) {
				dragBar.style.display = "none";
				dragBarLow.style.display = "none";
			}

			scroll_container.style.height = scroll_content.scrollHeight + "px";
		}
	}
}
// Copyright 2007 Google, Inc.
// This sample code is under the Apache2 license, see
// http://www.apache.org/licenses/LICENSE-2.0 for license details.
/**
 * @fileoverview Wrapper for Time Tracking
 */

/**
 * @class Time Tracking component.
 *     This class encapsulates all logic for time tracking on a particular
 *     page. Time tracking could be for any object within a page or the page
 *     itself.
 *
 * @param {Array.<Number>} arg1 Optional array that represents the bucket
 * @constructor
 */
var TimeTracker = function(opt_bucket) {
  if (opt_bucket) {
    this.bucket_ = opt_bucket.sort(this.sortNumber); 
  } else {
    this.bucket_ = TimeTracker.DEFAULT_BUCKET;
  }
};

TimeTracker.prototype.startTime_;
TimeTracker.prototype.stopTime_;
TimeTracker.prototype.bucket_;
TimeTracker.DEFAULT_BUCKET = [100, 500, 1500, 2500, 5000];

/**
 * Calculates time difference between start and stop
 * @return {Number} The time difference between start and stop
 */
TimeTracker.prototype._getTimeDiff = function() {
  return (this.stopTime_ - this.startTime_);
};

/**
 * Helper function to sort an Array of numbers
 * @param {Number} arg1 The first number
 * @param {Number} arg2 The second number
 * @return {Number} The difference used to sort
 */
TimeTracker.prototype.sortNumber = function(a, b) {
  return (a - b);
}

/**
 * Records the start time
 * @param {Number} arg1 Optional start time specified by user
 */
TimeTracker.prototype._recordStartTime = function(opt_time) {
  if (opt_time != undefined) {
    this.startTime_ = opt_time;
  } else {
    this.startTime_ = (new Date()).getTime();
  }
};

/**
 * Records the stop time
 * @param {Number} arg1 Optional stop time specified by user
 */
TimeTracker.prototype._recordEndTime = function(opt_time) {
  if (opt_time != undefined) {
    this.stopTime_ = opt_time;
  } else {
    this.stopTime_ = (new Date()).getTime();
  }
};

/**
 * Tracks the event. Calculates time and sends information to
 * the event tracker passed
 * @param {Object} arg1 GA tracker created by user
 * @param {String} arg2 Optional event object name
 * @param {String} arg3 Optional event label
 */
TimeTracker.prototype._track = function(tracker,
                                        opt_event_obj_name,
                                        opt_event_label) {
  var eventTracker;
  if (opt_event_obj_name != undefined && opt_event_obj_name.length != 0) {
    eventTracker = tracker._createEventTracker(opt_event_obj_name);
  } else {
    eventTracker = tracker._createEventTracker('TimeTracker');
  }

  var i;
  var bucketString;
  for(i = 0; i < this.bucket_.length; i++) {
    if ((this._getTimeDiff()) < this.bucket_[i]) {
      if (i == 0) {
        bucketString = "0-" + (this.bucket_[0]);
        break;
      } else {
        bucketString = this.bucket_[i - 1] + "-" + (this.bucket_[i] - 1);
        break;
      }
    }
  }
  if (!bucketString) {
    bucketString = this.bucket_[i - 1] + "+";
  }
  eventTracker._trackEvent(bucketString, opt_event_label, this._getTimeDiff());
};

/**
 * Sets the bucket for histogram generation in GA
 * @param {Array.<Number>} The bucket array
 */
TimeTracker.prototype._setHistogramBuckets = function(buckets_array) {
  this.bucket_ = buckets_array.sort(this.sortNumber);
};

function OpenSendAFriendWindow(url) {    
	width = 450;
	height = 380;
	winName = "SendAFriend";
	
	options = 'toolbar=no,menubar=no,location=no,directories=no,status=no,scrollbars=auto,resizable=no,copyhistory=no';
	options += ',width=' + width + ',height=' + height;
	if (window.screen)
	{
		windowLeft = (screen.availWidth - width)/2;
		windowTop = (screen.availHeight - height)/2;
		options += ',left=' + windowLeft + ',top=' + windowTop;
	}
	newwindow = window.open(url,winName,options);
	newwindow.opener = this;
	newwindow.focus();
}

function OpenPrintSelectorWindow(url)
 {    
	width = 380;
	height = 280;
	winName = "PrintSelector";
	
	options = 'toolbar=no,menubar=no,location=no,directories=no,status=no,scrollbars=auto,resizable=no,copyhistory=no';
	options += ',width=' + width + ',height=' + height;
	
	if (window.screen)
	{
		windowLeft = (screen.availWidth - width)/2;
		windowTop = (screen.availHeight - height)/2;
		options += ',left=' + windowLeft + ',top=' + windowTop;
	}
	
	var tripSpecificationElement = document.getElementById('_tripSpecification');
	var tripSpecification ="";
	
	if (tripSpecificationElement !=null)
	{
	  tripSpecification = tripSpecificationElement.value;
	}	
	theUrl = url + "&tripSpec="+ tripSpecification;	
	newwindow = window.open(theUrl,winName,options);
	newwindow.opener = this;
	newwindow.focus();
}

function OpenPrintAccommodationWindowUrl(baseUrl)
 {  
	if (baseUrl == "" || baseUrl == null)
	{
			throw("Missing URL from sender exception!");
	}	
	var width = 640;
	var height = 700;
	var winName = "AccommodationPrintPage";

	var options = 'toolbar=no,menubar=no,location=no,directories=no,status=no,scrollbars=yes,resizable=no,copyhistory=no';
	options += ',width=' + width + ',height=' + height;


	if (window.screen)
	{
		var windowLeft = (screen.availWidth - width)/2;
		var windowTop = (screen.availHeight - height)/2;
		options += ',left=' + windowLeft + ',top=' + windowTop;
	}
	
	var url = baseUrl;						
	var idx;		

	for(idx= 0; idx< chkItems.length; idx++)
	{
		var elemId = chkItems[idx][0];
		var paramName = chkItems[idx][1];

		var chk = document.getElementById(elemId);
		if ((chk != null) && (chk.type == 'checkbox') && (chk.checked))
		{				
			url+='&' + paramName + '=1';		
		}
	}	
		
	/*TODO(sergiu) add the check back if (urlParam == null || urlParam == "")
	if (urlParam == null)
	{
		throw("Missing parameters exception");
	}  

	url+=urlParam; 
	*/
	
	var newwindow = window.open(url, winName, options);
	if (newwindow != null)
	{
		newwindow.opener = this.opener;
		newwindow.focus();	
		self.close();
	}    
}


// JS file containing functions used by the price-calculation.

// ====================================================
//	Shows or hides the price calculation PriceHelp.
// ====================================================
function ShowPriceCalculationPriceHelp(visible) {
	var priceHelp = document.getElementById('PriceHelp');
	if (priceHelp) {
		if (visible) { priceHelp.style.visibility = "visible"; }
		else { priceHelp.style.visibility = "hidden"; }
	}
}

// ====================================================
//	Moves the price calculation panel to a visible area on the screen.
// ====================================================
function MovePriceCalculation() {
	var priceCalculationMovable = document.getElementById('PriceCalculationMovable');
	var priceTableTab = document.getElementById('pricetable_data');
	var scrollPosition;
	var maxTop = 550;
}
// ====================================================
//	Hides the price calculation
// ====================================================
function HidePriceCalculation() {
	var priceCalculationContainer = document.getElementById('PriceCalculationContainer');
	priceCalculationContainer.style.display = "none";
}

// ====================================================
//	Shows the price calculation and if needed resizes the tab containing it
// ====================================================
function ShowPriceCalculation() {
	var priceTabPaddingBottom = 10;
	var priceTableContainer = document.getElementById('priceTableContainer');
	var priceCalculationContainer = document.getElementById('PriceCalculationContainer');
	var priceCalculationMovable = document.getElementById('PriceCalculationMovable');
	var priceTableTab = document.getElementById('pricetable_data');

	priceCalculationContainer.style.display = "block";

	if (priceTableTab) {
		// get the current height of the the tab
		var currentTabHeight = priceTableTab.offsetHeight;
		// get the new height that is required for the tab after displaying the pricecalculation
		var requiredHeightCalculation = priceCalculationMovable.offsetHeight + priceCalculationMovable.offsetTop;

		// resize the tab when the height of the pricecalculation > the height of the tab
		if (requiredHeightCalculation > currentTabHeight) {
			priceTableTab.style.height = priceTabPaddingBottom + requiredHeightCalculation + 'px';
		}
		// resize the tab when the height of the pricecalculation < the height of the tab
		if (requiredHeightCalculation < currentTabHeight) {
			if (priceTableContainer != null) {
				// get the height required for the pricetable
				var requiredHeightPriceTable = priceTableContainer.offsetHeight;
				// if the height of the pricecalculation > the height of the pricetable,
				// set the pricetab height to the height of the pricecalculation
				if (requiredHeightCalculation > requiredHeightPriceTable) {
					priceTableTab.style.height = priceTabPaddingBottom + requiredHeightCalculation + 'px';
				}
				// if the height of the pricecalculation < the height of the pricetable,
				// set the pricetab height to the height of the pricetable
				if (requiredHeightCalculation < requiredHeightPriceTable) {
					priceTableTab.style.height = priceTabPaddingBottom + requiredHeightPriceTable + 'px';
				}
			}
		}
	}
}

// ====================================================
//	Called when either the transport option or lodgement option
//  in the price calculation is changed. This change results in
//  1) a new price calculation and 2) an update of the price table with
//  the selected transport- and lodgement codes.
//	The optionValue argument should be a string containing the trip spec, 
//	transport code and lodgement code (optional), separated by a &.
//	Example: "B5AGShJIAgI3RApXQVRJUkggUk9ZBENtQ21DbUNt0&WATIRH ROY&7D",
//  where 'WATIRH ROY' is the transport code and '7D' the lodgement code.
// ====================================================
function ProcessPriceCalcSelectionChangeEvent(optionValue) {
	var Array;
	var TripSpec;
	var MonthNumber, TransportCode, LodgementCode;
	var MonthNumberInput;

	// The optionValue is a '&' separated string containing the trip spec, 
	// transport code and lodgement code (optional!)
	Array = optionValue.split('&');

	// Get the selected trip spec
	TripSpec = Array[0];
	// Get the selected month number from the price table controls
	MonthNumberInput = document.getElementById('monthfilter');
	if (MonthNumberInput != null) MonthNumber = MonthNumberInput.options[MonthNumberInput.selectedIndex].value;
	else MonthNumber = '';
	// Get the transport code
	TransportCode = Array[1];
	// Get the lodgement code. This code is optional so it set it to null if it is not there.
	LodgementCode = (Array.length > 2) ? Array[2] : null;
	// Update the price calculation
	CallPriceCalculationUpdate(TripSpec, null);
	// Refresh the price table with the current selection
	DoRetrievePricesDaVinci(MonthNumber, TransportCode, LodgementCode);
}

function ProcessPriceCalcPartyCompositionChangeEvent(TripSpec) {
	// Update the price calculation
	CallPriceCalculationUpdate(TripSpec, null);
}

// ====================================================
//	Function for updating the PriceCalculation	
// ====================================================
function PriceCalcHandleCallbackServerResponse(arg, context) {
	if (arg == '-2') {
		OpenPartyNotFitEditor();
	}
	else {
		// get the price from the context, which is the price cell. If it is available, add it to the price calc url
		var priceCalcUrl = arg;
		var price;
		if (context != null) {
			if (context.innerText != null) {
				price = context.innerText;
			}
			else {
				if (context.textContent != null) {
					price = context.textContent;
				}
			}
			
			if (price != '') {
				price = new Number(price);
				if (!isNaN(price)) {
					var priceString = price.toFixed(2).toString();
					
					// now make sure that the decimal formatter is a comma instead of a dot
					priceString = priceString.replace(".",",");
					priceCalcUrl += '&prc=' + priceString;
				}
			}
		}
		
	  var priceCalculationFrame = document.getElementById('pricecalculation_frame');
	  priceCalculationFrame.src = priceCalcUrl;

	  ShowPriceCalculation();
		UpdatePriceCalculationOnTabs();
	}
}

// ====================================================
//	Function for updating the PriceCalculation on other tabs
// ====================================================
function UpdatePriceCalculationOnTabs() {
	var priceCalculationTabInfo = document.getElementById('PriceCalculationTabInfo');
	var priceCalculationTabTestimonial = document.getElementById('PriceCalculationTabTestimonial');
	var priceCalculationTabBookOptions = document.getElementById('PriceCalculationTabBookOptions');
	var priceCalculationContainer = document.getElementById('PriceCalculationContainer');

	if (priceCalculationTabInfo) { priceCalculationTabInfo.innerHTML = priceCalculationContainer.innerHTML };
	if (priceCalculationTabTestimonial) { priceCalculationTabTestimonial.innerHTML = priceCalculationContainer.innerHTML };
	if (priceCalculationTabBookOptions) {
		priceCalculationTabBookOptions.innerHTML = priceCalculationContainer.innerHTML;
	}
}

function UpdatePriceTableFromCalculation(transportCode, lodgementCode) {
	alert('Updating price table. Transport: ' + transportCode + ' Lodgement: ' + lodgementCode);
}

//// ====================================================
////	Function to be called when you wish to show
////	the price calculation
//// ====================================================
function ShowPriceCalculation() {
	  var priceCalculationFrame = document.getElementById('pricecalculation_frame');
	  priceCalculationFrame.style.display = 'block';
	  priceCalculationFrame.style.visibility = 'visible';
}

$(document).ready(function() {
	if ($('#pricecalculation_frame').attr('src') && $('#pricecalculation_frame').attr('src') != '') {
		ShowPriceCalculation();
	}
});
   // redirect to the content page
   function redirectToContent(linkElemenent, url) {
   	// if the call is made from the history page, toggle the tabs
   	if (IsRedirectFromContent(url)) {
   		var lSplits = url.split('#');
   		if (lSplits[1] != undefined) {
   			var el = $get(lSplits[1]);
   			// try getting the #termTab to be focused
   			if (focusTab && el != undefined) {
   				var tab = $get(el.id + '_data');
   				focusTab(tab);
   				focusTabItem(el, tab);
   			}
   			// if no tabs are available, redirect
   			else {
   				window.location = url;
   			}
   		}
   		// if the page does not contain any #term, redirect
   		else {
   			window.location = url;
   		}
   	}
   	// if the call is made from a page diferent than the content page, redirect
   	else {
   		window.location = url;
   	}
   }
   // check to see if the redirect call is made from the content page
   function IsRedirectFromContent(url) {
   	var lPath = 'content/index.aspx';
   	return (url.indexOf(lPath) > -1) && (window.location.href.indexOf(lPath) > -1);
   }

(function($) {

	$(document).ready(function() {
	
		if (!IsHistoryCookieAvailable()) {
			UpdateHistory();
		}
		else {
			DisplayHistoryFromCookie();
		}
	});

})(jQuery);



var panel = document.getElementById('pnlCompositionEditor');
if (panel != undefined && panel.parentNode) {
	panel.parentNode.removeChild(panel);
	document.forms[0].insertBefore(panel, document.forms[0].firstChild);
}
function ResizeFadeOutPanel() {
	var panel = document.getElementById('pnlCompositionEditor');
	panel.style.height = document.getElementsByTagName("body")[0].scrollHeight + "px";
	panel.style.width = document.getElementsByTagName("body")[0].scrollWidth + "px";
}
// redirect to the history page
function redirectToHistory(linkElemenent, url) {
	// if the call is made from the history page, toggle the tabs	
	if (IsRedirectFromHistory(url)) {		
			var lSplits = url.split('#');
			if (lSplits[1] != undefined) {
				var el = $get(lSplits[1]);
				var tab = $get(el.id + '_data');				
				focusTab(tab);
				focusTabItem(el, tab);
		}
	}
	// if the call is made from a page diferent than the history page, perform the redirect
	else {
		window.location = url;
	}
}
// check to see if the redirect call is made from the history page
function IsRedirectFromHistory(url) {
	var lPath = 'index.aspx#';
	return (url.indexOf(lPath) > -1) && (window.location.href.indexOf('history') > -1);
}
// updates the text on the user menu control with the number of viewed/stored accommodations.
function UpdateButtonTexts(savedText, viewedText) {
		//defer the update of the button texts until the page is fully loaded.
		$(document).ready(function() {
			SaveHistoryCountsInCookie(viewedText, savedText);
			DisplayHistory(viewedText, savedText);
		});
}

function updateUserMenu(id, message) {
	var lButton = $get(id);
	if (lButton) {
		lButton.innerHTML = message;
	}
}





function DisplayHistory(viewedCount, storedCount) {


	var viewedText = $('#HistoryLink_Viewed').html().replace(/\(\d*\)/, "(" + viewedCount + ")");
	var storedText = $('#HistoryLink_Stored').html().replace(/\(\d*\)/, "(" + storedCount + ")");
	var viewedLink = $('#HistoryLink_Viewed');
	var storedLink = $('#HistoryLink_Stored');
	viewedLink.html(viewedText);
	storedLink.html(storedText);
	viewedLink.attr("title", viewedText);
	storedLink.attr("title", storedText);
}

function UpdateHistory() {

	var lCode = $("input#code").val();

	$.ajax({

		type: "POST",
		url: "/accommodation/WebServices/CustomerHistoryService.svc/UpdateCustomerHistory",
		contentType: "application/json; charset=utf-8",
		data: JSON.stringify({ "key": lCode }),
		dataType: "json",
		success: function(json) {

			SaveHistoryCountsInCookie(json.d.Viewed, json.d.Stored);
			DisplayHistory(json.d.Viewed, json.d.Stored);

		}
	});
}

function IsHistoryCookieAvailable() {
	var lCode = $("input#code").val();
	return $.cookie("HistoryItemsViewed" + lCode) != null;
}

function DisplayHistoryFromCookie() {
	var lCode = $("input#code").val();
	DisplayHistory($.cookie("HistoryItemsViewed" + lCode), $.cookie("HistoryItemsStored" + lCode));

}
function SaveHistoryCountsInCookie(viewedCount, storedCount) {
	var lCode = $("input#code").val();
	$.cookie("HistoryItemsViewed" + lCode, viewedCount, { path: "/", expires: 30 });
	$.cookie("HistoryItemsStored" + lCode, storedCount, { path: "/", expires: 30 });
}
(function($) {

	$(document).ready(function() {
		var lCode = $("input#code").val();
		var lAccoId = $("input#hisAccoId").val();
		var lAccoCode = $("input#hisAccoCode").val();

		$.ajax({
			type: "POST",
			url: "WebServices/CustomerHistoryService.svc/AddItemToCustomerHistory",
			contentType: "application/json; charset=utf-8",
			data: JSON.stringify({ "key": lCode, "accommodationId": lAccoId, "accommodationCode": lAccoCode }),
			dataType: "json",
			complete: function(json) {

				UpdateHistory();

			}
		});

	});

})(jQuery);
function NewWindow(theURL,winName,features)
{
  newwindow = window.open(theURL,winName,features);
  if (newwindow) {
  	newwindow.focus();
  }
}

//Scalable Tabset script 
//TODO:
//check why sometimes the offsetwidth is smaller then the rendering width
//

/**************************
Restructure code
**************************/

var isFirstTab = true;

function buildTabs(){	
		
	// Create a container for the tab panel headings
	var tabContainer = $("<ul class='strip'></ul>").appendTo(this);
	var panelContainer = $("<div class='data'></div>").appendTo(this);
	
	$("> div[class!=data]", this)

	// Process the tabs and their panels
		.each(function() {
			var tabPanelId = $(this).attr("id").toLowerCase();
			// Give each tab panel a proper id and proper styling.
			// Add a clearing div to force floated content to clear properly.
			var tabPanel =
				$(this)
					.attr("id", tabPanelId + "_data")
					.addClass("tab")
					.append("<div class='clearing'></div>");

			// Add a tab heading for each panel
			$("<li></li>")
				.attr("id", tabPanelId)
				.text(tabPanel.attr("title"))
				.appendTo(tabContainer);

			// Move the tab using the direct DOM functions instead of jQuery.appendTo,
			// which re-runs scripts.
			panelContainer[0].appendChild(this);
		})
		.filter(":first")
			.each(function() {
				focusTab(this);
			});

	// Prevent margin spacing on the last tab heading
	tabContainer
		.find("li:last")
			.addClass("nomargin");

	// If the current tabset was hidden (while loading the page) make it visible now.
	$(this).removeClass("hidden");	
}

/**************************
runtime behavior code
**************************/

function tabclick(el, useFallback) {
	var tab = document.getElementById(el.id + '_data');
	// call google tracker to track the tab click
	// the call is in a try{}catch{} block because the method needs to 
	// be defined in the page before the call.

	// for the implicit tab that is loaded the tracking is bypassed
	if (!isFirstTab) {
		try { trackTabClick(el); } catch (err) { }

	}
	isFirstTab = false;
	focusTab(tab);
	focusTabItem(el, tab);
	GetOriginalStrips(tab);

	if (IsFallbackNeeded(el, 0) > 1) {
		if ((useFallback != null) && (useFallback)) {
			fallbackFocus(el);
		}
	}
	if (el.id == "pricetable" && typeof (InitPriceScrollbar) != "undefined") {
			InitPriceScrollbar();
	}
}

/*Recursively determines if a tab control nested inside another tab control 
tabs - number of tab controls in the nest
*/
function IsFallbackNeeded(tabItem, tabs) {
	if (tabItem.nodeType == 9) {
		//reached the end document node so there is no point in going further
		return tabs;
	}
	else {
		if (tabItem.className.indexOf('tabset') > -1 && tabItem.className.indexOf('set') > -1) {
			//found a tab control
			tabs++;
		}
		//go one step up in the DOM
		return IsFallbackNeeded(tabItem.parentNode, tabs);
	}
}

/*if the current tab control is nested inside another tab control focus the tabs as required*/
function fallbackFocus(tabItem) {

	//get the tab the current tab is nested in
	var tabs = new Array();

	tabs = getParentTabItem(tabItem.parentNode, tabs);

	if (tabs != null && tabs.length == 2) {
		//focus the tab and its content
		//		focusTab(tabs.pop());
		//		focusTabItem(tabs.pop());

		focusTab(tabs[1]);
		focusTabItem(tabs[0]);
		tabs[1].focus();
	}
}

function getParentTabItem(el, tabs) {
	if (el.nodeType == 9 || tabs.length > 0) {
		//no elements found ... if this point is reached then there is an error
		return null;
	}
	else {
		if (el.id.indexOf('_data') > -1) {
			// a (data) was found
			var tabItem = getTabItemFromTabData(el);
			// a tab was found (LI)
			if (tabItem != null) {
				tabs.push(tabItem);
				tabs.push(el);

				return tabs;
			}
		}
		else {
			//go one level up in the DOM
			return getParentTabItem(el.parentNode, tabs);
		}
	}
}

function getTabItemFromTabData(tabData) {
	var tabItemId = tabData.id.substring(0, tabData.id.length - 5);
	return document.getElementById(tabItemId);
}

/* tab strip items behavior */
function focusTabItem(tabItem, dataTab) {
	var tabStripList = tabItem.parentNode.parentNode.childNodes;
	var i;

	for (i = 0; i < tabStripList.length; i++) {
		if ((tabStripList[i].nodeType == 1) && (tabStripList[i].className.indexOf('strip') > -1)) {
			blurSiblingTabItems(tabStripList[i].firstChild)
		}
	}
	//		blurSiblingTabItems(tabItem.parentNode.firstChild);
	tabItem.className += " on";

	try {
		FindOverflowClass(dataTab.childNodes, 'fragment')
	}
	catch (err) {

	}
}

function blurSiblingTabItems(tabItem) {
	if (tabItem != null) {
		if (tabItem.nodeType == 1)// elements only
		{
			tabItem.className = tabItem.className.replace(/\s*on/, '');
			if (document.all) {
				tabItem.className = tabItem.className.replace(/\s*hover/, "");
			}
		}
		blurSiblingTabItems(tabItem.nextSibling);
	}
}

/* tab (data) behavior */
function focusTab(tabElement) {
	if (tabElement != null) {
		blurSiblingTabs(tabElement.parentNode.firstChild);
		tabElement.className += " on";
	}
}

function findActiveTab(tabSet) {
	// find the first div in a div (first tab in data div)
	var CurTab = tabSet.getElementsByTagName('DIV')[1];
	while (CurTab != null) {
		if (CurTab.className.indexOf('on') > -1) {
			return CurTab;
		}
		else {
			CurTab = CurTab.nextSibling;
		}
	}
	return null;
}

function resizeParent(tabElement) {
	var maincont = tabElement.parentNode.parentNode;
}

function blurSiblingTabs(tabElement) {
	if (tabElement != null) {
		if (tabElement.nodeType == 1)// elements only
		{
			tabElement.className = tabElement.className.replace(/\s*on/, '');
		}
		blurSiblingTabs(tabElement.nextSibling);
	}
}

/* behavior init methods */
function setTabsBehavior(tabdiv) {
	var TabItem = tabdiv.getElementsByTagName('LI')[0];
	while (TabItem != null) {
		SetTabItemBehavior(TabItem);
		TabItem = TabItem.nextSibling;
	}
}

function SetTabItemBehavior(node) {
	node.onmouseover = function() { node.className += ' hover' }
	node.onmouseout = function() { node.className = node.className.replace(/\s*hover/, '') }
	node.onclick = function() { tabclick(node); }
}

function openTabFromUrl() {
	var locSplit = window.location.href.split('#');
	var result = '';

	if (locSplit.length > 1)
		result = locSplit[locSplit.length - 1].toLowerCase();

	return result;
}

function openFirstTabs() {
	var nodeId = openTabFromUrl();
	var tabNode = $(nodeId.length > 0) ? document.getElementById(nodeId) : null;
	if (tabNode) {
		tabclick(tabNode, true);
	}
	else {
		var tabs = $("> ul > li", this);
		if (tabs.length > 0) tabclick(tabs[0]);		
	}
}

function applyTabBehaviors() {
		setTabsBehavior(this);
}

/* like click on tab */
function openTab(tabId) {
	var tab = document.getElementById(tabId);
	if (tab) {
		// open the tab
		tabclick(tab);
		// open parent
		var parent = tab.parentElement;
		while (parent != null && parent.id.indexOf('_data') < 0) {
			parent = parent.parentElement;
		}
		if (parent != null) {
			openTab(parent.id.replace('_data', ''));

		}
	}
}

/* click from an external link and lunck the click on tab */
function remoteOpenTab(link) {
	var locSplit = link.split('#');
	var result = '';

	if (locSplit.length > 1)
		result = locSplit[locSplit.length - 1].toLowerCase();
	openTab(result);
}

function openLocationHashTab() {
	var hash = location.hash;
	var tabId;

	if (hash != '') {
		tabId = hash.replace('#', '');
		var element = document.getElementById(tabId);
		if (element != null) {
			/* Check if the provided hash is not real anchor */
			if (element.tagName != 'A') {
				openTab(tabId);
			}
			else {  //ie bugfix
				var parent = element.parentNode;
				while (parent != null && parent.id.indexOf('_data') < 0) {
					parent = parent.parentNode;
				}
				if (parent != null) {
					openTab(parent.id.replace('_data', ''));
				}
			}
		}
		else {
			var anchorCol = document.getElementsByTagName('A');
			var i = 0;
			var foundElement;
			for (i; i < anchorCol.length; i++) {
				if (anchorCol[i].name == tabId) {
					foundElement = anchorCol[i];
					i = anchorCol.length;
				}
			}
			if (foundElement != null) {
				var parent = foundElement.parentNode;
				while (parent != null && parent.id && parent.id.indexOf('_data') < 0) {
					parent = parent.parentNode;
				}
				if (parent != null) {
					openTab(parent.id.replace('_data', ''));
				}
			}
		}
	}
}

// New Scale specific script

function setNoMarginLastChild(List) {
	if ((List != null) && (List.lastChild != null)) {
		List.lastChild.className += " nomargin"
	}
} 

//search strip elements
//if a strip element is found
//look is there are sibling strip elements
function GetOriginalStrips(node) {
	var count = 0;
	var list;
	list = node.getElementsByTagName('UL');
	//loop through all ul items
	for (count; count < list.length; count++) {
		//if it is a strip element
		if (list[count].className.indexOf("strip") > -1) {
			var placeholder;
			var placeholderSet = false;
			var parent;
			var originalStrip;
			//get sibling ul set for a complete list item set. This is done in case a tabstrip is already split across several strips. 
			var siblingSet = list[count].parentNode.childNodes
			var y;

			//create a dummy placeholder for the future tabstrips
			placeholder = document.createElement('DIV');
			placeholder.className = 'placeholder';
			placeholder.id = 'dummy';

			originalStrip = document.createElement('UL');
			originalStrip.className = 'strip';

			placeholder.appendChild(originalStrip);

			//reverse order. Original tabstrip is split across several ul's with the last ul containing the first li's
			for (y = siblingSet.length - 1; y >= 0; y--) {
				if (siblingSet[y].nodeType == 1 && siblingSet[y].className.indexOf("strip") > -1) {
					parent = siblingSet[y].parentNode;
					if (!placeholderSet) {
						// place a placeholder and remove the split strip
						parent.insertBefore(placeholder, siblingSet[y]);
						y = y + 1;
						AppendListItems(originalStrip, parent.removeChild(siblingSet[y]));
						placeholderSet = true;
					}
					else {
						//remove the split strip
						AppendListItems(originalStrip, parent.removeChild(siblingSet[y]));
					}
				}

			}
			//original strip is restored. and placed in the placeholder in a strip element. It is placed in a strip element
			// for the width calculation of the elements. If this is not done the style on the listitems are lost.

			//create new tabstrips next
			count += CreateNewTabStrips(originalStrip, placeholder) - 1;
		}
	}
}

//create new tabstrips at the place of the placeholder
function CreateNewTabStrips(originalStrip, placeholder) {
	var currentInsertPoint;
	var totalWidth;
	var elementWidth;
	var elementCount;
	var stripCount = 0;

	var widthLimit = GetWidthLimit(document.getElementById(originalStrip.childNodes[0].id + '_data'));
	var i = 0;
	//set current insertion point
	currentInsertPoint = placeholder;
	//get list item count
	elementCount = originalStrip.childNodes.length;

	//get a new tab strip with the correct css classes
	var newStrip = GetNewStrip(stripCount++)
	//strip paddings
	var totalWidth = 5 * stripCount;
	//add the strip to the dom and set is as the current insert point for listitems/strips
	currentInsertPoint.parentNode.insertBefore(newStrip, currentInsertPoint)
	currentInsertPoint = newStrip;
	//loop through all the list items
	for (i = 0; i < elementCount; i++) {
		//get elementwidth(offsetwidth(contentwidth + paddingwidth's + borderWidth's) + marginWidth's
		elementWidth = GetElementWidth(originalStrip.childNodes[0]);

		//check if new width exceeds the limit
		if ((totalWidth + elementWidth) > widthLimit) {
			//limit exceded
			//create a new tabstrip set.
			//insert it in the DOM
			//Set it as the current insertion point.
			//reset the width counter
			setNoMarginLastChild(currentInsertPoint);
			newStrip = GetNewStrip(stripCount++);
			currentInsertPoint.parentNode.insertBefore(newStrip, currentInsertPoint)
			currentInsertPoint = newStrip;
			totalWidth = 5 * stripCount;
		}
		//add the list item to the strip
		currentInsertPoint.appendChild(originalStrip.childNodes[0]);
		//count the width
		totalWidth += elementWidth;
	}

	//when done remove the obsolete placeholder container
	placeholder.parentNode.removeChild(placeholder);
	return stripCount;
}

//gather all the list items of the strips in a set.
function AppendListItems(targetElement, listItemContainer) {
	var itemList = listItemContainer.getElementsByTagName('LI');
	var count = itemList.length;
	var i = 0;
	for (i = 0; i < count; i++) {
		//IE FIX
		//fixes stuck hover effect.
		// TODO check why hover is stuck and check strange behavior when 2 tabsets are involved
		// guessing hover style gets stuck at a resize event cycle when the li's are split across different strips.
		while (itemList[0].className.indexOf('hover') > 1) {
			itemList[0].className = itemList[0].className.replace(/\s*hover/, "");
		}

		targetElement.appendChild(itemList[0]);
	}
}

//calculate the element currentwidth of the provided element
function GetElementWidth(el) {
	var totalElementWidth = 0;
	if (document.all) {
		//IE
		totalElementWidth = el.offsetWidth + parseInt(el.currentStyle.marginLeft.replace('px', '')) + parseInt(el.currentStyle.marginRight.replace('px', ''));
	}
	else {
		//Firefox opera does not work in safari
		totalElementWidth = el.offsetWidth + parseInt(window.getComputedStyle(el, null).marginLeft.replace('px', '')) + parseInt(window.getComputedStyle(el, null).marginRight.replace('px', ''));
	}
	return totalElementWidth;
}

//create a strip with the correct css classes
function GetNewStrip(count) {
	var newStrip = document.createElement('UL');
	if (count == 0) {
		newStrip.className = 'strip';
	}
	else {
		newStrip.className = 'strip strip' + count;
	}
	return newStrip
}

//get the width limit of the strips
//gets the tab_data segment and searches the displayed tab
//and returns it's offsetWidth
function GetWidthLimit(el) {
	var list = el.parentNode.childNodes;
	var counter = 0;
	while (list[counter] != null) {
		if (list[counter].nodeType == 1 && list[counter].offsetWidth > 0) {
			return list[counter].offsetWidth - 5;
		}
		counter++
	}
	return 300; //in the event that no width is found return a standard value
}

// checks if tabElement.id is in the array tracking list and if it is track the tab on google analytics.
function trackOnGoogleTabClick(tabElement, googlePageTracker) {
	var lTabText, lTabsToTrack, lIndex, lPath, lCurrentPageAddress;

	// an array to keep all the tab id's we want to track on Google Analytics
	lTabsToTrack = new Array('pricetable', 'info', 'testimonial', 'excursions', 'flights', 'dive',
		'weather', 'map', 'carrent', 'accommodations', 'bookoptions', 'skiarea', 'destinations');

	// web address to track
	// use regular expression to replace the space intead of simple replace
	lTabText = tabElement.innerHTML.replace(/ /g, '_').replace(/&amp;/g, '&');
	lIndex = document.location.toString().indexOf(document.location.pathname.toString())
	lPath = document.location.toString().substring(lIndex);
	lCurrentPageAddress = lPath + '~' + lTabText;

	// loop and see if the tabElement.id belongs to the array list; if it belongs then track the event if not continue 
	// to the next iteration 
	for (i = 0; i < lTabsToTrack.length; i++) {
		if (lTabsToTrack[i] != tabElement.id)
			continue;

		if (googlePageTracker != null) {
			googlePageTracker._trackPageview(lCurrentPageAddress);
		}
	}
}

/*
	Since the redrawing of the HTML for the tabs can have iframes to become empty,
	reload the iframes
*/
function reloadFrames() {
	$("div.tabset iframe[src]:visible", document).each(function() {
		try {
			var iFrameCopy = $(this).clone();
			$(this).replaceWith($(iFrameCopy));
		}
		catch (e) { }
	});
}

function InitTabs() {

	$("div.tabset", document).each(function() {

		// Check for presence of an initialization marker, so that
		// the tabset isn't initialized twice.
		if ($(this).data("tabset-initialized"))
			return true; /* continue */

		// Store a marker indicating the tabset as initialized.		
		$(this).data("tabset-initialized", true);

		buildTabs.apply(this, []);
		applyTabBehaviors.apply(this, []);
		openFirstTabs.apply(this, []);
		reloadFrames.apply(this, []);

		openLocationHashTab();

		GetOriginalStrips(this);
	});

	// Work around issues with the Google visualization API rendering the column chart for
	// climate information into a dynamic iframe. The iframe's contents end up wiped when
	// the DOM containing the iframe is manipulated by the tab-generating script.

	// Wrap everything in a try-catch as the drawChart variable may be undeclared.
	try {
		// Assume this is the drawChart function we got from thirdparty code.
		if (drawChart) {
			function fixChart() {
				if (climateBarDrawn === true) // Is only set after the graph has been generated.
				{
					$("#show-weather-bar-chart iframe", document).remove();
					drawChart();
				}
				else {
					setTimeout(fixChart, 250);
				}
			}
			setTimeout(fixChart, 250);
		}
	}
	catch (e) {
	} 
}
// Must be global as DoRetrievePricesDaVinci is global and it needs to access this data...
var davinciData = null;
var priceCalcSiteVariation = 'jiba';

function DoRetrievePricesDaVinci(monthNumber, transportCode, lodgementCode) {


	window.OnRequestStart && window.OnRequestStart();

  // Set the monthfilter and transportfilter to an acceptable value for the webservice.	
	monthNumber = monthNumber || '';
	transportCode = transportCode || '';
	lodgementCode = lodgementCode || ''; 
	
	var lRequestData = JSON.stringify({	 
		accommodationId: davinciData.accomodationId,
		partyCompositionXml: davinciData.partyCompositionXml,
		monthFilter: monthNumber,
		transportFilter: transportCode,
		lodgementCode: lodgementCode
	});


	$.ajax({
		type: "POST",
		url: "/accommodation/WebServices/PriceTableService.asmx/GetPriceTableDaVinciSummerHtml",
		contentType: "application/json; charset=utf-8",
		data: lRequestData,
		dataType: "json",
		success: function(json) {
		window.OnRequestComplete && window.OnRequestComplete(davinciData.accomodationId, json.d);
		},
		error: function(ajaxRequest, errorMessage) {

		window.OnRequestError && window.OnRequestError(davinciData.accomodationId, errorMessage, ajaxRequest.responseText);

			/* PSEUDOCODE:
			if ('Http error code indicates unreachable service')
			{
			window.OnServiceUnavailable && window.OnServiceUnavailable();			
			}
			*/
		}
	});
}


$(document).ready(function() {
	davinciData = $("script[type=application/davinci-prices]").html();
	
	try
	{
		davinciData = JSON.parse(davinciData);
	}
	catch(e)
	{
		if (typeof (console) !== "undefined") { console.error("Error parsing data from <script type='application/davinci-prices'"); }
		davinciData = null;
	}
	
	davinciData && DoRetrievePricesDaVinci(davinciData.monthNumber, davinciData.transportCode, davinciData.lodgementCode);
});



function submitInfoUsefulFeedback(answer, ansnwerDetails, pageUrl, feedbackControlID) {


	var feedbackUrl = "https://nieuwsbrief.sunweb.nl/SSL/renderer/messagentHTTPS2.aspx?ID=eOgbwKneCAueeeW&FID=aanmelden&NUTTIG=" + answer +
		  "&MERK=" + siteVariationBrandCode + "&URL=" + escape(pageUrl) + "&OPMERKING=" + escape(ansnwerDetails);


	document.getElementById(feedbackControlID +"_frmInfoUsefulFeedback").src = feedbackUrl;


	var wizardStep1 = document.getElementById(feedbackControlID + "_infoUsefulFeedBackWizardStep1");
	var wizardStep2 = document.getElementById(feedbackControlID + "_infoUsefulFeedBackWizardStep2");

	closeInfoUsefulFeedbackDetails(feedbackControlID);
	
	wizardStep1.style.display = "none";
	wizardStep2.style.display = "inline";

}
function openInfoUsefulFeedbackDetails(feedbackControlID) {
	document.getElementById(feedbackControlID + "_infoUsefulFeedBackAnswerDetails").style.display = "inline";
	document.getElementById(feedbackControlID + "_infoUsefulFeedBackAnswerDetails").focus();
}

function closeInfoUsefulFeedbackDetails(feedbackControlID) {
	document.getElementById(feedbackControlID + "_infoUsefulFeedBackAnswerDetails").style.display = "none";
}
(function($) {

	$(document).ready(function() {

	if (typeof(topTestimonialsData) != "undefined" && topTestimonialsData != null) {
			$("#topTestimonialsList").setTemplateElement("testimonialsListTemplate");
			$("#topTestimonialsList").processTemplate(topTestimonialsData);

			if (moreTestimonialsAvailable) {

				var lAccoCode = $("input#hisAccoCode").val();

				$.ajax({
					type: "POST",
					url: "WebServices/TestimonialService.svc/GetData",
					contentType: "application/json; charset=utf-8",
					data: JSON.stringify({ "accoCode": lAccoCode }),
					dataType: "json",
					success: function(json) {
						$("#moreTestimonialsList").setTemplateElement("testimonialsListTemplate");
						$("#moreTestimonialsList").processTemplate(json.d);

					}
				});

			}
		}

	});

})(jQuery);




/**
 * ELabel.js 
 * This Javascript is provided by Mike Williams
 * Blackpool Community Church Javascript Team
 * http://www.commchurch.freeserve.co.uk/   
 * http://econym.googlepages.com/index.htm
 * This work is licenced under a Creative Commons Licence http://creativecommons.org/licenses/by/2.0/uk/
*/
/**
* @author Marco Alionso Ramirez, marco@onemarco.com
* @version 1.0
* The Tooltip class is an addon designed for the Google
* Maps GMraker class.
*/

function Tooltip(marker, content, padding) {
  this.marker = marker;
  this.content = content;
  this.padding = padding;
  this.div = null;
  this.map = null;
}

function InitializeTooltip() {
  Tooltip.prototype = new GOverlay();

  Tooltip.prototype.initialize = function(map) {

    this.div = document.createElement("div");
    var innerContainer = this.div.cloneNode(false);
    this.div.appendChild(innerContainer);
    this.div.style.position = 'absolute';
    this.div.style.visibility = 'hidden';
    innerContainer.className = 'googleTooltip';

    var child = typeof this.content == 'string' ?
		document.createTextNode(this.content) :
		this.content;
    innerContainer.appendChild(child);
    map.getPane(G_MAP_FLOAT_PANE).appendChild(this.div);
    //map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(this.shadow);
    this.map = map;
  }

  Tooltip.prototype.remove = function() {
    this.div.parentNode.removeChild(this.div);
  }

  Tooltip.prototype.copy = function() {
    var content = typeof this.content == 'string' ? this.content : this.content.cloneNode(true);
    return new Tooltip(this.marker, content, this.padding);
  }

  Tooltip.prototype.redraw = function(force) {
    if (!force) return;

    //draw tooltip
    var markerPos = this.map.fromLatLngToDivPixel(this.marker.getPoint());
    var iconAnchor = this.marker.getIcon().iconAnchor;
    var xPos = Math.round(markerPos.x - this.div.clientWidth / 2);
    var yPos = markerPos.y - iconAnchor.y - this.div.clientHeight - this.padding;
    this.div.style.top = yPos + 'px';
    this.div.style.left = xPos + 'px';
  }

  Tooltip.prototype.show = function() {
    this.div.style.visibility = 'visible';
  }

  Tooltip.prototype.hide = function() {
    this.div.style.visibility = 'hidden';
  }
}

function ELabel(point, html, classname, pixelOffset, percentOpacity, overlap)
{
  // Mandatory parameters
  this.point = point;
  this.html = html;

  // Optional parameters
  this.classname = classname || "";
  this.pixelOffset = pixelOffset || new GSize(0, 0);
  if (percentOpacity)
  {
    if (percentOpacity < 0) { percentOpacity = 0; }
    if (percentOpacity > 100) { percentOpacity = 100; }
  }
  this.percentOpacity = percentOpacity;
  this.overlap = overlap || false;
  this.hidden = false;
}

function InitializeELabel()
{
  ELabel.prototype = new GOverlay();

  ELabel.prototype.initialize = function(map)
  {
    var div = document.createElement("div");
    div.style.position = "absolute";
    div.innerHTML = '<div class="' + this.classname + '">' + this.html + '</div>';
    map.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(div);
    this.map_ = map;
    this.div_ = div;
    if (this.percentOpacity)
    {
      if (typeof (div.style.filter) == 'string') { div.style.filter = 'alpha(opacity:' + this.percentOpacity + ')'; }
      if (typeof (div.style.KHTMLOpacity) == 'string') { div.style.KHTMLOpacity = this.percentOpacity / 100; }
      if (typeof (div.style.MozOpacity) == 'string') { div.style.MozOpacity = this.percentOpacity / 100; }
      if (typeof (div.style.opacity) == 'string') { div.style.opacity = this.percentOpacity / 100; }
    }
    if (this.overlap)
    {
      var z = GOverlay.getZIndex(this.point.lat());
      this.div_.style.zIndex = z;
    }
    if (this.hidden)
    {
      this.hide();
    }
  };

  ELabel.prototype.getContentDiv = function()
  {
    return this.div_;
  };

  ELabel.prototype.remove = function()
  {
    this.div_.parentNode.removeChild(this.div_);
  };

  ELabel.prototype.copy = function()
  {
    return new ELabel(this.point, this.html, this.classname, this.pixelOffset, this.percentOpacity, this.overlap);
  };

  ELabel.prototype.redraw = function(force)
  {
    var p = this.map_.fromLatLngToDivPixel(this.point);
    var h = parseInt(this.div_.clientHeight, 10);
    this.div_.style.left = (p.x + this.pixelOffset.width) + "px";
    this.div_.style.top = (p.y + this.pixelOffset.height - h) + "px";
  };

  ELabel.prototype.show = function()
  {
    if (this.div_)
    {
      this.div_.style.display = "";
      this.redraw();
    }
    this.hidden = false;
  };

  ELabel.prototype.hide = function()
  {
    if (this.div_)
    {
      this.div_.style.display = "none";
    }
    this.hidden = true;
  };

  ELabel.prototype.isHidden = function()
  {
    return this.hidden;
  };

  ELabel.prototype.supportsHide = function()
  {
    return true;
  };

  ELabel.prototype.setContents = function(html)
  {
    this.html = html;
    this.div_.innerHTML = '<div class="' + this.classname + '">' + this.html + '</div>';
    this.redraw(true);
  };

  ELabel.prototype.setPoint = function(point)
  {
    this.point = point;
    if (this.overlap)
    {
      var z = GOverlay.getZIndex(this.point.lat());
      this.div_.style.zIndex = z;
    }
    this.redraw(true);
  };

  ELabel.prototype.setOpacity = function(percentOpacity)
  {
    if (percentOpacity)
    {
      if (percentOpacity < 0) { percentOpacity = 0; }
      if (percentOpacity > 100) { percentOpacity = 100; }
    }
    this.percentOpacity = percentOpacity;
    if (this.percentOpacity)
    {
      if (typeof (this.div_.style.filter) == 'string') { this.div_.style.filter = 'alpha(opacity:' + this.percentOpacity + ')'; }
      if (typeof (this.div_.style.KHTMLOpacity) == 'string') { this.div_.style.KHTMLOpacity = this.percentOpacity / 100; }
      if (typeof (this.div_.style.MozOpacity) == 'string') { this.div_.style.MozOpacity = this.percentOpacity / 100; }
      if (typeof (this.div_.style.opacity) == 'string') { this.div_.style.opacity = this.percentOpacity / 100; }
    }
  };

  ELabel.prototype.getPoint = function()
  {
    return this.point;
  };
  ELabel.prototype.U = function()
  {
    return this.point;
  };
  ELabel.prototype.V = function()
  {
    return this.point;
  };
  ELabel.prototype.W = function()
  {
    return this.point;
  };
  ELabel.prototype.X = function()
  {
    return this.point;
  };
  ELabel.prototype.Y = function()
  {
    return this.point;
  };
  ELabel.prototype.Z = function()
  {
    return this.point;
  };
}

//Exception handling
function NetMatchGoogleException(name, message)
{
  this.name = name;
  this.message = message;
}
NetMatchGoogleException.prototype.toString = function()
{
  return this.name + " : " + this.value;
};
function ManageException(e)
{
  var settings = read_settings();

  if (settings['targetControlId'] != '' && (settings['errorMessage'] != '' || e.name == 'BrowserException'))
  {
    var mapDiv = document.getElementById(settings['targetControlId']);
    //clear any child the target control might have
    var parent = mapDiv.parentNode;
    var i = 0;
    for (i = 0; i < parent.childNodes.length; i++)
    {
      if (parent.childNodes[i].id == settings['targetControlId']) 
	  {
		ApplyWidthAndHeight(parent.childNodes[i].style, 0, 0);
	  }
      else
      {
        parent.removeChild(parent.childNodes[i]);
      }
    }
    //add the error paragraph
    var errorParagraph = document.createElement('p');
    parent.appendChild(errorParagraph);

    //mapDiv.style.display = 'none';
    ApplyWidthAndHeight(mapDiv.style, 0, 0);
    
    document.getElementById('errorField').value = e.name + '<br />' + e.value;

    if (e.name != 'BrowserException')
      errorParagraph.innerHTML = settings['errorMessage'];
    else
      errorParagraph.innerHTML = e.message;
  }
}
function read_secondaryMarkers(markersValue)
{
  var aResult;
  if (markersValue !== '')
  {
    //the input is formated like : (23,12 ^ 31,49) (51,01 ^ 14,37) 
    var i = 0;
    var matches = 0;
    //find out if there are more than 1 pairs of (latitude, longitude) coordinates
    for (i = 0; i < markersValue.length; i++)
    {
      if (markersValue.charAt(i) == '(')
      {
        matches++;
        //more than 1 pair found so we can break
        if (matches > 1)
        {
          break;
        }
      }
    }

    var latitude, longitude, id;

    // an array result having as key an index and the value a (latitude, longitude) pair.
    // eg. aResult[1,0] = latitude0;
    //     aResult[1,1] = longitude0;
    var mSplit

    //if there is exactly 1 pair
    if (matches == 1)
    {
      aResult = new Array(1);
      aResult[0] = new Array(4);

      mSplit = markersValue.split('^');

      //the latitude will look something like (23,12^34,19^name^id) so we have to remove the '(' and the ')'
      latitude = mSplit[0];
      latitude = parseFloat(latitude.substring(1, latitude.length).replace(',', '.'));
      aResult[0][0] = latitude;

      longitude = mSplit[1];
      longitude = parseFloat(longitude.replace(',', '.'));
      aResult[0][1] = longitude;

      aResult[0][2] = mSplit[2];

      id = mSplit[3];
      id = parseInt(id.substring(0, id.length - 1, 10));
      aResult[0][3] = id;
    }
    else		//there are at least 2 coordinates pairs :   (11,32 : 14:56)(19,76 : 41,59)(23,14 : 19:51)
    {
      var markers = markersValue.split(')(');
      aResult = new Array(markers.length);

      mSplit = markers[0].split('^');
      aResult[0] = new Array(4);
      //clean the first result as above : (11,32 ^ 145,6 ^ 12
      latitude = mSplit[0];
      latitude = parseFloat(latitude.substring(1, latitude.length).replace(',', '.'), 10);
      aResult[0][0] = latitude;
      aResult[0][1] = parseFloat(mSplit[1]); 		//the longitude
      aResult[0][2] = mSplit[2];                      //the name
      aResult[0][3] = parseInt(mSplit[3]); 		//the id of the acco/dest/region

      //clean the last result as above : 11,32 ^ 145,6 ^ 12)
      aResult[1] = new Array(4);
      mSplit = markers[markers.length - 1].split('^');
      aResult[1][0] = parseFloat(mSplit[0]); 	//latitude
      longitude = mSplit[1]; 					//longitude
      longitude = parseFloat(longitude.replace(',', '.'));
      aResult[1][1] = longitude;
      aResult[1][2] = mSplit[2];
      aResult[1][3] = parseInt(mSplit[3], 10); 	//the id of the acco/dest/region

      //create the other coordinate pairs, from the second to the last but one coordinate pairs
      i = parseInt(i);
      for (i = 1; i < markers.length - 1; i++)
      {
        mSplit = markers[i].split('^');
        aResult[i + 1] = new Array(4);
        //the latitude
        aResult[i + 1][0] = parseFloat(mSplit[0]);
        //the longitude
        aResult[i + 1][1] = parseFloat(mSplit[1]);
        //the name 
        aResult[i + 1][2] = mSplit[2];
        //the id
        aResult[i + 1][3] = parseInt(mSplit[3]);
      }
    }
  }

  return aResult;
}

function read_settings()
{
  var settings = document.getElementById('settingsDiv');

  //get the value of the settings hidden field 
  if (settings !== undefined)
  {
    //for IE
    var sttngs = settings.childNodes[0].value;
    if (sttngs == undefined)
    {
      //for non-IE
      settings = settings.childNodes[1].value;
    }
    else
    {
      settings = sttngs;
    }
  }
  //the settings
  var geoSettings;

  if (settings != undefined)
  {
    geoSettings = settings.split(';');
  }

  //create a dictionary like structure for the settings
  //dSettings["latitude"] = 91,1231
  //the incrementation goes till length - 1 because the split creates an extra null element at the end of the array
  var i = 0;
  var dSettings = new Array(geoSettings.length);
  for (i = 0; i < geoSettings.length; i++)
  {
    var key = geoSettings[i].split(':')[0];
    var value = geoSettings[i].split(':')[1];

    if (key != 'secondaryMarkers')
    {
      dSettings[key] = value;
    }
    else
    {
      dSettings[key] = read_secondaryMarkers(value);
    }

    if (key == 'latitude' || key == 'longitude')
    {
      dSettings[key] = parseFloat(value.replace(',', '.'), 10);
    }
    if (key == 'level' || key == 'entityId')
    {
      dSettings[key] = parseInt(value, 10);
    }
    if (key == 'OneEntityOnGoogleMapZoomLevel') {
		dSettings[key] = parseInt(value, 10);
    }
  }
    return dSettings;
  }
  
function failedCallback(e)
{
  ManageException(e);
}

function CreateTabs(marker, id, level) {
	$.ajax({
		type: "POST",
		url: "/googleMaps/Service/GoogleMapHelperService.asmx/GetTabInfo",
		contentType: "application/json; charset=utf-8",
		data: JSON.stringify({ id: id, level: level }),
		dataType: "json",
		success: function(json) {
			var info = json.d.split("/**/");

			if (info[0].length + info[1].length > 0) {





				var detailsDiv = ['<div id="detailsDivTab" class="googleDetailsDiv">', info[0], '</div>'].join('');
				var photosDiv = ['<div id="pictureDivTab" class="googlePictureDiv">', info[1], '</div>'].join('');

				var tabs = [
					new GInfoWindowTab('Details', detailsDiv),
					new GInfoWindowTab('Fotos', photosDiv)
				];

				marker.openInfoWindowTabsHtml(tabs);
			}
		},
		error: function(xhr, status, error) {
			// Pull the JSON-serialized exception from the responseText manually.
			var err = JSON.parse(xhr.responseText);
			err && failedCallback(err);

			throw new NetMatchGoogleException('Service exception', '');
		}
	});     

}

function CreateSimpleMarker(latitude, longitude, id, level, map, name)
{
  //single click -> display	additional information
  var marker = new GMarker(new GLatLng(latitude, longitude));
  GEvent.addListener(marker, 'click', function() { CreateTabs(marker, id, level); }, failedCallback);
  
  var tooltip = new Tooltip(marker, name, 4);
  marker.tooltip = tooltip;  
  map.addOverlay(tooltip);
  GEvent.addListener(marker, 'mouseover', function() {    
    this.tooltip.show();
  });
  GEvent.addListener(marker, 'mouseout', function() {
    this.tooltip.hide();
  });
  
  map.addOverlay(marker);

  return marker;
}

function GetPath(markerData, level)
{
  var path = window.location.pathname;

  if (level == 3)
      path = path.replace('/region/', '/destination/');

  return window.location.protocol + '//' + window.location.host + path + '?id=' + markerData[3] + '#map';
}
function CreateRegionMarkers(map, settings)
{
  var i = 0;
  var secMarkers = settings['secondaryMarkers'];

  if (secMarkers != undefined)
  {
    for (i = 0; i < secMarkers.length; i++)
    {
      var content = '<nobr><a href="' + GetPath(secMarkers[i], settings['level']) + '">' + secMarkers[i][2] + '</a></nobr>';

      var marker = new ELabel(new GLatLng(secMarkers[i][0], secMarkers[i][1]), content, 'contentMarker');
      map.addOverlay(marker);
    }
  }
}

function CreateAccommodationMarker(map, settings) {
  var marker = CreateSimpleMarker(settings['latitude'], settings['longitude'], settings['entityId'], 1, map, settings['entityName']);
  CreateTabs(marker, settings['entityId'], settings['level']);
}

function CreateDestinationMarkers(map, settings)
{
  var i = 0;

  var secMarkers = settings['secondaryMarkers'];
  if (secMarkers != undefined)
  {
		// bounds used to determine the best zoom level and map center
		var bounds = new GLatLngBounds();
		
    for (i = 0; i < secMarkers.length; i++) {
      var marker = CreateSimpleMarker(secMarkers[i][0], secMarkers[i][1], secMarkers[i][3], 2, map, secMarkers[i][2]);
      bounds.extend(marker.getPoint());
    }
    // best fit the zoom level so that all accommodations to be visible on the map.
    bestFit(map, bounds);
  }
}

// this function adds markers to the provided coordinates              
// map - is a reference to a GoogleMap object
// coordinates - is an Array with elements like : (coordinates[1][0], coordinates[1][1]) corresponding to the latitude & longitude        
function add_markers(map, settings)
{
  switch (settings['level'])
  {
    case 1: CreateAccommodationMarker(map, settings); break;
    case 2: CreateDestinationMarkers(map, settings); break;
    case 3: CreateRegionMarkers(map, settings); break;
  }
}
//this function is used to open a link to accommodation-page, from the infotabs's links to accommodations
//in case that we are on the accommodation page (level 1), just the tab is changed to 'pricetable'
function openLinkToPricetableOrPhotos(href, showPhotos, photoUrl)
{
  var settings = read_settings();
  switch (settings['level'])
  {
    case 1: 
       if (showPhotos)
       {
         NewWindow(photoUrl, null , 'toolbar=no,menubar=no,location=no,directories=no,status=no,scrollbars=no,resizable=no,copyhistory=no,width=756,height=485'); 
         return false;
         break;
       }
       else
       {
        openTab('pricetable'); return false; break;
       }
       break;
    case 2: location.href = href; break;
  }  
}

function ApplyWidthAndHeight(divStyle, width, height)
{
  //IE
  divStyle.width = width;
  //non-IE
  if (divStyle.width == '')
  {
    divStyle.width = width + 'px';
  }
  //IE
  divStyle.height = height;
  //non-IE
  if (divStyle.height == '')
  {
    divStyle.height = height + 'px';
  }
}
function setTitle(settings) {  
  var title = document.getElementById('googleMapTitle');
  var map = document.getElementById(settings['targetControlId']);
  title.parentNode.removeChild(title);
  map.parentNode.insertBefore(title, map);
}
// Call this function when the page has been loaded  
function initialize() {
	InitializeELabel();
  InitializeTooltip();  
  var settings = null;
  try {
  	settings = read_settings();  	
    var d1 = undefined;
    var d2 = '';

    if (settings.length > 0 && GBrowserIsCompatible()) {
      ApplyWidthAndHeight(document.getElementById(settings['targetControlId']).style, parseInt(settings['width']), parseInt(settings['height']));

      //get the latitude and the longitude 
      var latitude = settings['latitude'];
      var longitude = settings['longitude'];

      if (latitude < -90 || longitude < -180 || latitude > 90 || longitude > 180)
      {
        throw new NetMatchGoogleException('CoordinatesException', 'The latitude and/or the longitude are empty.');
      }

      var target = document.getElementById(settings["targetControlId"]);
      target.tip = '';
      target.parentNode.parentNode.title = '';
      var map = new GMap2(target);

      setZoomLevel(map, settings); 
      
      map.addControl(new GLargeMapControl());
      map.addControl(new GMapTypeControl());
      if (settings['showOvervieMap'] == 'True')
        map.addControl(new GOverviewMapControl(), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0, 0)));

      map.disableContinuousZoom();
      map.disableDoubleClickZoom();

      //add markers
      add_markers(map, settings);
			
      ShowTitle();

      setTitle(settings);

      //if the destination has coordinates, but its accommodation don't, set the zoom level to the standard zoom level
      if (map.getZoom() == 0)
      	setZoomLevel(map, settings);
    }
    else
    {
      //if your browser is not capable of handling the google framework
      throw new NetMatchGoogleException('BrowserException', 'Your browser is not able to render the content of this page.');
    }

    //clear any memory leaks
    $(window).unload(function() { GUnload() }); ;
  }
  catch (e)
  {
    ManageException(e);
  }
}

// best fit the zoom level and the center for the bounds
function bestFit(map, bounds) {
	// maximum zoom level accepted
	var maxZoomLevel = 13; 
	
	// get calculated zoom.
	var zoom = map.getBoundsZoomLevel(bounds);
	
	// if calculated zoom is greater than maximum zoom level accepted reset the zoom
	// to maximum level accepted
	//zoom = zoom > maxZoomLevel ? maxZoomLevel : zoom;
   map.setZoom(zoom);
   map.setCenter(bounds.getCenter());
}

//Set a zoom level to the map.
function setZoomLevel(map, settings) {
	// The accommodation level (1) should have a higher zoom level
	// If there is only one marker to be displayed, also increase the zoom level.
	if (settings['level'] == 1 ||
 			(settings['secondaryMarkers'] != undefined && settings['secondaryMarkers'].length == 1))
		standardHighZoom(map, settings);
	else
		map.setCenter(new GLatLng(settings['latitude'], settings['longitude']), parseInt(settings['zoom'], 10));
}

// If there is a single marker on the map, the ZoomLevel will be taken from a config value.
 function standardHighZoom(map, settings) {
 	map.setCenter(new GLatLng(settings['latitude'], settings['longitude']), settings['OneEntityOnGoogleMapZoomLevel']);
 }
function addEvent(obj, evType, fn) {
  if (obj.addEventListener) {
    obj.addEventListener(evType, fn, false);
    return true;
  }
  else if (obj.attachEvent) {
    return obj.attachEvent("on" + evType, fn);
  } else {
    return false;
  }
}
function ShowTitle() {
  var div = document.getElementById('googleMapTitle');
  div.style.visibility = 'visible';
  div.style.display = 'block';
}
function LoadGoogleMapScript() {
  
  var key = document.getElementById('key').value;
  var script = document.createElement('script');
  var path = "http://maps.google.com/maps?file=api&v=2.x&key=" + key + "&c&async=2&callback=initialize&hl=nl";
  script.setAttribute('src', path);
  script.setAttribute('type', 'text/javascript');
  document.documentElement.firstChild.appendChild(script);
  script = document.createElement('script');
}
function GetSourceControlId() {
	return "map";
}
function AttachToControl() {
  var sourceControlId = GetSourceControlId();
  if (window.location.href.indexOf('#map') > -1) {
    LoadGoogleMapScript();
  }
  else {
    var obj = document.getElementById(sourceControlId);
    if (obj != undefined)
      addEvent(obj, 'click', LoadGoogleMapScript);
  }
}
// Handles the keypress in the textbox.
function KeyHandler(e) 
{
    if (navigator.appName == 'Netscape')
    {
        if (e.which == 13)
        {
            e.cancelBubble = true;
            e.returnValue = false;
            RedirectToSearch();
            if (e.stopPropagation)
            { e.stopPropagation();}
            if (e.cancelable)
            {
            e.preventDefault();
            }
      }
    }
    else
    {
        if (window.event.keyCode == 13)
        {
            window.event.cancelBubble = true;
            window.event.returnValue = false;
            RedirectToSearch();
        }
    }
}


function RedirectToSearch()
{
	var searchPage;
	var relPath = _DimSearchPage;
	var lSearchTerm = document.getElementById('SearchTerm').value;
	
	// Variables for use when search term == default search term
	var lDefaultSearchTerm = _DefaultTextSearchTerm;
	var lDimSearchPageDefaultSearched = _DimSearchPageDefaultSearched;
	var lSearchPageDefaultSearched;

  //if a page has a relative path to itself
  if (relPath == "")
  {
    var location = window.location.href;
    location = location.substring(location.lastIndexOf('/')+1);
    if(location.indexOf('?') >=0)
    {
      location = location.substring(0,location.indexOf('?'));
    }
    
    relPath = location; 
  }
  
  // if a page has a relative path to itself (DefaultString used)
  if (lDimSearchPageDefaultSearched == "" && lSearchTerm == lDefaultSearchTerm)
  {
    var location2 = window.location.href;
    location2 = location2.substring(location2.lastIndexOf('/')+1);
    if(location2.indexOf('?') >=0)
    {
      location2 = location2.substring(0,location2.indexOf('?'));
    }
    
    lDimSearchPageDefaultSearched = location2;
  }
  
  if (document.getElementById('baseUrl'))
  {
    searchPage = document.getElementById('baseUrl').href;
  }
  else
  {
    searchPage = window.location.href;
  }

	searchPage = searchPage.substring(0, searchPage.lastIndexOf('/'));
	while (relPath.indexOf('../') >= 0)
	{
	searchPage = searchPage.substring(0, searchPage.lastIndexOf('/'));
	relPath = relPath.substring(relPath.indexOf('../') + 3);
	}
	
	// The url contains an ../. Check if this has to be deleted.
	while (lDimSearchPageDefaultSearched.indexOf('../') >= 0)
	{	
		lDimSearchPageDefaultSearched = lDimSearchPageDefaultSearched.substring(lDimSearchPageDefaultSearched.indexOf('../') + 3);
	}
	
	// Copy the searchpage variable
	lSearchPageDefaultSearched = searchPage;
	
	searchPage = searchPage + '/' + relPath;

	if(lSearchTerm != null && lSearchTerm != '' && lSearchTerm != lDefaultSearchTerm)
    window.location.href = searchPage + '?N=0&search=' + lSearchTerm;
  
  // When default search term, redirect to another page.
  if (lSearchTerm == lDefaultSearchTerm)
  {
		window.location.href = lSearchPageDefaultSearched + '/' + lDimSearchPageDefaultSearched + '?search=' + lSearchTerm;
  }
}
