// Begin MasterController
MKTW.namespace("HomePage");

//Is triggered when a chart on the page is selected.
fnChartChanged = function(type, args)
{
    //This will now only be triggered when there it is a Market Overview chart that needs updating.
    //Get a pointer to the MCP
    var MCP = MKTW.HomePage.MasterController.getInstance();
    
    //Set the divName on the CHART MU
    var MU = MCP.getUpdaterByTask("CHART");

    MU.setDiv(args[0].ticker);
    var tickerElement = document.getElementById(args[0].ticker);
    var imgNodes = tickerElement.getElementsByTagName("img");      
    var img = imgNodes[imgNodes.length-1];
    
    if(img != null && 0 > img.src.search(/charts/) && !($(img).hasClassName('loading')))
    {
        $(img.id).addClassName('loading');
        MCP.performUpdate(args[0].ticker, false);
    }
}
//Subscribe to the event and notify the page a chart is changing.
if(chartChangedEvt){
    chartChangedEvt.subscribe(fnChartChanged);
}
MKTW.HomePage.MasterController = function(){
    // Private collection of updaters
    var updaters = new Array();
    // Privileged methods
    // Accessor for the updaters
    this.getUpdaters = function() { return updaters; };
    // Here, we'll create the ModuleUpdater with the state passed in
    this.createUpdater = function(div, task, dataSrc, interval, extraParams){
        //TODO : Check for duplicate updaters here?
        var updater = new MKTW.HomePage.ModuleUpdater(div, task, dataSrc, interval, extraParams);
        updaters[updaters.length] = updater;
    }
    this.createChartUpdater = function(div, task, dataSrc, interval, extraParams){
        //TODO : Check for duplicate updaters here?
        var updater = new ChartsUpdater (div, task, dataSrc, interval, extraParams);
        updaters[updaters.length] = updater;
    }
    this.createTestNewsUpdater = function(div, task, dataSrc, interval, extraParams){
        //TODO : Check for duplicate updaters here?
        var updater = new TestNewsUpdater (div, task, dataSrc, interval, extraParams);
        updaters[updaters.length] = updater;
    }
    // Add an updater created externally (for updater extensions)
    this.addUpdater = function(updater){
        updaters[updaters.length] = updater;
    }
    // Start an updater in the collection by it's configured div
    this.startUpdater = function(div){
        var u = this.getUpdaterByDiv(div);
        if(undefined != u){
            u.suspended = false;
            u.intervalId = setTimeout("MKTW.HomePage.MasterController.getInstance().performUpdate('" + u.getDiv() + "', true)", u.getInterval());
        } else
        {   // What to do if it isn't found?
        }
    }
    // Start all the updaters            
    this.startAll = function(){
        for(i = 0; i < updaters.length; i++){
            this.startUpdater(updaters[i].getDiv());
        }
    }
    // Suspend an updater by its div
    this.suspendUpdater = function(div){
        var u = this.getUpdaterByDiv(div);
        if(undefined != u){
            u.suspended = true;
            clearTimeout(u.intervalId);
            u.intervalId = -1;
        } else {   // What to do if it isn't found?
        }
    }
    // Suspend all the updaters
    this.suspendAll = function(){
        for(i = 0; i < updaters.length; i++){
            this.suspendUpdater(updaters[i].getDiv());
        }
    }
    // Get an updater instance out of the collection by its div name
    this.getUpdaterByDiv = function(div){
        for(i = 0; i < updaters.length; i++){
            if(div.toLowerCase() == updaters[i].getDiv().toLowerCase()){
                return updaters[i];
            }
        };
        return null;
    }
    // Get an updater instance out of the collection by its assigned task name
    this.getUpdaterByTask = function(task){
        for(i = 0; i < updaters.length; i++){
            if(task.toLowerCase() == updaters[i].getTask().toLowerCase()){
                return updaters[i];
            }
        };
        return null;
    }
    // this method is the callback from the updater interval to initiate the data update, and eventually the render.
    this.performUpdate = function(div, persistTimeout){
        var u;
        try{
            u = this.getUpdaterByDiv(div);
            if(u == undefined){
                // Let's try by task now... this is an exception for the ChartUpdater
                u = this.getUpdaterByTask("CHART");
            }
            var src = u.getDataSrc();
            if(!u.suspended && src){         
                var httpRequest = this.getRequestObject();
                if(persistTimeout != null)
                {
					src = src + '&persist=' + persistTimeout;
                }
                httpRequest.open("GET", src, true);
                
                httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                httpRequest.setRequestHeader("Connection", "close");
                
                var me = this;
                httpRequest.onreadystatechange = function(){
                    if(httpRequest.readyState == 4){
                        me.updateUI(httpRequest.responseText);
                        delete httpRequest.onreadystatechange;
                        httpRequest = null;
                    }
                }
                httpRequest.send(null);
            };
        } catch(e) {
            // Suspend the updater, it'll get reset after the next refresh
            if(undefined != u){
                this.suspendUpdater(u.getDiv());
            }
        }
    }
    // This method is the callback from the ajax request in performUpdate.  In the JSON object, the key
    //  is the target updater / div name, and the value is the updated HTML to place in the div.
    this.updateUI = function(responseText){
        var u;
        try{
            var response = JSON.deserialize(responseText);
            u = this.getUpdaterByDiv(response.name);
            if(u == undefined){
                // Let's try by task now... this is an exception for the ChartUpdater
                u = this.getUpdaterByTask("CHART");
            }
            
            // Should we do something if the response didn't succeed? No reason to update if it didn't make it.
            if(u != undefined){
                if(response && response.succeeded){
                    u.render(response.html);
                    if(response.timeout != null && response.timeout != "") {
                        u.setInterval(response.timeout);
                    }
                }
                if(response.persist)
                {
					u.intervalId = setTimeout("MKTW.HomePage.MasterController.getInstance().performUpdate('" + u.getDiv() + "')", u.getInterval());          
				}
            }   
        } catch(e) {
            // Just disable the updater, it'll get re-initialized on the next refresh
            if(undefined != u){
                this.suspendUpdater(u.getDiv());
            }
        }
    }
    // Just for debugging purposes, spit out what we have here.
    this.emitState = function(){
        var count = updaters.length;
		var retVal = ("Updater count: " + count + "<br />");
        for(i = 0; i < count; i++){
            retVal = retVal + ("updaters[" + i +"] : " + updaters[i]);
        };
        return retVal;
    }
    // Helper method for creating the XMLHttpRequest object.  Lifted from UniAuth.js per Phil's recommendation.    
    this.getRequestObject = function(){
        var xmlHttp = false;
        try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } 
        catch (msxml2Exception){
            try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } 
            catch (microsoftException) { xmlHttp = false; }
        }
        if (!xmlHttp && typeof XMLHttpRequest != 'undefined')
            xmlHttp = new XMLHttpRequest();
        return xmlHttp;     
    }    
}
// End MasterController

