
// Content: js framesizer
// Content: js framesizer
/////////////////////////////////////////////////////////////////////////////////////////
//	ADD ANY IFRAME ID OF IFRAMES WHICH NEED RESIZING TO THIS ARRAY, IDS SHOULD BE BETWEEN
//	QUOTES AND BE COMMA SEPARATED
//
//	NOTE: IF YOU WANT TO ADD NEW IFRAMES AFTER PAGE LOAD DO NOT ADD TO THIS ARRAY, USE 
//				IFRAMEMANAGER.ADD METHOD INSTEAD
//
/////////////////////////////////////////////////////////////////////////////////////////
var IFRAME_IDS = new Array("extFrame");

// When this variable is set to 'true' any statements like:
//
//     Logger.WriteLine("<string message>", ["#<RGB value>"], [<integer font size>]);
// 
// will show up in a single popup window.
//
var ENABLE_LOGGING = false;

/////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC CLASS IFRAME
//
//  ARGUMENTS 
//		o: Object (IFrame element) or string (IFrame element ID)
//
//	RETURNS
//		new IFrame instance
//
/////////////////////////////////////////////////////////////////////////////////////////
function IFrame(o) {
	//
	// MEMBER VARIABLES
	//
	var defaultHeight = 3600;
	var minHeight = Browser.IsFireFox && Browser.MinorVersion >= 0.1 ? 16 : (!Browser.IsSafari && !Browser.IsIE ? 10 : 0);

	this.GetID = function() { return o.id; }
	this.SetUri = function(uri) { o.src = uri; }
	
	//
	// SETDEFAULTHEIGHT: Sets the height used for the IFrame when its document is inaccessible
	//                   or when it is removed from the IFrameManager's IFrames collection.
	//
	//  ARGUMENTS 
	//		value: Integer
	//
	//	RETURNS
	//		No return value
	//	
	this.SetDefaultHeight = function(value) { defaultHeight = value; }
	
	//
	// GETDEFAULTHEIGHT: Returns the height for the IFrame used in case it is inaccessible or 
	//                   removed from the IFrameManager collection. The value is either 3600 (=default) 
	//                   or the value from Tridion set in the application's configuration component
	//
	//  ARGUMENTS 
	//		No arguments
	//	
	//	RETURNS
	//		Integer representing the DefaultHeight
	//		
	this.GetDefaultHeight = function() { return defaultHeight; }
	
	//
	// APPLYDEFAULTHEIGHT: Sets the IFrame's height back to the specified default height
	//
	//  ARGUMENTS 
	//		No arguments
	//	
	//	RETURNS
	//		No return value
	//			
	this.ApplyDefaultHeight = function() { this.SetHeight(this.GetDefaultHeight()); }	
	
	//
	// SETMINHEIGHT: Sets the minumum height for the IFrame. If this value is set and the
	//               calculated height is less than this value the this.GetHeight() method
	//               will return the value set here
	//
	//  ARGUMENTS 
	//		value: Integer
	//
	//	RETURNS
	//		No return value
	//	
	this.SetMinHeight = function(value) { minHeight = value; }
	
	//
	// GETMINHEIGHT: Returns if set the minumum height, else null
	//
	//  ARGUMENTS 
	//		No arguments
	//	
	//	RETURNS
	//		Integer representing the minimum height of the IFrame
	//	
	this.GetMinHeight = function() { return minHeight; }

	//
	// SETHEIGHT: Sets the height of the IFrame
	//
	//  ARGUMENTS 
	//		value: Integer
	//
	//	RETURNS
	//		No return value
	//	
	this.SetHeight = function(value) {
		o.height = value;
	}

	//
	// GETHEIGHT: Gets the height of this IFrame's document
	//
	//  ARGUMENTS 
	//		No arguments
	//	
	//	RETURNS
	//		Integer representing the height of the IFrame's document. If a minimum height is set and
	//    the height of the document is less than this value the minimum height is returned. In case
	//    the IFrame's document is not accessible the default height will be returned
	//
	//  NOTES
	//	  To overwrite this function with a custom function use: 
	//
	//         		IFrameManager.IFrames(id).GetHeight = function() { <custom code here> }
	//
	//    When using custom code the default code will not be executed any longer, unless the custom 
	//    code is implemented like:
	//
	//				    var base = IFrameManager.IFrames(<id>).GetHeight;
	//				    IFrameManager.IFrames(<id>).GetHeight = function() { base(); <custom code>; }
	//
	//  BUG REPORT
	//
	//  	Known bugs for EBT & MMB are caused by the HTML/JavaScript in the applications themselves
	//
	this.GetHeight = function() {
		var height = 0;
		try {
			if (Browser.IsOpera) {					
				iframeDoc = window.frames[DOMElement.id].document;
			}
			else if ( o.contentDocument ) {
				iframeDoc = o.contentDocument;
			}
			else if ( o.contentWindow.document ) {
				iframeDoc = o.contentWindow.document;
			}
			else {
				iframeDoc = o.document;
			}

			//
			// Opera
			//
			if (Browser.IsOpera) {
				height = document.defaultView.getComputedStyle(iframeDoc.body,null).getPropertyValue("height");
			}
			//
			// Firefox
			//
			else if (Browser.IsFirefox) {
				height = iframeDoc.documentElement.offsetHeight;
				var h_default = this.GetDefaultHeight();
				var h_current = o.height;
				var h_doc_offset = iframeDoc.body.parentNode.offsetHeight;
				var h_doc_scroll = iframeDoc.body.parentNode.scrollHeight;
				var h_doc_body_scroll = iframeDoc.body.scrollHeight;
					
				if (h_doc_scroll == h_doc_body_scroll)
					height = h_doc_body_scroll;
				else {
					height = h_doc_offset != h_default ? h_doc_offset : (h_current != h_default ? h_doc_offset : height);
					height = h_doc_scroll > height && h_doc_scroll != h_default ? h_doc_scroll : height;
					height = h_doc_body_scroll > height && h_doc_body_scroll != h_default ? h_doc_body_scroll : height 
				}
			}
			//
			// Safari
			//
			else if (Browser.IsSafari) {
				height = o.contentDocument.documentElement.scrollHeight;
			}
			//
			// Internet Explorer 
			//
			else if (Browser.IsIE) {
				//
				// 5.x and older
				//
				// NOTE: Known issues: After expanding, collapsing does not cause size to re-adjust, this is by choice because when fixed, 
				//       fares selection is no longer possible when fares menu is longer than content, which would make booking impossible.
				//       This problem can only be resolved after when EBT fixes their HTML/JavaScript.
				//
				if (Browser.MajorVersion <= 5) {
					var h_current = o.height;
					var h_default = this.GetDefaultHeight();
					var h_doc_offset = iframeDoc.body.parentNode.offsetHeight;
					var h_doc_body_offset = iframeDoc.body.offsetHeight;
					var h_doc_body_scroll = iframeDoc.body.scrollHeight;

					height = h_doc_body_offset > h_doc_body_scroll && h_doc_body_offset != h_default ? h_doc_body_offset : h_doc_body_scroll;
				}
				//
				// 6.x
				//
				// NOTE: Currently no problems, but when EBT fixes their HTML/JavaScript this code needs to be 
				//       changed to standard implementation
				//				
				else if (Browser.MajorVersion <= 6) {
					var h_default = this.GetDefaultHeight();
					var h_current = o.height;
					var h_doc_offset = iframeDoc.body.parentNode.offsetHeight;
					var h_doc_scroll = iframeDoc.body.parentNode.scrollHeight;
					var h_doc_body_scroll = iframeDoc.body.scrollHeight;
					
					if (h_doc_scroll == h_doc_body_scroll)
						height = h_doc_body_scroll;
					else {
							height = h_doc_offset != h_default ? h_doc_offset : (h_current != h_default ? h_doc_offset : height);
							height = h_doc_scroll > height && h_doc_scroll != h_default ? h_doc_scroll : height;
							height = h_doc_body_scroll > height && h_doc_body_scroll != h_default ? h_doc_body_scroll : height;
					}					
				}
				//
				// 7 and later
				//
				else {
					height = iframeDoc.body.scrollHeight + 20;
				}
			}
			//
			// Other browsers
			//
			else {
				height = iframeDoc.body.scrollHeight > iframeDoc.body.offsetHeight ? iframeDoc.body.scrollHeight : iframeDoc.body.offsetHeight;
			}
		} 
		catch (e) {
			// No access to iframe document or unsupported browser, try again later (100ms), for now use fallbackHeight
			height = this.GetDefaultHeight();
			if ( this.GetMinHeight() != null ) {
				if ( this.GetMinHeight() > height ) {
					height = this.GetMinHeight();
				}
			}
		}
		return height;	
	}

	//
	// RESIZE: Resizes this IFrame to match the height of its document 
	//
	//  ARGUMENTS 
	//		No arguments
	//	
	//	RETURNS
	//		No return value
	//	
	this.Resize = function() {
		var height = this.GetHeight();
		
		// If a minimum height has been set and the height is less than this minimum height apply the minimum height
		if (this.GetMinHeight() && height <= this.GetMinHeight())
			height = this.GetMinHeight();
		
		// If height equals 0 apply default height
		if (height == 0)
			this.ApplyDefaultHeight();
		else
			this.SetHeight(height);
	}

	//
	// CONSTRUCTOR: Checks if a valid DOM element (IFRAME) or a valid ID (string) to such an element was provided. 
	//              And sets any initial values for IFrame its members
	//
			
	// Make sure argument is valid DOM element. Argument is either valid IFRAME or element belonging to provided ID string is valid IFRAME
	o = IsIFrameElement(o) ? o : (!IsNull(o) && IsString(o) ? document.getElementById(o) : null);		
	if (!o) {
		throw("IFrame.Constructor: Missing or invalid argument <o>. Allowed types are a valid iframe (DOM element) or a valid iframe element id (string)");
		return;
	}
	
	// On creation the height defined on IFRAME equals any value set in the application's configuration component in Tridion
	this.SetDefaultHeight( (o.height > 0 ? o.height : this.GetDefaultHeight()) );
}

