/***********************************************************
 *    base class for showing ads based on frequency 
 *      cookies used for tracking/persistence
 ***********************************************************/
function adDisplayManager (id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl) {
    if ( arguments.length > 0 ) {
        this.init(id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl);
    }
}
// init method - really the "contructor"
adDisplayManager.prototype.init = function (id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl) {
    // important behavioral properties
    this.id = id;
    this.adType = adType;
    this.duration = duration;
    this.intDays = days;
    this.intHours = hours;
    this.intMinutes = minutes;
    this.intMStoExpire = (days * 86400000) + (hours * 3600000) + (minutes * 60000);
    this.setCookieIncludeIframe = setCookieIncludeIframe;
    if(redirectUrl){
    	this.redirectUrl=redirectUrl;
    }
    this.maxReruns = 1;
    this.disabled = false;
    // timer housekeeping
    this.intCurrentTime = new Date().getTime();
    this.timer = null;
    // cookie props/constants
    this.cookieName = 'adDisplayManager';
    this.cookieKey = this.id;
    this.cookieDelim = '&';
    this.cookieValDelim = '=';
    this.cookieValCountDelim = '~';
    this.cookieExpires = 30;
    // ad types and div ids to suppress
    this.adTypesToSuppress = null;
    this.divIdsToHide = null;
    this.handlers = null;
    // default (non-freq capped) ad types and div ids to suppress
    this.defaultAdTypesToSuppress = null;
    this.defaultDivIdsToHide = null;
    this.defaultHandlers = null;
    // read state from cookie
    var state = this.readState();
    this.lastRun = state.lastRun;
    this.runCount = state.runCount;
}
// set suppressed ads/elements 
adDisplayManager.prototype.setItemsToSuppress = function(adTypes, divIds) {
    if ( adTypes != null && adTypes.length > 0 ) {
        this.adTypesToSuppress = adTypes;
    }
    if ( divIds != null && divIds.length > 0 ) {
        this.divIdsToHide = divIds;
    }
}
// set default (non-freq capped) suppressed ads/elements 
adDisplayManager.prototype.setDefaultItemsToSuppress = function(adTypes, divIds) {
    if ( adTypes != null && adTypes.length > 0 ) {
        this.defaultAdTypesToSuppress = adTypes;
    }
    if ( divIds != null && divIds.length > 0 ) {
        this.defaultDivIdsToHide = divIds;
    }
}
// set a display handler object
adDisplayManager.prototype.setHandler = function(handler) {
    if ( handler != null ) {
      if ( this.handlers == null ) {
          this.handlers = new Array();
      }
      this.handlers[this.handlers.length] = handler;
    }
}
// set a default (non-freq capped) display handler object
adDisplayManager.prototype.setDefaultHandler = function(handler) {
    if ( handler != null ) {
      if ( this.defaultHandlers == null ) {
          this.defaultHandlers = new Array();
      }
      this.defaultHandlers[this.defaultHandlers.length] = handler;
    }
}
// set global "adsrc" type (appended to all adsrc vars)
adDisplayManager.prototype.setGlobalAdSrcType = function(globAdSrc) {
  if (this.isAdNeeded()) {
    AD_TRACKER.globalAdSrcType = globAdSrc;
  }
}
// set  default (non-freq capped) global "adsrc" type
adDisplayManager.prototype.setDefaultGlobalAdSrcType = function(globAdSrc) {
  if (!this.isAdNeeded()) {
    AD_TRACKER.globalAdSrcType = globAdSrc;
  }
}
// run the ad logic
adDisplayManager.prototype.run = function() {
    if (this.isAdNeeded()) {
	// reset count to prevent windup
	var newCount = this.runCount+1;
        if ( this.maxReruns > 1 && newCount > this.maxReruns ) {
	    newCount = 0;
        }
        this.saveState(this.intCurrentTime, newCount);
	this.start();
    } else {
        // never to sure about this logic but it was there
        if(this.duration!=null && this.duration != '' && this.duration != -1) {
            this.finish();
        }
        // start the default or "rest of the time" mode
	this.startDefault();
    }
}
// determine whether or not to show ad
adDisplayManager.prototype.isAdNeeded = function() {
  if (!this.disabled) {
    if (typeof (hideAllAds) == 'undefined' || hideAllAds == false) {
        if (null != this.lastRun) {
            if ( (this.intCurrentTime - this.lastRun) > this.intMStoExpire ) {
                return true;
            } else if (this.runCount < this.maxReruns) {
                return true;
            }
        } else {
            return true;
        }
    }
  }
  return false;
}
// save the ad state into the cookie
adDisplayManager.prototype.saveState = function(time, count) {
  if (!this.disabled) {
    this.setCookieValue(time + this.cookieValCountDelim + count);
    if (this.setCookieIncludeIframe && this.setCookieIncludeIframe.length > 0) {
      var iframe = document.createElement('iframe');
      iframe.src = this.setCookieIncludeIframe;
      iframe.style.width='0px';
      iframe.style.height='0px';
      var introDiv = document.getElementById(this.id);
      if (introDiv) {
        introDiv.appendChild(iframe);
      }
    }
  }
}
// save the ad state into the cookie
adDisplayManager.prototype.readState = function() {
  var last = null;
  var runcnt = 0;
  var cookval = this.readCookieValue();
  if (cookval != null) {
    var vals = cookval.split(this.cookieValCountDelim);
    if ( vals != null && vals.length > 0 ) {
      last = vals[0];
      if ( vals.length > 1 ) {
        runcnt = parseInt(vals[1], 10);
      }
    }
  }
  return { lastRun: last, runCount: runcnt };
}
// "start" or "show" the ad
//    - start is semantically associated with duration
//    - think of this method as "show" when no duration is specified)
adDisplayManager.prototype.start = function() {
    // show self and start duration timer
    document.getElementById(this.id).style.display = 'block';
    if(this.duration != null && this.duration != '' && this.duration != -1) {
        this.timer = window.setTimeout(this.id+'.finish()', this.duration);
    }
    // suppress ads that "conflict" with this managed ad
    if ( this.adTypesToSuppress != null ) {
        var adTypes = this.adTypesToSuppress.split(',');
        for ( var i=0; i<adTypes.length; i++ ) {
            AD_TRACKER.addToHidden(adTypes[i]);
        }
    }
    // suppress dom elems that "conflict" with this managed ad
    if ( this.divIdsToHide != null ) {
        var divIds = this.divIdsToHide.split(',');
        for ( var i=0; i<divIds.length; i++ ) {
            document.write('<style type=\"text/css\">div#' + divIds[i] + ' { display: none; }</style>');
        }
    }
    // run display handlers
    if ( this.handlers != null ) {
        for ( var i=0; i<this.handlers.length; i++ ) {
            if ( !this.handlers[i].makeRoom.call(this) ) {
            	this.handlers[i].manager = this;
                AD_TRACKER.addDeferredHandler(this.handlers[i]);
            }
        }
    }
}
// "finish" or "hide" the ad
adDisplayManager.prototype.finish = function() {
    // if redirecting, do it
    if(this.redirectUrl){
    	window.location = this.redirectUrl;
    	return;
    }
    // hide self and clean up timer
    document.getElementById(this.id).style.display = 'none';
    if (this.timer) {
        window.clearTimeout(this.timer);
    }
    // ad is finished, show the hidden elems
    if ( this.divIdsToHide != null ) {
        var divIds = this.divIdsToHide.split(',');
        for ( var i=0; i<divIds.length; i++ ) {
	    if (document.getElementById(divIds[i]) != null) 
	        document.getElementById(divIds[i]).style.display = 'block';
        }
    }
    // ad is finished, revert the handlers
    if ( this.handlers != null ) {
        for ( var i=0; i<this.handlers.length; i++ ) {
            handler[i].revert.call(this);
        }
    }
}
// start/show the ad in "default" or "rest of the time" mode WRT frequency capped operation
adDisplayManager.prototype.startDefault = function() {
    // show self
    document.getElementById(this.id).style.display = 'block';
    // suppress ads that "conflict" with this managed ad
    if ( this.defaultAdTypesToSuppress != null ) {
        var adTypes = this.defaultAdTypesToSuppress.split(',');
        for ( var i=0; i<adTypes.length; i++ ) {
            AD_TRACKER.addToHidden(adTypes[i]);
        }
    }
    // suppress dom elems that "conflict" with this managed ad
    if ( this.defaultDivIdsToHide != null ) {
        var divIds = this.defaultDivIdsToHide.split(',');
        for ( var i=0; i<divIds.length; i++ ) {
            document.write('<style type=\"text/css\">div#' + divIds[i] + ' { display: none; }</style>');
        }
    }
    // run display handlers
    if ( this.defaultHandlers != null ) {
        for ( var i=0; i<this.defaultHandlers.length; i++ ) {
            if ( !this.defaultHandlers[i].makeRoom.call(this) ) {
            	this.defaultHandlers[i].manager = this;
                AD_TRACKER.addDeferredHandler(this.defaultHandlers[i]);
            }
        }
    }
}
// set a value in the cookie
adDisplayManager.prototype.setCookieValue = function(newValue) {
    var newvals = '';
    var keyExists = false;
    var cook = getCookie(this.cookieName);
    if ( cook != null ) {
        var vals = cook.split(this.cookieDelim);
        for (var i=0; i<vals.length; i++) {
            var val = vals[i].split(this.cookieValDelim);
            newvals += (i==0) ? '' : this.cookieDelim;
            if ( val != null && val.length > 1 ) {
                if ( val[0] == this.cookieKey) {
                    newvals += val[0] + this.cookieValDelim + newValue;
                    keyExists = true;
                } else {
                    newvals += val[0] + this.cookieValDelim + val[1];
                }
            }
        }
    }
    if (!keyExists) {
        newvals += (newvals.length == 0) ? '' : this.cookieDelim;
	newvals += this.cookieKey + this.cookieValDelim + newValue;
    }
    setCookie(this.cookieName, newvals, this.cookieExpires);
}
// read a value from the cookie
adDisplayManager.prototype.readCookieValue = function() {
    var cook = getCookie(this.cookieName);
    if ( cook != null ) {
        var vals = cook.split(this.cookieDelim);
        for (var i=0; i<vals.length; i++) {
            var val = vals[i].split(this.cookieValDelim);
	    if ( val != null && val.length > 1 && val[0] == this.cookieKey) {
               return val[1];
	    }
        }
    }
    return null;
}