// MasterController singleton
MKTW.HomePage.MasterController._controller = null;
MKTW.HomePage.MasterController.getInstance = function() {
    if(MKTW.HomePage.MasterController._controller == null) {
        MKTW.HomePage.MasterController._controller = new MKTW.HomePage.MasterController();
    }
    
    return MKTW.HomePage.MasterController._controller;
}
// End MasterController singleton

// ModuleUpdater definition
MKTW.HomePage.ModuleUpdater = function(div, task, src, interval, extraParams){
    // Private members
    var div = div;
    var task = task;
    var dataSrc = src;
    var intervalValue = interval;
    var extraParams = extraParams;
    var mutex = new Date();
    
    this.getMutex = function(){return mutex};
    this.setMutex = function()
    {
        var now = new Date();
        mutex = now.setSeconds(now.getSeconds() + 1);
    };
    
    // Privileged methods
    this.getDiv = function(){ return div; };
    this.getTask = function(){ return task; };
    this.setDiv = function(val){ div = val; };
    this.setInterval = function(val){ intervalValue = val; };
    this.getInterval = function(){ return intervalValue; };
    this.toString = function(){
        return "Div: <strong>" + div + "</strong> Task: <strong>" + task + "</strong> Data Source: <strong>" + dataSrc + "</strong> Interval value: <strong>" + intervalValue + "</strong> Suspended: <strong>" + this.suspended + "</strong><br />";
    };
    this.getDataSrc = function(){
        return dataSrc + "?task=" + task + "&target=" + this.getDiv() + (stringIsUndefinedOrEmpty(extraParams) ? "" : "&" + extraParams); 
    };
    
    this.render = function(newData){
        // Get the div name, and update the innerHTML with the passed in value.
        var divName = this.getDiv();
        if(!this.suspended){ 
            if(undefined != document.getElementById(divName)){
                document.getElementById(divName).innerHTML = newData;
            } else {
                // For whatever reason, the target div was not found.  Suspend here!
                MKTW.HomePage.MasterController.getInstance().suspendUpdater(divName);
            }
        }
    };
    // Public properties
    this.intervalId = -1;
    this.suspended = false;
}
// End ModuleUpdater definition