/////////////////////////////////////////////////////////////////////////////////////////
//	PUBLIC CLASS IFrameManager (Singleton)
//
//  This class can manage a collection of IFrames and perform actions, like resizing, on
//  any IFrame instances in its collection. It is instanced when library is included and 
//  can not be instanced again after
//
//	ARGUMENTS
//		none
//
//	RETURNS
//		IFrameManager containing IFrame instances for all IDs specified 
//		in the IFRAME_IDS array, it can be accessed through 'IFrameManager' variable
//		
/////////////////////////////////////////////////////////////////////////////////////////
var IFrameManager = new function() {
	//
	// MEMBER VARIABLES
	//
	var iframes	= new Array();		// ordered list of IFrames
	var indices = new Object();		// unordered 'list' matching IDs to IFrame indices in the list of IFrames
		
	//
	// ADD: Adds an IFrame to the collection
	//
	//  ARGUMENTS 
	//		value:  either a valid DOM element (IFRAME) or a valid ID (string) to such an element
	//
	//	RETURNS
	//		No return value
	//	
	this.Add = function(o)	{
		// Make sure argument is valid DOM element. Argument is either valid IFRAME or element belonging to provided ID string is valid IFRAME		
		o = IsIFrameElement(o) ? o : (!IsNull(o) && IsString(o) ? (document.getElementById ? document.getElementById(o) : document.all[o]) : null);
		if (!IsIFrameElement(o)) return;
		if (!this.Contains(o.id)) {
			indices[o.id] = iframes.length;
			iframes[iframes.length] = new IFrame(o);
		}
		else {
			throw("IFrameManager.Add(): IFrame <"+o.id+"> already exists. Duplicates are not allowed.");
		}
	}
	
	//
	// REMOVE: Removes an IFrame from the collection
	//         Before removal the DOM IFRAME's height is set back to its default height
	//
	//  ARGUMENTS 
	//		value:  either a valid DOM element (IFRAME) or a valid ID (string) to such an element
	//
	//	RETURNS
	//		No return value
	//	
	this.Remove = function(o) {
		// Make sure argument is valid DOM element. Argument is either valid IFRAME or element belonging to provided ID string is valid IFRAME
		o = IsIFrameElement(o) ? o : (!IsNull(o) && IsString(o) ? (document.getElementById ? document.getElementById(o) : document.all[o]) : null);		
		if (!IsIFrameElement(o) || !this.Contains(o.id)) return;
		
		// Restore DOM IFRAME to original height
		iframes[indices[o.id]].ApplyDefaultHeight();	
		
		// Delete the IFrame instance to prevent memory leaks
		delete iframes[indices[o.id]];
		
		// Move each following IFrame instance
		for (var i=indices[o.id]+1; i<iframes.length; i++) {
			iframes[i-1] = iframes[i];            // Copy current IFrame one place back in the iframes array
			indices[iframes[i].GetID()] = i-1;    // Adjust index belonging to current IFrame to reflect new position
			delete iframes[i];                    // Remove the current IFrame from its previous position
		}
		iframes.length--;                       // One IFrame was removed so reduce the array size by 1
		delete indices[o.id];                   // Clear the removed IFrame's index in indices object
	}
	
	//
	// REMOVEALL: Removes all IFrames from the collection
  //            Before removal each DOM IFRAME's height is set back to its default height	
	//
	//  ARGUMENTS 
	//		No arguments
	//
	//	RETURNS
	//		No return value
	//		
	this.RemoveAll = function() {
		for (var i=0; i<iframes.length; i++) {
			iframes[i].ApplyDefaultHeight();      // Restore DOM IFRAME to original height
			delete iframes[i];                    // Remove the current IFrame instance from the collection
		}
		iframes.length = 0;                     // All IFrame instances have been removed, reset the array by setting its length to 0
		delete indices;                         // All indices can be discarded, sicne there are no IFrame instances any longer
		indices = new Object();                 // Create new empty indices object
	}

  //
	// GETIFRAMECOUNT: Gets the number of IFrame instances in the collection
	//
	//  ARGUMENTS 
	//		No arguments
	//
	//	RETURNS
	//		Integer representing the number of IFrame instances in the IFrames collection
	//	
	this.GetIFrameCount = function() {
		return iframes.length;
	}
	
	//
	// CONTAINS: Checks if an IFrame is present in the collection
	//
	//  ARGUMENTS 
	//		String representing the ID of the IFrame for which to check
	//
	//	RETURNS
	//		Boolean, true if the IFrame is present, false if not
	//		
	this.Contains = function(id) { return !IsNull(indices[id]); }
	
	//
	// IFRAMES: Returns an IFrame from the collection if it exists, else returns null
	//
	//  ARGUMENTS 
	//		String representing the ID of the IFrame which to get
	//
	//	RETURNS
	//		The requested IFrame instance if it exists, null if it does not exist
	//	
	this.IFrames = function(id) {
		if (!this.Contains(id)) return null;
		else return iframes[indices[id]];		
	}

	//
	// RESIZEALL: Loops over the IFrames in the collection and resizes each one of them
	//
	//  ARGUMENTS 
	//		No arguments
	//
	//	RETURNS
	//		No return value
	//	
	this.ResizeAll = function() {
		for (var i=0; i<iframes.length; i++)
			iframes[i].Resize();
	}

	//
	// CONSTRUCTOR: This code makes sure that the IFrameManager will be initialized before any 
	//              calls are made to it, it uses the global array at the top of this file to
	//              determine which IFrame elements should be added to its collection
	//
	var original_window_onload = function() { return; }
	if (window.onload)
		original_window_onload = window.onload;
		
	addEventHandler(window, "load", 
		function() {
			if (!IsNull(IFRAME_IDS) && IFRAME_IDS.length && IFRAME_IDS.length != 0) {
				for (var i=0; i<IFRAME_IDS.length; i++)
					IFrameManager.Add(IFRAME_IDS[i]);	
			}
			original_window_onload();
		}
	);
}