/***********************************************************
 *    static/global ad tracking class
 *      keeps global state of ad types and diplay handlers
 ***********************************************************/
function adDisplayTracker () {
    this.hiddenAds = null;
    this.handlers = null;
    this.timer = null;
    this.interval = 750;
    this.maxRunCount = 15;
    this.globalAdSrcType = null;
}
// static method to keep track of ads to hide
adDisplayTracker.prototype.addToHidden = function(adType) {
    if ( this.hiddenAds == null ) {
        this.hiddenAds = new Array();
    }
    this.hiddenAds[this.hiddenAds.length] = adType;
}
// static method to keep track of ads to hide
adDisplayTracker.prototype.isAdHidden = function(adType) {
    if ( this.hiddenAds != null ) {
        for( var i=0; i<this.hiddenAds.length; i++ ) {
            if ( this.hiddenAds[i] == adType ) {
                return true;
                break;
            }
        }
    }
    return false;
}
adDisplayTracker.prototype.addDeferredHandler = function(hand) {
    this.ensureSetup();
    this.handlers[this.handlers.length] = hand;
}
adDisplayTracker.prototype.ensureSetup = function() {
    if ( this.timer == null ) {
        this.timer = setTimeout('AD_TRACKER.processHandlers()', this.interval);
    }
    if ( this.handlers == null ) {
        this.handlers = new Array();
    }
}
adDisplayTracker.prototype.processHandlers = function() {
    if ( this.handlers == null || this.handlers.length == 0 ) {
        this.timer = null;
    } else {
        var newHandlers = new Array();
        for( var i=0; i<this.handlers.length; i++ ) {
            if ( !this.handlers[i].makeRoom.call(this.handlers[i].manager) && this.handlers[i].runCount < this.maxRunCount) {
                this.handlers[i].runCount++;
                newHandlers[newHandlers.length] = this.handlers[i];
            }
        }
        if ( newHandlers.length > 0 ) {
            this.handlers = newHandlers;
            this.timer = setTimeout('AD_TRACKER.processHandlers()', this.interval);
        } else {
            this.timer = null;
            this.handlers = null;
        }
    }
}
var AD_TRACKER = new adDisplayTracker();