MKTW.HomePage.Hash = function(){
	this.length = 0;
	this.items = new Array();
	this.getItem = function(in_key){
		return this.items[in_key];
	}
	this.setItem = function(in_key, in_value){
	    var ret = -1;
		if (typeof(in_value) != 'undefined') {
			// add the item - use the hasItem method below instead?
			if (!this.hasItem(in_key)) {
		        this.items[in_key] = in_value;
				this.length++;
			} else {
			    // if the item exists, check the time against the one that is already in here.
			    // split the in_value, it is [index]:[time]
                var incomingItem = in_value.split("::");
                var incomingDate = new Date(Date.parse(incomingItem[1]));
                var existingItem = this.getItem(in_key).split("::");
                var existingDate = new Date(Date.parse(existingItem[1]));
                // compare dates.  If the incoming is later than the stored date, store it - otherwise, skip it.
                if(incomingDate >= existingDate){
			        ret = incomingItem[0]; // the index that's being replaced.
			        this.items[in_key] = in_value;
                }
			}
		}
	   
		return ret;
	}
	this.hasItem = function(in_key){
		return typeof(this.items[in_key]) != 'undefined';
	}
}


// StoryQueueManager
MKTW.HomePage.StoryQueueManager = function() {
    // Private members
    var _storyQueue = new Array();
    var _vintageQueue = new Array();
    var _timeoutId = null;
    var _timeoutDuration = 6000; // 6 secs
    var _storySeperator = "|||";
    var _ttlinks = [];
    var _tooltip = null;
    var _anim = null;
    // Privileged methods
    this.getStoryQueue = function() { return _storyQueue; };
    this.getVintageQueue = function() { return _vintageQueue; };
    this.animate = function(divName){
        this.cancelAnimation();
        _anim = new YAHOO.util.ColorAnim(divName, { backgroundColor: { from: '#E6EFEA', to: '#ffffff' } }, 5, YAHOO.util.Easing.easeIn);
        _anim.onComplete.subscribe(this.animComplete);
        _anim.animate();
    };
    this.cancelAnimation = function(){
        if(_anim != null && _anim.isAnimated()){
            _anim.stop(true);
            var el = _anim.getEl();
            el.style.backgroundcolor = '#ffffff';
            _anim = null;
        }
    }
    this.animComplete = function(){
        this.cancelAnimation();
        // Dump vintage queue?
        if(_vintageQueue.length > 0){
            var item = _vintageQueue.shift();
            if(item != undefined && item != null){
                var split = item.split(_storySeperator);
                updateDiv(split[1], split[0], false, true);
                this.updateToolTipLinks(split[0]);
            }
        }
    }
    this.init = function(){
        var div = getCurrentNewsDiv();
        this.updateToolTipLinks(div.id);
    }
    this.updateToolTipLinks = function(divName){
        var d = document.getElementById(divName);
        var collection = d.getElementsByTagName('a');
        _ttlinks.length = 0;
        for(i = 0; i < collection.length; i++){
            var headline = collection[i];
            if(headline.getAttribute('title') != null && headline.getAttribute('title') != undefined && headline.getAttribute('title') != ''){
                _ttlinks[_ttlinks.length] = headline;
            }            
        }
        _tooltip = new YAHOO.widget.Tooltip('_tooltip', { autoDismissDelay:30000, hideDelay:3000, context:_ttlinks });
    };
    this.updateTimeout = function(){ 
        _timeoutId = setTimeout("MKTW.HomePage.StoryQueueManager.getInstance().processStory(true)", _timeoutDuration);
    };
    // Queue up the passed in stories for insertion into the control.
    this.queueStory = function(divName, story){
        try{
            _storyQueue.push(divName + _storySeperator + story);
            if(_timeoutId == null){
                this.updateTimeout();
            }
        } catch(ex) {
            // do something!        
        }
    };
    // Queue up the passed in VINTAGE stories for insertion into the control.
    this.queueVintageStories = function(divName, stories){
        try{
            this.cancelAnimation();
            var dustyStories = MKTW.Cheat.parseJSON(stories);
	        var vintage = "";
	        // Pull the content out.
	        for(i = 0; i < dustyStories.length; i++){
	            vintage += dustyStories[i].html;
	        }
	        // If animating, store them for when anim is complete, otherwise, just throw them in the div.
            if(_anim && _anim.isAnimated()){
                _vintageQueue.push(divName + _storySeperator + vintage);
	        } else {
	            updateDiv(vintage, divName, false, true);
			    this.updateToolTipLinks(divName);
	        }
        } catch(ex) {
            // do something!        
        }
    };
    // This method gets called to pop a story off the queue and insert into the proper content div.
    this.processStory = function(anim){
        try{
            var item = _storyQueue.shift();
            if(item != undefined && item != null){
                var split = item.split(_storySeperator);
                updateDiv(split[1], split[0], anim);
                this.updateToolTipLinks(split[0]);
            }
            if(_storyQueue.length > 0){
                this.updateTimeout();
            } else {
                _timeoutId = null;
            }
        } catch(ex) {
            // Do something!        
        }
    };
    // This method will get called when the current tab switches to dump all stories out into
    //  the now hidden div.
    this.dumpQueue = function(){
        while(_storyQueue.length > 0){
            this.processStory(false);
        }
    };
    this.filterLiveNewsStories = function(newNews){
        var h = new MKTW.HomePage.Hash();
        for(i = 0; i < newNews.length; i++){
            var story = newNews[i];
            var delIndex = h.setItem(story.ID, i + "::" + story.Time);
            if(delIndex >= 0){
                delete newNews[delIndex];
                newNews[delIndex] = null;
            }
        }
        var counter = 0;
        var filteredNews = new Array();
        for(i = 0; i < newNews.length; i++)
        {
            if(newNews[i] != null)
            {
                filteredNews[counter++] = newNews[i];
            }
        }
        return filteredNews;
    };
}
// End StoryQueueManager

