/*
	(w) 2005-2009 Ingrid Graefen, BRAINPOOL Artist und Content Services GmbH
*/

// Guarantee that some variables are defined.
if (!window.add2tag) add2tag = '';
if (!window.soi_adtrace) soi_adtrace = '';
if (!window.soi_ad) soi_ad = '';

if (!window.SIMAdWriter) {
	window.SIMAdWriter = new SIMAdHandler('DUMMY', null, window, 0);
}

/* GOOGLE ADS CONFIG */

/*
	This object allows google ads to query the state of relevant ordinary ads.
	It does *not* provide full info on display of ordinary ads.
	Key/value pairs ad_id => 0|1 are set by checkRectangle (e.g. rectangle2: 1).
	Thus SIM_ADTAG_INFO must only be queried after execution of these functions.
*/
var SIM_ADTAG_INFO = {};

// This variable is needed for incrementing google_skip
var SIM_GOOGLE_COUNT = 0;

// This variable is set with google variable configuration
// before including google's show_ads.js
var SIM_GOOGLE_ADTYPE = '';

/**********************************/

/*************************************************
Encapsulation for different adservers
*************************************************/
/*
	Arguments:
	ad_type:       string
	adserver_call: either reference to function, or NAME of global function (i.e. STRING)
	my_window:     window object (obsolete)
	config:        associative array
	               Valid properties (optional):
	               - path:                subsite path # maybe different from document path
	               - content_type:        beitrag|video|...
	               - available_ad_ids:    ['popup1', 'fullbanner2', ...]
	               - available_video_ads: ['preroll', 'sponsor', 'presplit', 'midroll', 'postsplit', 'overlay', 'postroll']
	               - videoad:             true|false
	               - ad_iframe:           URL for ad iframe document (currently not used)
	               - do_log:              0|1 (enable logging with timestamps)

	public properties:
		adType, bannerAdRequests, videoAdRequests

	public general methods:
		getSessionID, updateAds, handleEvent, isUpdateStart, loadNextIFrameAd,
		finishIFrameAd, resizeIFrame, syncVars, getTLD, hasVideoAds,
		doLog, showLog, clearLog

	public methods (ad_type specific):
		doAd, getVideoAdRequest, getAdtrace, getAdDimensions

	(1) Valid properties for updateAds config (all optional)
	- path                taxonomie path for update, e.g. '/kino/one/two'
	- triggered_for:      MCplayer|MCcontent|CPplayer|iframe_action|contentgallery|video...
	- callback_function:  name of callback function (string)
	- callback_id:        id of object whose callback_function is to be called
	- callback_object:    object whose callback_function is to be called (wins over callback_id)
	- callback_caller:    OPTIONAL, passed only if callback must be fired from specific ad_id, i.e. rectangle for contentgalleries
	- ad_iframe:          path to domino iframe - pass this only if default_ad_iframe is not suitable,
	                      and a suitable path could not be set on initialization of SIMAdWriter

	Applicable for videos only
	- video_type:         short|full
	- ad_exclude_all:      0|1
	- ad_exclude_midroll:  0|1
	- ad_exclude_overlays: 0|1
	- screen_mode:         fullscreen|fullsize|normal

	(2) Valid properties for handleEvent config
	- event:               screen
	- screen_mode:         fullscreen|fullsize|normal

	(3) Arguments for getVideoAdRequest
		(3.1) video_ad_id:  preroll1|midroll1|midroll1b...
		(3.2) JSON config - valid properties (optional)
		- prefetch:    0|1 // for prefetched video ad types, e.g. midrolls
		- industries:  {
		                  midroll1:  {industry: 'blub'},
		                  midroll1c: {industry: 'blab'}
		               }
*/
function SIMAdHandler(ad_type, adserver_call, my_window, config)
{
	var self = arguments.callee;
	
	// Constants
	this.__DOM_SAFE_ID = 'simadwriter-dom-safe';

	// Instance properties

	// Valid ad types are SOI
	this.adType = ad_type && ad_type == 'SOI' ?
		ad_type : 'DUMMY';

	// This property is obsolete
	// but set here to explain the meaning of the third argument,
	// which must be passed for backward compatibility
	this.__window = (my_window || window);

	this.__start_time = (new Date).getTime();

	this.__adserver_call = adserver_call;

	this.__config = typeof(config) == 'object' ? config : new Object;

	if (!this.__config.tld) this.__config.tld = 'de';
	if (!this.__config.available_ad_ids) this.__config.available_ad_ids = [];
	if (!this.__config.available_video_ads) this.__config.available_video_ads = [];

	if (!self.__init_general) {
		self.__init_general = 1;

		self.prototype.__iframe_prefix = 'iframe_';
		self.prototype.__default_ad_iframe = '/php-bin/functions/adtags/ad_iframedigital.php';

		// Public general methods

		self.prototype.isUpdateStart = function() {
			return (this.__is_update_start || 0);
		}

		self.prototype.updateAds = function(args) {
				// Prevent IE abortion on premature dom manipulation
				var is_dom_safe = this.__isDOMSafe();

				if (is_dom_safe == 0) {
					var that = this;
					setTimeout(function() {that.updateAds(args);}, 50);
					return;
				}
				else if (is_dom_safe < 0) {
					// Check was impossible.
					// Simply looped for some time.
					// Should be ok now => continue.
				}

				this.__logMsg('updateAds called with arguments:', args);

				this.__initUpdateConfig(args);

				if (this.adType == 'DUMMY') {
					this.__doCallback(0);
				}
				else {
					this.__startAdUpdate();
				}
			};
			
		self.prototype.handleEvent = function(args) {
				if (!args || typeof(args) != 'object') return;

				var event = args.event;
				if (!event) return;
				
				var content_type = this.__getUpdateConfig('content_type');

				if (event == 'screen') {
					var flag;
					if (content_type == 'MCcontent') {
						flag = 1;
					}
					else if (content_type == 'MCplayer' || content_type == 'CPplayer') {
						var screen_mode = (args.screen_mode || 'normal');
						flag = screen_mode == 'fullsize' ? 0 : 1;
					}
					else {
						return;
					}

					this.__logMsg('handleEvent called with arguments:', args);

					this.__setDisplayForAdIFrames(flag);
				}
			};

		self.prototype.loadNextIFrameAd = function(is_start) {
				var ad_id = this.__getNextAdID(is_start);
				if (!ad_id) return;
				
				// Default is used unless ad_iframe is passed on initialization
				// or via updateAds
				var ad_iframe = this.__getUpdateConfig('ad_iframe')
					|| this.__getConfig('ad_iframe')
					|| this.__default_ad_iframe;
				if (!ad_iframe) return;

				// Checking for the private property directly is necessary
				// to allow standalone test for ad_iframe*.php
				if (typeof(this.__update_config) != 'object') {
					this.updateAds();
					return;
				}

				var content_type = (this.__getUpdateConfig('content_type') || '');
				
				var url = ad_iframe + '?path='+ escape(this.__getUpdateConfig('path'))
					+ '&ad_id=' + escape(ad_id);

				if (content_type) url += '&content_type=' + escape(content_type);

				var available_ad_ids = this.__getConfig('available_ad_ids');
				if (available_ad_ids.length)
					url += '&all_iframe_ads=' + available_ad_ids.join('-');

				if (content_type.match(/^(video|CPplayer|MCplayer)$/)) {
					var video_type  = this.__getUpdateConfig('video_type');
					var screen_mode = this.__getUpdateConfig('screen_mode');

					if (video_type)                                    url += '&video_type=' + escape(video_type);
					if (screen_mode && screen_mode != 'normal')        url += '&video_screen_mode=' + escape(screen_mode);
					if (this.__getUpdateConfig('ad_exclude_all'))      url += '&video_no_ad=1';
					if (this.__getUpdateConfig('ad_exclude_midroll'))  url += '&video_no_midrolls=1';
					if (this.__getUpdateConfig('ad_exclude_overlays')) url += '&video_no_overlays=1';
				}

				// Params for debugging
				var query_string = window.location.search;
				if (query_string) {
					var found = query_string.match(/(?:[ios]+_[a-z]+_[a-z]+|[df][a-z]+_ads_?[a-z]*|ad_[a-z]+)=[a-zA-Z0-9_-]*/g);
					if (found) url += '&' + found.join('&');
				}

				try {
					this.__getIFrameHandler().loadIFrame(ad_id, this.__getIFrameID(ad_id), url);
					this.__logMsg('loadNextIFrameAd for ' + ad_id + ' session id: ' + this.getSessionID());
				}
				catch(e) {
					return;
				}

				return true;
			};

		self.prototype.finishIFrameAd = function(ad_id, iframe_window) {
				this.syncVars(iframe_window, window, 'after');

				if (this.__getUpdateConfig('callback_function')) {
					var callback_caller = (this.__getUpdateConfig('callback_caller') || '');
					if (callback_caller == ad_id) this.__doCallback(1);
				}

				this.resizeIFrame(ad_id);
			};

		self.prototype.resizeIFrame = function(ad_id) {
				var dimensions = this.getAdDimensions(ad_id);

				// Do not clobber dimensions array
				var x = dimensions[0];
				var y = dimensions[1];
				// Remedy for wrong fallback values
				if (x == 1 && y == 1) x = y = 0;

				try {
					this.__getIFrameHandler().resizeIFrame(
							this.__getIFrameID(ad_id),
							[x, y]
						);
				}
				catch(e) {
					return;
				}
				
				return true;
			};

		// This can be used to sync vars between arbitrary objects,
		// e.g. (parent, window), (this, window) ...
		// The third argument 'which' specifies sync_vars slot
		self.prototype.syncVars = function(from, to, which) {
				if (typeof(from) != 'object' || typeof(to) != 'object') return;
				if (from == to) return;

				var varnames = (this.__sync_vars[which] || new Array);
				
				for (var i = 0; i < varnames.length; i++) {
					to[varnames[i]] = from[varnames[i]];
				}
			};
		
		// Setter and getter method
		self.prototype.hasVideoAds = function() {
				if (arguments.length) this.__setConfig('videoad', arguments[0]);
				return this.__getConfig('videoad');
			};
		
		self.prototype.getTLD = function() {
				return this.__getConfig('tld');
			};
		
		self.prototype.getSessionID = function() {
				return this.__session_id || '';
			};
		
		self.prototype.doLog = function(flag) {
				if (typeof(flag) != 'undefined') this.__setConfig('do_log', flag);
				return this.__getConfig('do_log');
			};
			
		self.prototype.showLog = function() {
				if (!this.__log) return '';
				var retval = this.__log.join('\n\n');
				if (retval) retval = 'ALL TIMES ARE GIVEN IN SECS AFTER INIT OF SIMAdWriter\n\n' + retval;
				return retval;
			};
			
		self.prototype.clearLog = function() {
				this.__log = [];
			};
		
		// Private general methods

		self.prototype.__initInstance = function() {
				this.__setSessionID();
				if (typeof(this.__setSyncVars) == 'function') this.__setSyncVars();
				// For ie dom safe test
				if (parent == window && !document.getElementById(this.__DOM_SAFE_ID)) {
					document.write('<div id="' + this.__DOM_SAFE_ID + '" style="display:none"><\/div>');
				}

				try {
					var found = top.location.search.match(/simadwriter_debug=([0-9]+)/)
					if (found) this.doLog(found[1]);
				}
				catch(e) {
					this.__logMsg('__initInstance:\n' + this.__catchMe(e));
				}

				if (this.adType != 'DUMMY') this.__logMsg('new\nadType: ' + this.adType, this.__config);
			};

		self.prototype.__setSessionID = function() {
				var master = this.__findMaster();
				var rand = String(Math.random()).substring(2,11);
				this.__session_id = master ? (master.getSessionID() || rand) : rand;
				return this.__session_id;
			};

		self.prototype.__getAdserverCall = function() {
				var func = this.__adserver_call;
				var type = typeof(func);

				if (type == 'string') func = window[func];

				// Do not clobber property!
				if (typeof(func) != 'function') func = function() {return ''};

				return func;		
			};

		self.prototype.__startAdUpdate = function() {
				this.__setSessionID();

				// Clear all ads before new round.
				this.__clearSowefoContainer();
				this.__clearIFrameAds();
				this.__clearDebugPanel();
				this.bannerAdRequests = {};
				this.videoAdRequests  = {};

				// Init new update round with true argument.
				this.loadNextIFrameAd(true);
			};

		self.prototype.__findMaster = function(key) {
				if (window == parent) return;
				
				// This cannot be done on initialization
				// because child might exist before parent,
				// e.g. because of firefox iframe caching bug
				if (!this.__master) {
					try {
						// Should not know the name of parent instance, but ...
						if (parent.SIMAdWriter) this.__master = parent.SIMAdWriter;
					}
					catch(e) {
						this.__logMsg('__findMaster:\n' + this.__catchMe(e));
					}
				}

				return this.__master;
			};

		self.prototype.__getConfig = function(key) {
				if (!key || typeof(this.__config) != 'object') return;
				return this.__config[key];
			};

		self.prototype.__setConfig = function(key, value) {
				if (!key) return;
				if (typeof(this.__config) != 'object')
					this.__config = new Object;
				this.__config[key] = value;
			};

		self.prototype.__initUpdateConfig = function(args) {
				// Reset
				this.__update_config  = new Object;
				this.__video_ads_skip = new Object;

				if (typeof(args) == 'object') {
					for (var key in args) {
						this.__setUpdateConfig(key, args[key]);
					}
				}

				var available_ad_ids = this.__getConfig('available_ad_ids');

				// Special content types
				var triggered_for = (this.__getUpdateConfig('triggered_for') || '');
				if (triggered_for == 'CPplayer') {
					this.__setUpdateConfig('content_type', 'CPplayer');
				}
				else if (triggered_for == 'MCplayer') {
					this.__setUpdateConfig('content_type', 'MCplayer');
				}
				else if (triggered_for == 'MCcontent') {
					this.__setUpdateConfig('content_type', 'MCcontent');
				}
				else if (triggered_for == 'video') {
					this.__setUpdateConfig('content_type', 'video');
				}
				else if (triggered_for == 'contentgallery') {
					this.__setUpdateConfig('content_type', 'gallery');
				}

				// Defaults
				if (!this.__getUpdateConfig('path'))
					this.__setUpdateConfig('path', (this.__getConfig('path') || '/'));

				if (!this.__getUpdateConfig('content_type'))
					this.__setUpdateConfig('content_type', (this.__getConfig('content_type') || ''));
					
				if (!this.__getUpdateConfig('event'))
					this.__setUpdateConfig('event', '');
					
				if (!this.__getUpdateConfig('screen_mode'))
					this.__setUpdateConfig('screen_mode', 'normal');

				if (this.__getUpdateConfig('callback_function')) {
					if (!this.__getUpdateConfig('callback_caller')) {
						var l = available_ad_ids.length;
						if (l) {
							// callback should happen after fullbanner2
							// because fullbanner2 is reference ad type
							if (l > 1 && available_ad_ids[1] == 'fullbanner2') {
								this.__setUpdateConfig('callback_caller', 'fullbanner2');
							}
							else if (l > 0) {
								this.__setUpdateConfig('callback_caller', available_ad_ids[0]);
							}
						}
					}
					else {
						// callback_caller property was passed with update config
					}
				}

				if (this.__getUpdateConfig('ad_exclude_all'))      this.__video_ads_skip.all = 1;
				if (this.__getUpdateConfig('ad_exclude_midroll'))  this.__video_ads_skip.midrolls = 1;
				if (this.__getUpdateConfig('ad_exclude_overlays')) this.__video_ads_skip.overlays = 1;
			};

		self.prototype.__getUpdateConfig = function(key) {
				if (!key || typeof(this.__update_config) != 'object') return;
				return this.__update_config[key];
			};

		self.prototype.__setUpdateConfig = function(key, value) {
				if (!key) return;
				if (typeof(this.__update_config) != 'object')
					this.__update_config = new Object;
				this.__update_config[key] = value;
			};

		self.prototype.__doCallback = function(flag) {
			var callback_function = this.__getUpdateConfig('callback_function');
			if (!callback_function) return;

			var object = this.__getUpdateConfig('callback_object');
			if (!object) {
				var callback_id = this.__getUpdateConfig('callback_id');
				object = callback_id ? document.getElementById(callback_id) : window;
			}
			if (!object) return;

			var args = {
					init:    flag ? 1 : 0,
					ad_type: this.adType,
					tld:     this.__getConfig('tld')
				};

			var triggered_for = (this.__getUpdateConfig('triggered_for') || '');

			try {
				object[callback_function](args);
				this.__logMsg('callback function ' + callback_function + ' called with arguments:', args);
			}
			catch(e) {
				this.__logMsg('callback function ' + callback_function + ' FAILED with arguments:', args);
				return;
			}

			return true;
		}

		self.prototype.__clearIFrameAds = function() {
				var available_ad_ids = this.__getConfig('available_ad_ids');
				for (var i = 0; i < available_ad_ids.length; i++) {
					var ad_id = available_ad_ids[i];
					setAttributeForElement(ad_id, 'display', 'none');
					
					var iframe_handler = this.__getIFrameHandler();

					iframe_handler.resizeIFrame(this.__iframe_prefix + ad_id, [0,0]);

					try {
						iframe_handler.loadIFrame(ad_id, this.__getIFrameID(ad_id), 'about:blank');
					}
					catch(e) {
						continue;
					}
				}
				
				// Clear adserver variables (must be set to undefined!)
				if (this.__sync_vars) {
					for (var key in this.__sync_vars) {
						var varnames = (this.__sync_vars[key] || new Array);
						for (var i = 0; i < varnames.length; i++) {
							// IMPORTANT:
							// The delete operator deletes only global variables
							// that were explicitly defined as *window* property,
							// i.e. window[PROP] rather than using the var keyword.
							// Some global SOI variables cannot be deleted via delete.
							window[varnames[i]] = undefined;
						}
					}
				}
				
				if (this.__dimensions) this.__dimensions = new Array;
				if (this.__adtrace) this.__adtrace = new Array;
			};

		self.prototype.__setDisplayForAdIFrames = function(flag) {
				var available_ad_ids = this.__getConfig('available_ad_ids');
				var l = available_ad_ids.length;
				if (!l) return;

				for (var i = 0; i < l; i++) {
					var ad_id = available_ad_ids[i];
					try {
						this.__getIFrameHandler().setIFrameDisplay(this.__getIFrameID(ad_id), flag);
					}
					catch(e) {}
				}
			};

		self.prototype.__clearSowefoContainer = function() {
				var sowefo_container = document.getElementById('sowefo');
				if (sowefo_container) sowefo_container.innerHTML = '';
			};

		self.prototype.__clearDebugPanel = function() {
				var debug_id = 'sim_ad_debug';
				var debug_container = document.getElementById(debug_id);
				if (debug_container) debug_container.innerHTML = '';
			};

		self.prototype.__getNextAdID = function(is_start) {
				var available_ad_ids = this.__getConfig('available_ad_ids');
				var total = available_ad_ids.length;
				
				if (!total) {
					this.__updating = false;
					return;
				}
				
				// Avoid endless loops
				if (!is_start && !this.__updating) return;

				if (is_start) {
					this.__updating = true;
					this.__update_index = 0;
					this.__is_update_start = true;
				}
				else {
					this.__is_update_start = false;

					if (this.__update_index == total) {
						this.__updating = false;
						this.__update_index = null;
						return;
					}
				}
				
				return available_ad_ids[this.__update_index++];
			};

		self.prototype.__getIFrameID = function(ad_id, prefix) {
				return (prefix || this.__iframe_prefix) + ad_id;
			};
			
		self.prototype.__getIFrameHandler = function() {
				if (!this.__ad_iframe_handler) {
					this.__ad_iframe_handler = new SIMAdIFrameHandler();
				}
				return this.__ad_iframe_handler;
			};

		self.prototype.__skipVideoAdRequest = function(video_ad_id) {
				if (!this.hasVideoAds()) return true;
				if (!this.__video_ads_skip) return false;
				if (this.__video_ads_skip.all) return true;
				if (video_ad_id) {
					if (video_ad_id.match(/^(presplit|midroll|postsplit)/) && this.__video_ads_skip.midrolls) return true;
					if (video_ad_id.match(/^overlay/) && this.__video_ads_skip.overlays) return true;
				}
				return false;
			};

		// Check if IE is ready for dom manipulation.
		// The hidden container is written on instance initialization
		self.prototype.__isDOMSafe = function() {
				var retval;
				
				if (window != top) {
					// Should never happen
					retval = 0;
				}
				else {
					if (!this.__dom_check) {
						var container = document.getElementById(this.__DOM_SAFE_ID);
						var safe = !/msie/.test(window.navigator.userAgent.toLowerCase()) || window.opera ? 1 : 0;
						var hopeless = safe || (container && container.doScroll) ? 0 : 1;
						this.__dom_check = {
								counter:    1,
								safe:       safe,
								container:  container,
								hopeless:   hopeless,
								max_rounds: hopeless ? 10 : 40
							};
					}

					if (this.__dom_check.safe) {
						retval = 1;
					}
					else {
						if (this.__dom_check.hopeless) {
							// DOM safe check is impossible, just loop max_rounds
							if (++this.__dom_check.counter > this.__dom_check.max_rounds) {
								retval = -1;
							}
							else {
								retval = 0;
							}
						}
						else {
							try {
								this.__dom_check.container.doScroll('left');
								retval = 1;
							}
							catch(e) {
								retval = ++this.__dom_check.counter > this.__dom_check.max_rounds ? -1 : 0;
							}
						}

						// Also considered safe in -1 case (i.e. hopeless after max rounds)
						if (retval != 0) this.__dom_check.safe = 1;

						if (retval < 0 && this.__dom_check.safe) {
							this.__logMsg('__isDOMSafe check impossible. Considered safe in round ' + this.__dom_check.counter);
						}
						else if (retval > 0) {
							this.__logMsg('__isDOMSafe ok in round ' + this.__dom_check.counter);
						}
					}
				}
				
				return retval;
			};
		
		self.prototype.__logMsg = function(msg, args) {
				if (!this.doLog()) return;
				
				if (typeof(msg) == 'undefined') msg = '';
				
				if (!this.__log) this.__log = [];
				
				if (typeof(args) == 'object') {
					msg += '\n';
					for (var k in args) {
						// Let's go without recursion if value is an object
						msg += [k, args[k]].join(': ')+'\n'
					}
					msg = msg.replace(/\n+$/, '');
				}
				
				var time_passed = ((new Date).getTime() - this.__start_time) / 1000;

				var master = this.__findMaster();
				if (master) {
					// Currently the only way to log from within domino iframes.
					master.__logMsg(msg + ' from domino iframe');
				}
				else {
					// Usually, this case applies to parent instance.
					// But master is also not defined
					// if domino iframes are loaded before master instance has been initialized.
					// This may happen due to firefox iframe caching bug.
					// Unfortunately, such messages are lost for the parent document
					// because the domino iframes are reloaded immediately.
					this.__log.push('* ' + time_passed + ' secs\n' + msg);
				}
			};
			
		self.prototype.__catchMe = function(e) {
				return '<span style="color:red">' + (typeof(e) == 'string' ? e : [e.name, e.message].join('\n')) + '<\/span>\n';
			};
	}

	if (!self.__init_ad_type) {
		if (this.adType != 'DUMMY') {
			// Set __init_ad_type property for first *regular* object, not for dummy objects.
			// After that all SIMAdHandler objects share these properties.
			self.__init_ad_type = 1;
		}

		// Prototype property
		if (!this.bannerAdRequests) this.bannerAdRequests = new Object();
		if (!this.videoAdRequests)  this.videoAdRequests  = new Object();
		
		if (this.adType == 'SOI') {
			// Public prototype methods

			// WARNING:
			// doAd writes a *script* tag to the document.
			// Thus it is not possible to fill the
			// properties '__dimensions' and '__adtrace'.
			// The variables are simply accessible too late.
			self.prototype.doAd = function(ad_id) {
					this.__logMsg('doAd for ' + ad_id);
					var adserver_call = this.__getAdserverCall()
					var retval = adserver_call(ad_id);

					// For debugging.
					var master = this.__findMaster();

					var found = retval.match(/src=["']?([^"'< ]+)/);
					var src = found && found[1] ? found[1] : '';

					this.bannerAdRequests[ad_id] = src;
					// Always collect also in master
					if (master) master.bannerAdRequests[ad_id] = src;

					document.write(retval);
				};

			self.prototype.getVideoAdRequest = function(video_ad_id, args) {
					if (this.__skipVideoAdRequest(video_ad_id)) return '';

					// Backwards compatibility:
					// Second and third argument used to be strings (tvl, tcluster),
					// which are obsolete.
					if (typeof(args) != 'object') args = new Object;
					
					var ad_request = '';

					if (typeof(window.soi_VideoAdRequest) == 'function') {
						var content_type = this.__getUpdateConfig('content_type');
						var config_data = new Object;
						if (typeof(args.industries) == 'object') config_data.industries = args.industries;
						if (args.prefetch) config_data.prefetch = true;
						// FIXME: This must disappear eventually.
						// Player must pass 'prefetch' if needed.
						if (typeof(args.prefetch) == 'undefined'
							&& (content_type == 'MCplayer' || content_type == 'CPplayer')) {
							if (video_ad_id.match(/^midroll/)) {
								config_data.prefetch = true;
							}
						}

						ad_request = window.soi_VideoAdRequest(video_ad_id, config_data);
					}

					// For debugging.
					this.videoAdRequests[video_ad_id] = ad_request;
					
					this.__logMsg('getVideoAdRequest for ' + video_ad_id, args);

					return ad_request;
				};

			self.prototype.getAdtrace = function() {
					return window.soi_adtrace ? unescape(window.soi_adtrace) : '';
				};

			self.prototype.getAdDimensions = function(ad_id) {
					var dimensions;

					if (window.soi_dimension) {
						dimensions = window.soi_dimension[ad_id];
					}

					if (dimensions && ad_id == 'fullbanner2'
						&& isType('fullbanner2', 'PB2', this.getAdtrace())) {
						// For some strange reason, the powerbanner height value
						// is usually faulty (90 instead of 180).
						dimensions[1] = 180;
					}

					return (dimensions || [0,0]);
				};

			// Private prototype methods
			self.prototype.__setSyncVars = function() {
					this.__sync_vars = {};

					this.__sync_vars.after = ['soi_adtrace', 'soi_dimension',
						'SoiSetPre', 'SoiSetSpon', 'SoiSetMid', 'SoiSetOva', 'SoiSetPost',
						'forceSkyscraperInside', 'forceSkyscraperOutside', 'preferSkyscraperOutside',
						'DFPSite', 'DFPZone', 'DFPTile', 'DFPOrd', 'DFPOid',
						'SOI_SITE', 'SOI_SUBSITE', 'SOI_SUB2SITE', 'SOI_SUB3SITE', 'SOI_SUB4SITE', 'SOI_SUB5SITE', 'SOI_SUB6SITE',
						'SOI_BREADCRUMBS', 'SOI_MARKETINGCLUSTER', 'SOI_CONTENT',
						'SOI_WERBUNG', 'SOI_FB1', 'SOI_FB2', 'SOI_RT1', 'SOI_RT2', 'SOI_RT3', 'SOI_SC1', 'SOI_PU1',
						'SOI_VP', 'SOI_VA1', 'SOI_VA2', 'SOI_VA3', 'SOI_VA4', 'SOI_VA5', 'SOI_LPY', 'SOI_NPY',
						'SOI_SOWEFO', 'SOI_PU', 'SOI_WP', 'SOI_PW', 'SOI_PB', 'SOI_PC', 'SOI_PL', 'SOI_PR',
						'SOI_UPC'
					];
				};
		}
		
		// Define defaults for undefined methods.
		var methods = ['doAd', 'getVideoAdRequest', 'getAdtrace'];

		for (var i = 0; i < methods.length; ++i ) {
			var method = methods[i];
			if (!self.prototype[method]) {
				self.prototype[method] = function() {return ''};
			}
		}
		
		if (!self.prototype.getAdDimensions) {
			self.prototype.getAdDimensions = function() {return []};
		}
	}
		
	this.__initInstance();
}

/*******************************************
IMPORTANT:
SIMAdIFrameHandler is only useful
in main document
*******************************************/

function SIMAdIFrameHandler()
{
	var self = arguments.callee;

	if (!self.__init) {
		self.__init = 1;

		self.prototype.loadIFrame = function(ad_id, iframe_id, url) {
				if (!url) url = 'about:blank';

				try {
					var iframe_window = this.__getIFrameWindow(ad_id, iframe_id);
					iframe_window.location.replace(url);
				}
				catch(e) {
					try {
						var iframe = document.getElementById(iframe_id);
						iframe.src = url;
					}
					catch(e) {
						return;
					}
				}

				return true;
			};

		self.prototype.resizeIFrame = function(iframe_id, dimensions) {
				var iframe = document.getElementById(iframe_id);
				if (!iframe) return;

				if (iframe.style.display == 'none') iframe.style.display = 'inline';
				iframe.style.width  = dimensions[0] + 'px';
				iframe.style.height = dimensions[1] + 'px';
			};
			
		self.prototype.setIFrameDisplay = function(iframe_id, flag) {
				var iframe = document.getElementById(iframe_id);
				if (!iframe) return;
				
				if (flag) {
					if (iframe.style.display == 'none') iframe.style.display = 'inline';
				}
				else {
					// Always
					iframe.style.display = 'none';
				}
			};

		self.prototype.__getIFrameWindow = function(ad_id, iframe_id) {
				var iframe = this.__getAdIFrame(ad_id, iframe_id);
				if (!iframe) return;

				var iframe_window = iframe.contentWindow;

				if (!iframe_window) {
					try {
						iframe_window = iframe.contentDocument.defaultView;
					}
					catch(e) {
						try {
							iframe_window = window.frames[iframe_id];
						}
						catch(e) {}
					}
				}

				return iframe_window;
			};

		self.prototype.__getAdIFrame = function(ad_id, iframe_id) {
				if (!ad_id) return;
				if (!this.__ad_iframes) this.__ad_iframes = new Object;

				if (!this.__ad_iframes[ad_id]) {
					var iframe = document.getElementById(iframe_id);

					if (!iframe) {
						var ad_container = document.getElementById('target_' + ad_id);
						if (!ad_container) return;

						var width  = 0;
						var height = 0;
						var border = 0;

						iframe = document.createElement('iframe');

						iframe.id           = iframe_id;
						iframe.name         = iframe_id;
						iframe.style.width  = width + 'px';
						iframe.style.height = height + 'px';
						iframe.width        = width;
						iframe.height       = height;
						iframe.src          = 'about:blank';
						iframe.frameBorder  = border;
						iframe.border       = border;
						iframe.scrolling    = 'no';

						var container_parent = ad_container.parentNode;
						if (!container_parent) return;

						container_parent.replaceChild(iframe, ad_container);
					}

					this.__ad_iframes[ad_id] = iframe;
				}

				return this.__ad_iframes[ad_id];
			};

	}
}

/*****************************************
Functions for adtags check and adjustment
*****************************************/

function isType(ad_id, type) {
	var ad_type = SIMAdWriter.adType;
	
	var adtrace = SIMAdWriter.getAdtrace();
	if (!adtrace) return false;

	// Existence check.
	if (type == null) type = '';

	var typeTest = new RegExp(ad_id + '.+' + type, 'i');
	var result = typeTest.test(adtrace);

	return result ? true : false;
}

function existsRectangle(ad_id) {
	var exists   = isType(ad_id);
	var fallback = isType(ad_id, 'Fallback');

    return exists && !fallback ? true : false;
}

function hasBlockpixel(ad_id) {
	return isType(ad_id, 'Block[_-]?pixel') ? true : false;
}

function reserveSowefoSpace(ad_id) {
	var reserve_space = isType(ad_id, 'Block[_-]?pixel.+' + ad_id);

	// fullbanner2 keyword can also be 'superblock'
	if (!reserve_space && ad_id == 'fullbanner2') {
		reserve_space = isType(ad_id, 'Block[_-]?pixel.+' + 'superblock');
	}

	return reserve_space ? true : false;
}

function minWidthForSkyscraperOutside() {
	var searchstring = window.location.search.substring(1);

	var found;
	var min_width;

	if (searchstring) {
		found = searchstring.match(/outside=([0-9]+)/);
		if (found && found[1]) min_width = parseInt(found[1]);
	}
	
	if (!min_width) min_width = 1175;
	return min_width;
}

function checkRectangle(ad_id, div_id) {
	var exists = existsRectangle(ad_id) ? true : false;
	SIM_ADTAG_INFO[ad_id] = exists ? 1 : 0;

	// Container might not exist.
	var elem = document.getElementById(div_id);
	if (!elem) return exists;

	if (exists) {
		if (hasBlockpixel(ad_id)) {
			if (reserveSowefoSpace(ad_id)) {
				elem.style.backgroundColor = 'transparent';
				elem.style.backgroundImage = 'none';
				var td_elem = document.getElementById('td-' + ad_id);
				if (td_elem) td_elem.style.backgroundImage = 'none';
			}
			else {
				elem.style.display = 'none';
				return;
			}
		}

		elem.style.display = 'block';
	}
	else {
		elem.style.display = 'none';
	}

	return exists;
}

function adjustLayoutForWallpaper() {
	void(0);
}

// Function may be called after loading popup1
function adjustLayoutForSowefo() {
	void(0);
}

function shiftSkyscraper(div_id) {
	var el = document.getElementById(div_id);
	if (!el) return;
	if (el.style.display == 'none') return;
	
	if (needsSkyscraperEmbedded()) {
		el.className = 'skyscraper-embedded';
	}
}

function needsSkyscraperEmbedded() {
	var needs_skyscraper_embedded;

	if (!window.forceSkyscraperOutside) {
		if (window.forceSkyscraperInside) {
			needs_skyscraper_embedded = 1;
		}
		else if (!window.preferSkyscraperOutside
			&& !hasScreenWidthForSkyscraperOutside()) {
				needs_skyscraper_embedded = 1;
		}
	}

	return (needs_skyscraper_embedded || 0);
}

function hasSkyscraperEmbedded() {
	return SIM_ADTAG_INFO['skyscraper1'] && needsSkyscraperEmbedded();
}

function hasScreenWidthForSkyscraperOutside()
{
	return getScreenWidth() >= minWidthForSkyscraperOutside() ? true : false; 
}

function getScreenWidth()
{
	var x = top.innerWidth;

	if (!x) {
		var element = top.document.documentElement || top.document.body;
		if (element) x = element.clientWidth;
		if (!x) x = top.document.body.offsetWidth;
	}

	return x || 0; 
}

function checkGalleryRectangle(ad_id, forwardUrl) {
    if (!existsRectangle(ad_id)) document.location = forwardUrl;
}

function checkCrossRectangles() {
	return void(0);
}

/*
	Function for moving ordinary and google ads to final location
*/
function moveAd(id)
{
	var source_element = document.getElementById('source_' + id);
	var target_element = document.getElementById('target_' + id);

	if (!source_element || !target_element) return;
	
	// Workaround for IE bug:
	// Prevent IE duplicate request of script src when moving content of container.
	var embedded_scripts = source_element.getElementsByTagName('script');
	for (var i = 0; i < embedded_scripts.length; i++) {
		if (!embedded_scripts[i].src) continue;
		embedded_scripts[i].removeAttribute('src');
	}

	var target_parent = target_element.parentNode;

	target_parent.replaceChild(source_element, target_element);

	// Renaming of id is necessary for dynamic ad update via iframe.
	source_element.id = 'target_' + id;

	source_element.style.display = source_element.tagName.toLowerCase() == 'div' ?
		'block' : 'inline';
}

/******************************************
Functions for reloading adtags in iframes. 
******************************************/

/*
	Usage:
	*******
	
	The function iframesReload can be assigned to the onload event of an iframe.

	This will trigger the reload of adtags and ivw count (optionally)
	on each reload of this iframe.
	
	Arguments:
	**********
	
	- iframe_ids:
	  an array of iframe ids associated with iframes containing adtags
	  *or*
	  a string containing a single iframe id
	  PLEASE NOTE: This argument is obsolete but still required.
	
	- iframe:
	  a reference to the iframe that triggers the function
	  (this iframe must have a unique id)
	  *or*
	  a string containing a unique id
	
	- do_ivw_count:
	  boolean value
	  If set to true, executes the function 'count_ivw' provided
	  this function is defined.
	  
	Please note:
	************
	
	- The function gets executed on reload of the master iframe,
	  but *not* on first load of the document.
	
	- In IE 5.0, iframes do not fire the onload event.
	  Thus, this function gets never called in IE5.0.
*/

function iframesReload(iframe_ids, iframe, do_ivw_count)
{
	var id = typeof(iframe) == 'object' ? iframe.getAttribute('id') : iframe;
	// Some default id.
	if (!id) id = 'null';
	
	// This prevents reloading of iframes on initial load of master document.
	if (iframesReload[id]) {
		if (do_ivw_count && window.count_ivw) {count_ivw();}
		SIMAdWriter.updateAds({triggered_for: 'iframe_action'});
	}
	else {
		iframesReload[id] = 1;
	}
}