/*****************************************************************************
 *    ad display handler abstract class
 *      display handlers encapsulate more complicated dom 
 *      manipulation (ie: more than hiding elems or suppressing ads by type
 *****************************************************************************/
function adDisplayHandler () {
    this.runCount;
}
// make room for the ad
adDisplayHandler.prototype.makeRoom = function() {
    return true;
}
// revert the "make room" operation
adDisplayHandler.prototype.revert = function() {}



/****** intro message manager ******/
function introMessageManager (id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl) {
    if ( arguments.length > 0 ) {
        this.init(id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl);
    }
}
introMessageManager.prototype = new adDisplayManager();
introMessageManager.superclass = adDisplayManager.prototype;
introMessageManager.prototype.init = function(id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl) {
    introMessageManager.superclass.init.call(this, id, adType, duration, days, hours, minutes, setCookieIncludeIframe, redirectUrl);
}
introMessageManager.prototype.start = function() {
    introMessageManager.superclass.start.call(this);
    if (this.adType=='intromessage') {
        document.write('<style type="text/css">div#maincontent, div#banner, div#Footer1 { display: none; }</style>');
    } else if (this.adType=='ssintromessage') {
        document.write('<style type="text/css">div#thumbFrame, div#multimedia, div#photoFrame, div#photoCaption, div#slideshowToolbar, div#slideshowAd, iframe#ReutersAd1 { display: none; }</style>');
    }
}
introMessageManager.prototype.finish = function() {
    introMessageManager.superclass.finish.call(this);

    if(this.adType == 'intromessage') {

        if (document.getElementById("maincontent") != null)
            document.getElementById("maincontent").style.display = 'block';
        if (document.getElementById("banner") != null)
            document.getElementById("banner").style.display = 'block';
        if (document.getElementById("Footer1") != null)
            document.getElementById("Footer1").style.display = 'block';

    } else if (this.adType == 'ssintromessage') {
    
        if (document.getElementById("section1") != null)
            document.getElementById("section1").style.display = 'block';
        if (document.getElementById("thumbFrame") != null) 
            document.getElementById("thumbFrame").style.display = 'block';
        if (document.getElementById("photoFrame") != null) 
            document.getElementById("photoFrame").style.display = 'block';
        if (document.getElementById("photoCaption") != null) 
            document.getElementById("photoCaption").style.display = 'block';
        if (document.getElementById("slideshowToolbar") != null) 
            document.getElementById("slideshowToolbar").style.display = 'block';
        if (document.getElementById("slideshowAd") != null) 
            document.getElementById("slideshowAd").style.display = 'block';
        if (document.getElementById("ReutersAd1") != null) 
            document.getElementById("ReutersAd1").style.display = 'block';

        var allDivs = document.getElementsByTagName("div");
        if (allDivs) {
            for (i=0; i<allDivs.length; i++) {
                if (allDivs[i].getAttribute('id') && allDivs[i].getAttribute('id') == 'slideshowAd')
                    allDivs[i].style.display = 'block';
            }
        }
    }
}