// StoryQueueManager singleton
/**
 * Unitary instance of the StoryQueueManager object
 * Do not call directly - use {StoryQueueManager.Instance()}
 * if you need to search and bind the DOM instead
 */

/**
 * Creates the single StoryQueueManager instance or returns the existing instance.
 */
MKTW.HomePage.StoryQueueManager.getInstance = function() {
    if (MKTW.HomePage.StoryQueueManager._qMgr == null){
        MKTW.HomePage.StoryQueueManager._qMgr = new MKTW.HomePage.StoryQueueManager();
    }
    return MKTW.HomePage.StoryQueueManager._qMgr;
}
// End StoryQueueManager singleton

// Just a helper method for identifying null / undefined / empty values.
stringIsUndefinedOrEmpty = function(value){
    return !((typeof(value) != "undefined") && (value != null) && (typeof(value) == "string") && value.length > 0);
}
// Creates an SEO link (like-this-with-dashes) for the story, if there's a headline.
seoInternalLink = function(headline, guid, extraParams){
    // We can not be sure if the guid will be encoded or decoded when it arrives here, so 
    // we have to decode it first to be safe.  Also, Story Finder for WAT needs the thing to be all-cap.
    return createSEOHeadline(headline) + "/story.aspx?guid=" + guid + (stringIsUndefinedOrEmpty(extraParams) ? "" : "&" + extraParams);
}
// Returns a formatted guid
getFormattedGuid = function(guid){
    if(stringIsUndefinedOrEmpty(guid)){
        return null;
    } else {
        var dash = /-/g, left = /{/g, right = /}/g
        var formattedGUID = guid.replace(dash, "%2D").toUpperCase();
        formattedGUID = formattedGUID.replace(left, "");
        formattedGUID = formattedGUID.replace(right, "");
        return "%7B" + formattedGUID + "%7D";
    }
}