/////////////////////////////////////////////////////////////////////////////////////////
//	HELPER FUNCTIONS & OBJECTS
/////////////////////////////////////////////////////////////////////////////////////////
function IsNull(o) { return (o == null || o == 'undefined'); }
function IsString(o) { return (typeof(o) == 'string'); }
function IsIFrameElement(o) { 
	try {
		return (typeof(o) == 'object' && o.tagName == 'IFRAME'); 
	} 
	catch(e) { 
		return false;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
//	PUBLIC HELPER CLASS BROWSER (Singleton)
//
//  This class provides various browser settings as used be the client and is instanced 
//  when library is included and can not be instanced again after
//
//	ARGUMENTS
//		none
//
//	RETURNS
//		Browser instance which can be queried through its public properties and is 
//    accessible through 'Browser' variable 
//		
/////////////////////////////////////////////////////////////////////////////////////////
var Browser = new function() {
   var UserAgent       = navigator.userAgent.toLowerCase();
   var AppVersion      = navigator.appVersion.toLowerCase();
      
   this.IsMac          = (UserAgent.indexOf("mac")!=-1);
   
   this.IsOpera        = UserAgent.indexOf("opera") != -1;
   this.IsSafari       = UserAgent.indexOf('safari') != -1;
   this.IsIE           = AppVersion.indexOf('msie') != -1 ? (this.IsMac ? UserAgent.indexOf('msie') != -1 : AppVersion.indexOf('msie') != -1) : false;
   this.IsKonqueror    = UserAgent.indexOf('konqueror') != -1;
   this.IsKHTML        = this.IsSafari || this.IsKonqueror;
   this.IsGecko        = !this.IsKHTML && navigator.product && navigator.product.toLowerCase()=="gecko";
   this.IsFirefox      = UserAgent.indexOf('firefox') != -1 &&
                         UserAgent.indexOf('mozilla/5') != -1 && 
                         UserAgent.indexOf('spoofer') == -1 && 
                         UserAgent.indexOf('compatible') == -1 && 
                         UserAgent.indexOf('webtv') == -1 && 
                         UserAgent.indexOf('hotjava') == -1 && 
                         !this.IsOpera && 
                         this.IsGecko;                                 
   this.IsMozilla      = (navigator.vendor == "" || navigator.vendor == "Mozilla" || navigator.vendor == "Debian") &&
                         UserAgent.indexOf('mozilla/5') != -1 && 
                         UserAgent.indexOf('spoofer') == -1 && 
                         UserAgent.indexOf('compatible') == -1 && 
                         UserAgent.indexOf('webtv') == -1 && 
                         UserAgent.indexOf('hotjava') == -1 && 
                         !this.IsOpera && 
                         this.IsGecko;                                 
   this.IsFirebird     = navigator.vendor == "Firebird" &&
                         UserAgent.indexOf('mozilla/5') != -1 && 
                         UserAgent.indexOf('spoofer') == -1 && 
                         UserAgent.indexOf('compatible') == -1 && 
                         UserAgent.indexOf('webtv') == -1 && 
                         UserAgent.indexOf('hotjava') == -1 && 
                         !this.IsOpera && 
                         this.IsGecko;                                 
   this.IsNetscape     = UserAgent.indexOf('mozilla') != -1 && 
                         UserAgent.indexOf('spoofer') == -1 && 
                         UserAgent.indexOf('compatible') == -1 && 
                         UserAgent.indexOf('webtv') == -1 && 
                         UserAgent.indexOf('hotjava') == -1 && 
                         !this.IsOpera &&
                         !this.IsKHTML && 
                         !this.IsMozilla && 
                         !this.IsFirebird && 
                         !this.IsFirefox;

   this.MinorVersion   = parseFloat(AppVersion);

   if (this.IsIE) {
      var pos = !this.IsMac ? AppVersion.indexOf('msie') : UserAgent.indexOf('msie');
      this.MinorVersion = !this.IsMac ? parseFloat(AppVersion.substring(pos+5, AppVersion.indexOf(';',pos))) : parseFloat(UserAgent.substring(pos+5, UserAgent.indexOf(';',pos)));
   }   
   
   if (this.IsKonqueror) {
      var pos = UserAgent.indexOf('konqueror');
      this.MinorVersion = parseFloat(UserAgent.substring(pos+10, UserAgent.indexOf(';', pos)));
   }
   
   if (this.IsGecko)
      this.MinorVersion = navigator.productSub;

   if (this.IsFirefox || this.IsFirebird || this.IsMozilla) {
      this.MinorVersion = (navigator.vendorSub) ? navigator.vendorSub : 0;
      if (!this.MinorVersion) {
         var pos = UserAgent.indexOf('rv:');
         this.MinorVersion = UserAgent.substring(pos+3);
         pos = this.MinorVersion.indexOf(')')
         this.MinorVersion = parseFloat(this.MinorVersion.substring(0, pos));
      }
      if (this.IsFirefox) {
         var pos = UserAgent.indexOf('firefox/');
         this.MinorVersion = parseFloat(UserAgent.substring(pos+8));
     }             
   }

  if (this.IsNetscape && navigator.vendor && (navigator.vendor == "Netscape6" || navigator.vendor=="Netscape"))
     this.MinorVersion = navigator.vendorSub;
   
  this.MajorVersion = parseInt(this.MinorVersion);
}

/////////////////////////////////////////////////////////////////////////////////////////
//	PUBLIC HELPER CLASS LOGGER (Singleton)
//
//  This class provides logging capability in a seperate tab or window. To enable logging
//  set ENABLE_LOGGING at the top of this file to 'true', after which one can write to
//  the logger like:
//
//    Logger.Write("<string message>", "#<RGB value>", <integer font size>);
//
//      OR
//
//    Logger.WriteLine("<string message>", ["#<RGB value>"], [<integer font size>]);
//
//  The default RGB value is #000 (black), the default font size is 14
//
//	ARGUMENTS
//		none
//
//	RETURNS
//		Logger instance which can be can be accessed through 'Logger' variable
//		
/////////////////////////////////////////////////////////////////////////////////////////
var	Logger = new function() {
	var hndl = null;
	var init = true;
	
	this.WriteLine = function(msg, color, size) {
		if (this.Write(msg, color, size))
			hndl.document.write("<br/>");
	}
	
	this.Write = function(msg, color, size) {
		if (!ENABLE_LOGGING) 
			return false;
		else {
			if (!hndl && init) {
				hndl = window.open();
				init = false;
			}
			try {
				hndl.document.write("");	
			} catch (e) {
				return false;	
			}
			if (!color) color = "#000";
			if (!size) size = 14;
			msg = msg.replace(/ /g,"&nbsp;");
			hndl.document.write("<font style='color: "+color+"; font-size: "+size+"px;'>"+msg+"</font>");
			return true;
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
//	LEGACY FUNCTIONS
//  
//  NOTE: DO NOT REMOVE/RENAME THESE, THEY ARE CALLED BY THE JSP VIEWS!
/////////////////////////////////////////////////////////////////////////////////////////
function resizeIframe(id) {
	if (IFrameManager.Contains(id))
		IFrameManager.IFrames(id).Resize();
}

function readjustIframe(e) {
	e = !e ? window.event : e;
	if (!e) return;
	var o = (e.currentTarget) ? e.currentTarget : e.srcElement;
	
	if (!IsNull(o)) {
	 	if (window.scrollTo)
			window.scrollTo(0,0);
		resizeIframe(o.id);
	}
}

function loadintoIframe(id, uri){
	if (IFrameManager.Contains(id))
		IFrameManager.IFrames(id).SetUri(uri);
}

function resizeCaller() {
	IFrameManager.ResizeAll();
}

function keepWatching () {
	var t = setInterval(resizeCaller, 100)
}