/****** poeCrumbinCorrect handler - moves the crumbtrail before the banner ******/
function poeCrumbinCorrectHandler () {}
poeCrumbinCorrectHandler.prototype = new adDisplayHandler();
poeCrumbinCorrectHandler.superclass = adDisplayHandler.prototype;
poeCrumbinCorrectHandler.prototype.makeRoom = function() {
    var res = false;
    if ( document.getElementById('crumbsBand') != null ) {
        var crumb = document.getElementById('crumbsBand');
        crumb.parentNode.removeChild(crumb);
        document.getElementById('prebanner').appendChild(crumb);
        crumb.style.display = 'block';
        res = true;
    } else if ( document.getElementById('crumbsBand') == null && this.runCount == 0 ) {
        document.write('<style type=\"text/css\">div#crumbsBand { display: none; }</style>');
    }
    return res;
}
poeCrumbinCorrectHandler.prototype.revert = function() {}


/****** poePageTitleHandler handler - moves a "page title" to a "new place" on the page ******/
function poePageTitleHandler () {}
poePageTitleHandler.prototype = new adDisplayHandler();
poePageTitleHandler.superclass = adDisplayHandler.prototype;
poePageTitleHandler.prototype.makeRoom = function() {
    var res = false;
    if ( document.getElementById('oldPageTitle') != null && document.getElementById('newPageTitle') != null) {
        var opt = document.getElementById('oldPageTitle');
        opt.parentNode.removeChild(opt);
        document.getElementById('newPageTitle').appendChild(opt);
        res = true;
    }
    return res;
}
poePageTitleHandler.prototype.revert = function() {}