// Actually creates the SEO headline by scrubbing the chars and breaking the words apart
createSEOHeadline = function(headline){
    var regexString = "";
    var outputString = "";
    var NUM_KEYWORDS = 5;
    var spacesRegex = /\s+/g;
    var invalidCharRegex = /[^A-Za-z0-9\s-]/g;
    var googleRegex = /\b(?:correct(?:ing|ed|ion)?|replac(?:e|ing|ed)|a(?:[nst]|re|nd)?|b(?:[ey]|ut)|f(?:or|rom)|i(?:[nst]|nto)?|l(?:ike|ot)|o[fnr]|t(?:o|h(?:an|at|e|is))|w(?:as|h(?:at|en|ere|ich|o)|i(?:th|ll)))\b\s+/g;
    regexString = headline.replace(spacesRegex, " ");
    regexString = regexString.replace(invalidCharRegex, "");
    regexString = regexString.replace(googleRegex, "");
    var splitStrings = regexString.split(' ');
    for (stringCnt = 0; stringCnt < splitStrings.length && (stringCnt < NUM_KEYWORDS + 1); stringCnt++){
        if (stringCnt == 0){
            outputString += "/";
        } else {
            outputString += "-";
        }
        outputString += splitStrings[stringCnt];
    }
    return outputString.toLowerCase();
}
// S.E.
isStoryAudioContent = function(doctype){
    return (doctype == "107" || doctype == "114" || doctype == "124");
}
// S.E.
isStoryVideoContent = function(doctype){
    return (doctype == "105" || doctype == "115" || doctype == "125");
}
// This method does the heavy lifting of creating the link to the story
getStoryUrl = function(story, params){
    var link = null;
    var rootLink = MKTWNonSecureUrl;
    if(rootLink.charAt(rootLink.length - 1) != "/"){
        rootLink = rootLink + "/";
    }
    if (story == undefined || story == null || stringIsUndefinedOrEmpty(story.DocType)){
        return link;
    }
    var headlineSpan = "<span>" + scrubTrashFromString(story.Headline) + "</span>"; // .unescapeHTML() + "</span>";
    // If the doctype is 90, there is no link... unless there's symbols in the story, then we can link to them.
    if(story.DocType == "90"){
        link = headlineSpan;
        if(story.Symbols.length > 0){   // Linkage!
            var symbol = story.Symbols[0];
            link = "[<a title=\"\" href=\"" + rootLink + "tools/quotes/quotes.asp?symb=" + symbol + "\">" + symbol + "</a>] " + link;
        }
    } else {
        var landingPage = "news/story/story.aspx";
        var guid = getFormattedGuid(story.ID);
        var title = scrubTrashFromString(story.Abstract.escapeHTML());
        var link = "<a ";
        if(!stringIsUndefinedOrEmpty(title)){
            link += "title=\"" + title + "\" ";
        }
        if(isStoryAudioContent(story.DocType)){
            link += "href=\"javascript:vlaunch('" + rootLink + "tvradio/player.asp?guid=" + guid + "')\">[audio] " + headlineSpan + "</a>";
        } else if(isStoryVideoContent(story.DocType)) {
            link += "href=\"javascript:vlaunch('" + rootLink + "tvradio/player.asp?guid=" + guid + "')\">[video] " + headlineSpan + "</a>";
        }
        else if (!stringIsUndefinedOrEmpty(story.Headline)){
            // Going to the story page, embed the headline into the URL
            var seoLink = seoInternalLink(story.Headline, guid, params);
            link += "href=\"" + rootLink + "news/story" + seoLink + "\">" + headlineSpan + "</a>";
        } else {
            link += "href=\"" + rootLink + landingPage + "?guid=" + guid + (stringIsUndefinedOrEmpty(params) ? "":"&" + params) + ">" + headlineSpan + "</a>";
        }
    }
    return link;
}
// The entry point for a returned story, creates the HTML for the entry in the control on the page.
formatNewsStory = function(story, params){
    if(story != undefined){
        var d = new Date(Date.parse(story.Time));
        var hour = d.getHours();
        hour += 1; // Surprise surprise... live news timestamps are CST!
        var ampm;
        if(hour >= 12){
            ampm = " p.m.";
        } else {
            ampm = " a.m.";
        }
        hour = hour % 12;
        if(hour == 0){
            hour = 12;
        } /*else if(hour > 12) {
            hour -= 12;
        }*/
        var minute = d.getMinutes() + '';
        if(minute.length == 1){
            minute = "0" + minute;
        }
        var retVal = "<div id=" + story.ID + " class=\"headlineEntry\">";
        retVal += "<span class=\"timestamp\">" +  hour + ":" + minute + ampm + "</span>";
        retVal += "<div class='headline'>" + getStoryUrl(story, params) + "</div>";
        retVal += "</div>";
        return retVal;
    }
}