/****** poe300x250Handler handler - moves the 300x250 to the top of the right rail to join with the top push-down ad ******/
function poe300x250Handler () {}
poe300x250Handler.prototype = new adDisplayHandler();
poe300x250Handler.superclass = adDisplayHandler.prototype;
poe300x250Handler.prototype.makeRoom = function() {
    var res = false;
    if ( document.getElementById('POE300x250') != null) {
        var ad = document.getElementById('POE300x250');
        var par = ad.parentNode;
        par.removeChild(ad);
        par.insertBefore(ad, par.firstChild);
        res = true;
    }
    return res;
}
poe300x250Handler.prototype.revert = function() {}

/****** poeOPAFixedPositionHandler handler - does the positioning of the ad ******/
function poeOPAFixedPositionHandler () {}
poeOPAFixedPositionHandler.prototype = new adDisplayHandler();
poeOPAFixedPositionHandler.superclass = adDisplayHandler.prototype;
poeOPAFixedPositionHandler.prototype.makeRoom = function() {
    document.write('<scri' + 'pt type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/yahoo-dom-event/yahoo-dom-event.js"></scri' + 'pt>');
    document.write('<scri' + 'pt type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/animation/animation-min.js"></scri' + 'pt>');
    var theAd = new adPositioner('theAd', 100, 'maincontent', true, 775, false );
    return true;
}

poeOPAFixedRightRailHandler.prototype.revert = function() {}
/****** poeOPAFixedRightRailHandler handler - makes room in the right rail and resizes maincontent and left rail ******/
function poeOPAFixedRightRailHandler () {}
poeOPAFixedRightRailHandler.prototype = new adDisplayHandler();
poeOPAFixedRightRailHandler.superclass = adDisplayHandler.prototype;
poeOPAFixedRightRailHandler.prototype.makeRoom = function() {
    document.write('<style type=\"text/css\"> .secondaryContent .moduleBody, #popularArticles, #rhsPOEtarget, .secondaryContent .moduleHeaderInline, .secondaryContent .tabs {display:none} .leftrail { margin-right:10px; } </style>');
    document.write('<style type=\"text/css\"> #maincontent, #maincontent #theAd { float: left; position: relative; } #theAd {height:775px;} .pointofentryContainer {display:none;} .primaryContent, .articleTools { width:454px } .secondaryContent { width:336px; } </style>');
    return true;
}
poeOPAFixedRightRailHandler.prototype.revert = function() {}


/***********************************************************
 *   positions ads in the vertical span by applying
 *   a cieling and a floor - a schwinn ming joint
 ***********************************************************/