// uh huh.
scrubTrashFromString = function(data){
    if(!stringIsUndefinedOrEmpty(data)){
        data = data.replace(/\"/g, "\'").replace(/<br>/g, "");
    }
    return data;
}

// Just what it says...
updateDiv = function(content, divName, anim, append){
    try{
        var d = document.getElementById(divName);
        if(append){        
            d.innerHTML = d.innerHTML + content;
        } else {
            d.innerHTML = content + d.innerHTML;
        }
        if(anim == true){
            MKTW.HomePage.StoryQueueManager.getInstance().animate($(divName).firstDescendant());
        }
    }
    catch(ex){
        // Let's do something about this!
    }
};
// The callback method for the live news control.
liveNewsCallback = function(newNews){
    liveNewsUpdate("livenewsdiv", newNews, "dist=hplatest");
};
topStoriesCallback = function(newNews){
    liveNewsUpdate("topstoriesdiv", newNews, "dist=hpts");
};
marketPulseCallback = function(newNews){
    liveNewsUpdate("marketpulsediv", newNews, "dist=hpmp");
};
headlinesCallback = function(newNews){
    liveNewsUpdate("headlinesdiv", newNews, "dist=hphead");
};
pressReleasesCallback = function(newNews){
    liveNewsUpdate("pressreleasesdiv", newNews, "dist=hppr");
};
bulletinCallback = function(newBulletin){
    if(newBulletin.length >= 1){
        var div = document.getElementById('bulletinContent');
        var story = newBulletin[0];
        div.innerHTML = getStoryUrl(story, null);
        var cDiv = document.getElementById('bulletinContainer');
        cDiv.setAttribute('style', 'display: block;');
        MKTW.HomePage.StoryQueueManager.getInstance().animate('bulletinContent')
    }    
};
liveNewsUpdate = function(divName, newNews, params){
    try{
        if(newNews.length > 1){
            newNews = MKTW.HomePage.StoryQueueManager.getInstance().filterLiveNewsStories(newNews);
        }
        for(i = 0; i < newNews.length; i++){
            var story = newNews[i];
            var div = document.getElementById(divName);

            if(div != null && div != undefined){
                var dupStory = document.getElementById(story.ID);
                if(dupStory != undefined && dupStory.parentNode == div){
                    div.removeChild(dupStory);
                }
            }
            // If the div is hidden, don't bother queueing these stories
            if($(divName).hasClassName('hidden')){
                updateDiv(formatNewsStory(story, params), divName, false);
            } else {   // This is the currently displaying div, queue these stories.
                MKTW.HomePage.StoryQueueManager.getInstance().queueStory(divName, formatNewsStory(story, params));
            }
        }
    }
    catch(exc){}
}
function newsTabClick(tab){
    var prevDiv;
    var contentDiv = tab + 'div';
    var ContainerElement=getContainerElement(tab, 'cmheader');
    if(!ContainerElement) 
        return;
    // 'unselect' the currently selected tab, by removing the class from all children who have 'cmtab'
    removeClassFrom('cmselectedtab', 'cmtab', ContainerElement);
    // Show the selected content div by removing the 'hidden' class from that div.
    var viewport = document.getElementById('latestheadlinesviewport');
    for(i = 0; i < viewport.childNodes.length; i++){
        var child = viewport.childNodes[i];
        // Make sure we hide all non-hidden divs.
        if(!$(child.id).hasClassName('hidden') && child.id != contentDiv){
            $(child.id).addClassName('hidden');
            prevDiv = child.id;
        }
    }
    // Reset scrolling to the top on a tab change, per Steve 6/3/08.
    if(viewport.scrollTop > 0) { viewport.scrollTop = 0; }
    // Now, show the selected tab as well as show the matching content.
    $(tab).addClassName('cmselectedtab');
    $(contentDiv).removeClassName('hidden');
    // If there's an animation in progress, can it.
    MKTW.HomePage.StoryQueueManager.getInstance().cancelAnimation();
    // Now dump the story queue, as the current div has changed - and set up the new links.
    MKTW.HomePage.StoryQueueManager.getInstance().dumpQueue();
    MKTW.HomePage.StoryQueueManager.getInstance().updateToolTipLinks(contentDiv);
    // Check to see if the new tab needs new - sorry, VINTAGE news too now!
    if(latestheadlinesviewport != undefined)
    { 
        latestheadlinesviewport.checkPosition();
    }
}
function getContainerElement(tabID, className){
    var ancestor=getAncestorWithClass(tabID, className);
    if(ancestor != null){
        return ancestor.up();
    } else {
        return null;
    }
}
function getAncestorWithClass(ID, PClass) {
    var Ancestors=$(ID).ancestors();
    for(var i=0; i < Ancestors.length; i++) {
        if(Ancestors[i].hasClassName(PClass))
            return Ancestors[i];
    }
    return null;
}
function removeClassFrom(classToRemove, classToSelect, ContainerElement) {
    var elements=ContainerElement.getElementsByClassName(classToSelect);
    for(var i=0; i < elements.length; i++) {
        elements[i].removeClassName(classToRemove);
    }
}
function getCurrentNewsDiv(){
    var viewport = document.getElementById('latestheadlinesviewport');
    for(i = 0; i < viewport.childNodes.length; i++){
        var child = viewport.childNodes[i];
        if(!$(child.id).hasClassName('hidden')){
            return child;
        }
    }
}
/* Begin MKTW.Cheat / MKTW.Forever section */
MKTW.namespace("Cheat");
MKTW.Cheat.parseJSON = function(string) {
    try {
        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                string.replace(/"(\\.|[^"\\])*?"/g, ''))) &&
            eval('(' + string + ')');
    } catch (e) {
        return false;
    }
};
MKTW.namespace("Forever");
MKTW.Forever.News = function(newsElementId, request){
	this.newsElement = document.getElementById(newsElementId);
	if (request.limit){
		this.maxHeadlines = request.limit;
	}
//	YAHOO.util.Event.onAvailable(this.newsElement.id, this.init, this);
};
MKTW.Forever.News.prototype.requestProcessing = false;
MKTW.Forever.News.prototype.maxHeadlines = 20;
MKTW.Forever.News.prototype.checkPosition = function(){
	var left = this.newsElement.scrollLeft;
	var top = this.newsElement.scrollTop;
	var pos = this.newsElement.scrollHeight - top;
	var pct = top / (this.newsElement.scrollHeight - this.newsElement.clientHeight);
	if (pct >= .8){
	    if(!MKTW.Forever.News.prototype.requestProcessing){
            MKTW.HomePage.StoryQueueManager.getInstance().cancelAnimation();
	        this.getMoreHeadlines();
	    }
	}
}
MKTW.Forever.News.prototype.getMoreHeadlines = function(){
    var currentDiv = getCurrentNewsDiv();
    var laststamp = $(currentDiv).readAttribute('lasttimestamp');
    var lastid = $(currentDiv).readAttribute('lastdocid');
    var doctype = $(currentDiv).readAttribute('doctype');
	this.headlineCallback = { success: this.handleSuccess, scope: this };
	MKTW.Forever.News.prototype.requestProcessing = true;
	var request = YAHOO.util.Connect.asyncRequest("GET", "BridgeTaskPage.aspx?task=VintageNews&target=" + currentDiv.id + "&count=" + this.maxHeadlines + "&lasttime=" + laststamp + "&lastid=" + lastid + "&doctype=" + doctype, this.headlineCallback);
};
MKTW.Forever.News.prototype.handleSuccess = function(o){
	MKTW.Forever.News.prototype.requestProcessing = false;
	if(o && o.responseText){
		var response = MKTW.Cheat.parseJSON(o.responseText);
		if(response && response.succeeded){
		    var result = MKTW.Cheat.parseJSON(response.html);
	        updateDiv(result.headlineHTML, response.name, false, true);
			var div = getCurrentNewsDiv();
			MKTW.HomePage.StoryQueueManager.getInstance().updateToolTipLinks(div.id);
		    if(result.lastDocId){
		        div.setAttribute('lastdocid', result.lastDocId);
			}
		    if(result.lastTimeStamp){
		        div.setAttribute('lasttimestamp', result.lastTimeStamp);
			}

            latestheadlinesviewport.checkPosition();
	    }
	}

//		var jsonResponse = MKTW.Cheat.parseJSON(o.responseText);
//		if (jsonResponse && jsonResponse.html){
//    		var jsonHeadlines = MKTW.Cheat.parseJSON(jsonResponse.html);
//			for (i = 0; i < jsonHeadlines.Headlines.length; i++){
//				updateDiv(formatNewsStory(jsonHeadlines.Headlines[i], null), jsonResponse.name, false, true);
//			}
//			var div = getCurrentNewsDiv();
//			MKTW.HomePage.StoryQueueManager.getInstance().updateToolTipLinks(div.id);
//		    if(jsonHeadlines.lastDocId){
//		        div.setAttribute('lastdocid', jsonHeadlines.lastDocId);
//			}
//		    if(jsonHeadlines.lastTimeStamp){
//		        div.setAttribute('lasttimestamp', jsonHeadlines.lastTimeStamp);
//			}
//		}
//	}
};
/* END MKTW.Cheat / MKTW.Forever section */
YAHOO.util.Event.onDOMReady(MKTW.HomePage.StoryQueueManager.getInstance().init);

SponsoredLinksUpdater.prototype = new MKTW.HomePage.ModuleUpdater();
SponsoredLinksUpdater.prototype.constructor = SponsoredLinksUpdater;
SponsoredLinksUpdater.prototype.parent = MKTW.HomePage.ModuleUpdater.prototype;
function SponsoredLinksUpdater(div, task, src, interval, extraParams)
{
    var div = div;
    var intervalValue = interval;
    
    this.parent.constructor.call(this, div, task, src, interval, extraParams);
    
    this.render = function(newData)
    {
        var iframe = document.getElementById(div);
        var oDoc = iframe.contentWindow || iframe.contentDocument;
        
    }
}


ChartsUpdater.prototype = new MKTW.HomePage.ModuleUpdater();
ChartsUpdater.prototype.constructor = ChartsUpdater;
ChartsUpdater.prototype.parent = MKTW.HomePage.ModuleUpdater.prototype;
function ChartsUpdater(div, task, src, interval, extraParams)
{   
    this.parent.constructor.call(this, div, task, src, interval, extraParams);

    var div = div;
    
    this.setDiv = function(newDiv)
    {
        div = newDiv;
    }
    
    this.getDiv = function()
    {
        return div;
    }
    
    this.render = function(newData)
    {
        var response = MKTW.Cheat.parseJSON(newData);
        var divTarget = response.target;
        var divNode = document.getElementById(divTarget);
        var imgNodes = divNode.getElementsByTagName("img");      
        if(imgNodes[imgNodes.length-1].getAttribute("src") != null)
        {
            imgNodes[imgNodes.length-1].setAttribute("src", response.html);
        }  
    }
}

TestNewsUpdater.prototype = new MKTW.HomePage.ModuleUpdater();
TestNewsUpdater.prototype.constructor = TestNewsUpdater;
TestNewsUpdater.prototype.parent = MKTW.HomePage.ModuleUpdater.prototype;
function TestNewsUpdater(div, task, src, interval, extraParams)
{   
    this.parent.constructor.call(this, div, task, src, interval, extraParams);

    var div = div;
    
    this.setDiv = function(newDiv)
    {
        div = newDiv;
    }
    
    this.getDiv = function()
    {
        return div;
    }
    
    this.render = function(newData)
    {
        liveNewsUpdate('livenewsdiv', newData, null);
    }
}