function adPositioner (id, interval, container, useAnimation, height, writeStyles) {
    if ( arguments.length > 0 ) {
        this.init(id, interval, container, useAnimation, height, writeStyles);
    }
}
// init method - really the "contructor"
adPositioner.prototype.init = function(id, interval, container, useAnimation, height, writeStyles) {
    this.moving = false;
    this.id = id;
    this.container = container;
    this.useAnimation = useAnimation;
    this.height = height;
    if ( writeStyles == null || writeStyles ) { 
        this.writeStyles()
    }
    POSITION_TRACKER.registerPositioner(this, interval);
}
// calc current ad position and move it
adPositioner.prototype.moveIt = function () {
    if ( !this.moving  ) {
        this.moving = true;
        try {
          var scrollPos = this.getScrollPos();
          var height = this.getHeight();
          var floor = this.getFloor();
          var ceiling = this.getCeiling();
          if (scrollPos < ceiling) {
              this.moveTo(0);
          } else if ( scrollPos > (floor - height) ) {
              this.moveTo(floor - height - ceiling);
          } else if ((scrollPos >= ceiling) && (scrollPos <= (floor - height))) {
              this.moveTo(scrollPos - ceiling);
          }
        } catch(ex) {
        }
        this.moving = false;
    }
}
// move the ad to a new position
adPositioner.prototype.moveTo = function (where, duration) {
    if ( duration == null ) duration = 1;
    if ( this.useAnimation ) {
        try { this.adScroller.stop(); } catch(e) {};
        this.adScroller = new YAHOO.util.Anim(this.id, { top: { to: where }  }, duration, YAHOO.util.Easing.easeOut);
        this.adScroller.animate();
    } else {
        document.getElementById(this.id).style.top = where + 'px';
    }
}
// calc the current ceiling position
adPositioner.prototype.getCeiling = function () {
    return document.getElementById(this.container).offsetTop;
}
// calc the current floor position
adPositioner.prototype.getFloor = function () {
    return (document.getElementById(this.container).offsetTop + document.getElementById(this.container).offsetHeight);
}
// calc the current ad height
adPositioner.prototype.getHeight = function () {
    if ( parseInt(this.height) ) {
        return this.height;
    } else {
        return document.getElementById(this.id).offsetHeight;
    }
}
// calc the current scroll position
adPositioner.prototype.getScrollPos = function () {
    var scrollY = 0;
    if (typeof(window.pageYOffset) == "number") {
        scrollY = window.pageYOffset;
    } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
        scrollY = document.body.scrollTop;
    } else if (document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop )) {
        scrollY = document.documentElement.scrollTop;
    }
    return scrollY;
}
// write out supplementary styles
adPositioner.prototype.writeStyles = function () {
    var html = '<style type=\"text/css\">';
    html += '#' + this.container + ' { float: left; position: relative; }';
    var height = parseInt(this.height) ? ('height: ' + this.height + 'px; ') : '';
    html += '#' + this.container + ' #' + this.id + ' { float: left; position: relative; ' + height + '}';
    html += '</style>';
    document.write(html);
}


/***********************************************************
 *    static/global ad positioning class
 *      keeps global registry of positioned ads
 ***********************************************************/
function adPositionTracker () {
    this.positioners = null;
    this.sheduled = false;
}
// schedule the move function
adPositionTracker.prototype.shedule = function(interval) {
    this.sheduled = true;
    window.setInterval('POSITION_TRACKER.moveIt()', interval);
}
// register ad positioners - first call sets global interval, supports multiple positioners
adPositionTracker.prototype.registerPositioner = function(positioner, interval) {
    if ( this.positioners == null ) {
        this.positioners = new Array();
    }
    this.positioners[this.positioners.length] = positioner;
    if ( !this.sheduled ) {
        window.setTimeout('POSITION_TRACKER.shedule(' + interval + ')', interval);
    }
}
// static method to keep track of ads to hide
adPositionTracker.prototype.moveIt = function() {
    if ( this.positioners == null || this.positioners.length == 0 ) {
        return;
    } else {
        for( var i=0; i<this.positioners.length; i++ ) {
            this.positioners[i].moveIt();
        }
    }
}
var POSITION_TRACKER = new adPositionTracker();


