/*****************************************************************************************************************
 * file         : ninemsn.ysmGenerator.js
 * authour 	    : jay.choi@ninemsn.com.au
 * version 	    : 3.2
 * last update  : Evgeny Popov, removed Optus support & defaulted search to 'msncom_au_js_ctx'
 * require 	: ContentMgr.js, NinemsnComm.js, IA.jsh
 *
 * This javascript library renders YSM ads for ninemsn article pages and site search pages. 
 * For the article pages, because affilData is not required, ysmGenerate will call createYsm directly. 
 * But ysmGenerator will get affilData from a web service then call createYsm for the site search pages. 
 * createYsm will set up the required parameters and call Ysm to get the feeds, which are rendered by ysmCallback.
 ******************************************************************************************************************/

/** replace the string global scope */
String.prototype.replaceAll = function(fromText, toText, byWord) {
	fromText = byWord ? "\\b" + fromText + "\\b" : fromText;
	var regExp = new RegExp(fromText, "gi");
	return this.replace(regExp, toText);
};

/* create namespace maker */
var createNamespace;
if (!createNamespace || typeof(createNamespace) != "function") {
    createNamespace = function(namespace) {
        var names = namespace.split(".");
        var w = window;
        for(var i=0; i<names.length; i++) {
            if(!w[names[i]]) {
                w[names[i]] = {};
			}
            w = w[names[i]];
        }
    };
};

/* create namespaces */
createNamespace("ninemsn");
createNamespace("ninemsn.utils");

/* constants for default values */
var DEFAULT_KEYWORD_COLLECTION = ["deposit term","cheap flight","auto insurance","car insurance","broadband","card credit","car","job search","ebay","home loan","job","air travel"];
var DEFAULT_AFFIL_SERVICE = "/share/com/highlights/hl_ysm_affil.aspx";

/** 
 * ysmGenerator will call createYsm or affil proxy depending on whether affilData is provided or not
 * [arguments:5] = 0:containerId, 1:ysm, 2:config, 3:queryName, 4:isDebug
 *	- ysm 	[start, count, count1, count2, count3, adultFilter, searchType, serveUrl, keywords, defaultKeywords, affilData]
 *	- config [brandingTitle, imageType, adImageHeight, titleLength, descLength, hideImages, makeStrong]
 */
ninemsn.ysmGenerator = function() {

    this.create = function(args) {
        // get the arguments
        this.containerId = args[0];
        this.ysm = args[1] || {};
        this.config = args[2] || {};
        this.queryName = args[3];
        this.isDebug = args[4];

        // get default values if not defined
        this.ysm.start = this.ysm.start || 1;
        this.ysm.partnerId = this.ysm.partnerId || "msncom_au_js_ctxt";
        this.ysm.configId = this.ysm.configId || "1409223976";
        this.ysm.count1 = (this.ysm.count || (this.ysm.count == 0)) ? this.ysm.count : this.ysm.count1;
        this.ysm.count2 = this.ysm.count2 || 0;
        this.ysm.count3 = this.ysm.count3 || 0;
        this.ysm.count = this.ysm.count1 || (this.ysm.count1 == 0) ? this.ysm.count1 : 3;
        this.ysm.market = this.ysm.market || "au";
        this.ysm.rotate = this.ysm.rotate || 1;
        this.ysm.adultFilter = this.ysm.adultFilter || "any";
        this.ysm.affilService = this.ysm.affilService || DEFAULT_AFFIL_SERVICE;
        this.ysm.keywordCollection = this.ysm.keywordCollection || DEFAULT_KEYWORD_COLLECTION;

        this.config.brandingTitle = this.config.brandingTitle || "Sponsored Links";
        this.config.imageType = this.config.imageType || "product";
        this.config.adImageHeight = this.config.adImageHeight || 70;
        this.config.timeout = this.config.timeout || 5;
    };

    this.execute = function() {
        // no container, no ysm
        if (this.containerId) {
            var params = {
                containerId:this.containerId,
                ysm:this.ysm,
                config:this.config,
                queryName:this.queryName,
                isDebug:this.isDebug
            };

            // if affilData is provided, create ysm straight
            // if jsonId is given, it is article page and no affilData required so create ysm straight
            // otherewise use the afill data service
            if (this.ysm.affilData) {
                ninemsn.ysmGenerator.createYsm(params);
            }
            else if(this.ysm.jsonId) {
                ninemsn.ysmGenerator.createYsm(params);
            }
            else {
                params.ysm.affilId = this.containerId + "_affilData";
                var ysmCallback = this.ysm.affilService + "?affilId=" + params.ysm.affilId;

                ninemsn.utils.loadData(ysmCallback, params.ysm.affilId);
                ninemsn.utils.runCallback(params.ysm.affilId, ninemsn.ysmGenerator.createYsm, params, this.config.timeout, this.isDebug, ninemsn.ysmGenerator.ysmAffilDataFailed);
            }
        }
        else if(this.isDebug) {
            nude("[ninemsn.ysmGenerator.execute] No containerId!");
        };
    };
    
    this.create(arguments);
};
	
/** 
 * createYsm can be called directory from ysmGenerator if affilData is provided
 * otherwise it gets called as a callback function from an service returning affil data
 * [arguments:1] 	= 0:params
 */
var zCn, zRef, zSr;
var JS_SITE, JS_MOOTER_CATEGORY_NAME, JS_PAGE_COBRAND;
ninemsn.ysmGenerator.createYsm = function() {

    /* construct ysmGenerator */
    this.create = function(args) {
        var params = args[0];
        
        this.containerId = params.containerId;
        this.ysm = params.ysm || {};
        this.config = params.config || {};
        this.queryName = params.queryName;
        this.isDebug = params.isDebug;
    };

    /* initialise this instance */
    this.init = function() {
        try {
            this.isDebug = ninemsn.utils.getParamValue("isDebug") == "true" ? true : this.isDebug;

            // if no affilData, check if it is generated by service
            if (!this.ysm.affilData && this.ysm.affilId) {
                this.ysm.affilData = eval(this.ysm.affilId);
            }

            // get the other required variables
            var form = document.getElementById("frmForm");
            this.url = form && form.action.split("?").length >= 2 ? form.action.split("?") : window.location.href.split("?");

            // if jsonId is given, it's article page
            if (this.ysm.jsonId) {
                this.getArticleYsm(this.containerId);
            }
            else {
                this.getSearchYsm(this.containerId);
            }
        }
        catch (e) {
            if (this.isDebug) {
                nude("[ninemsn.ysmGenerator.init] " + e);
            }
        }
    };

    /* get the required params and call ysm for site search */
    this.getSearchYsm = function(cointainerId) {
        try {
            this.cointainerId = cointainerId || this.containerId;

            // create ysm if content element is found
            var container = document.getElementById(this.containerId);
            if (container) {
                container.style.display = "none";

                // if keywords manually given, use it
                // otherwise, get it from query string
                this.ysm.keywords = this.ysm.keywords ? this.ysm.keywords : ninemsn.utils.getParamValue(this.queryName);
                
                // if keywords is not defined, check if defaultKeyword is given or doublecall is requested
                if(!this.ysm.keywords && this.ysm.forceDefaultKeywords && (this.ysm.keywordCollection.length > 0)) {
                    this.config.isForcedKeywords = true;
                    this.ysm.searchType = this.ysm.forcedSearchType || this.ysm.searchType;
                    this.ysm.keywords = this.ysm.keywordCollection[ninemsn.utils.getRandomNumber(this.ysm.keywordCollection.length)];
                }
                else {
                    this.config.isForcedKeywords = false;
                };
                if (this.ysm.keywords) {
                    this.ysm.keywords = this.ysm.keywords.replace(/^\s+|\s+$/g, "").replaceAll("\\+", " ");

                    // everything should be ready so call ysm with params
                    var propList = { params: this.getParams() };
                    var keywords = this.getFilteredKeywords();
                    var searchType = this.ysm.searchType ? this.ysm.searchType : "sitesearch_" + JS_SITE;
                    var serveUrl = this.ysm.serveUrl ? escape(this.ysm.serveUrl) : escape(window.location.protocol + "//" + window.location.host + window.location.pathname);
                    serveUrl = serveUrl.replace(/\//g, "%2F");

                    var ysmUrl = "http://xml.west.msn.overture.com/d/search/p/msn/xml/en-au/v8/?Partner=" + this.ysm.partnerId
			            + "&Keywords=" + keywords
			            + "&serveUrl=" + serveUrl
			            + "&type=" + searchType
			            + "&start=" + this.ysm.start
			            + "&count1=" + this.ysm.count
			            + "&count2=" + this.ysm.count2
			            + "&count3=" + this.ysm.count3
			            + "&mkt=" + this.ysm.market
			            + "&adultFilter=" + this.ysm.adultFilter
			            + (this.ysm.additionalParams ? "&" + this.ysm.additionalParams : "")
			            + "&affilData=" + this.ysm.affilData;
			            
			        if(this.isDebug) {
                        nudm("[ninemsn.ysmGenerator.getSearchYsm] ysmUrl:<br/>" + ysmUrl);
			        };

                    // call ysm with callback function and params
                    Ninemsn.Global.ContentManager.GetContent("http://data.ninemsn.com.au/NHHttpTransfer/GetNHHttpTransfer.aspx?domain=xml.west.msn.overture.com&fetchURL=" + escape(ysmUrl), ninemsn.ysmCallback, propList);
                }
                else if (this.isDebug) {
                    nude("[ninemsn.ysmGenerator.getSearchYsm] No keyword!");
                }
            }
        }
        catch (e) {
            if (this.isDebug) {
                nude("[ninemsn.ysmGenerator.getSearchYsm] " + e);
            }
        }
    };

    /* get the required params and call ysm article pages */
    this.getArticleYsm = function(cointainerId) {
        try {
            this.cointainerId = cointainerId || this.containerId;

            // create ysm if content element is found
            var container = document.getElementById(this.containerId);
            if (container) {
                container.style.display = "none";

                // everything should be ready so call ysm with params
                var params = this.getParams();
                
                var source = this.ysm.source ? this.ysm.source : "msncom_au_js_ctxt";
                var serveUrl = this.ysm.serveUrl ? escape(this.ysm.serveUrl) : escape(window.location.protocol + "//" + window.location.host + window.location.pathname);
                serveUrl = serveUrl.replace(/\//g, "%2F");
                var siteType = "msn_" + (this.ysm.siteCategory ? this.ysm.siteCategory : (JS_MOOTER_CATEGORY_NAME ? JS_MOOTER_CATEGORY_NAME : ""));

                var ysmUrl = "http://cm.au.msn.overture.com/js_flat_1_0/"
			        + "?config=" + this.ysm.configId
                    + "&source=" + source
			        + "&type=" + siteType
			        + "&ctxtRotate=" + this.ysm.rotate
			        + "&ctxtId=" + siteType
                    + "&ctxtUrl=" + serveUrl
                    + "&mkt=" + this.ysm.market
			        + "&maxCount=" + this.ysm.count
    	            + (this.ysm.additionalParams ? "&" + this.ysm.additionalParams : "")
                    + "&keywordCharEnc=UTF8&outputCharEnc=UTF8";

			        if(this.isDebug) {
                        nudm("[ninemsn.ysmGenerator.getArticleYsm] ysmUrl: <br/>" + ysmUrl);
			        };

                // call ysm with callback function and params
                ninemsn.utils.loadData(ysmUrl, params.ysm.affilId);
                ninemsn.utils.runCallback(this.ysm.jsonId, ninemsn.ysmCallback, params, this.config.timeout, this.isDebug, ninemsn.ysmFailback);
            }
        }
        catch (e) {
            if (this.isDebug) {
                nude("[ninemsn.ysmGenerator.getArticleYsm] " + e);
            }
        }
    };

    /* return an array of params */
    this.getParams = function() {
        var params = {
            containerId:this.containerId,
            ysm:this.ysm,
            config:this.config,
            queryName:this.queryName,
            isDebug:this.isDebug
        };

        return params;
    };

    /* set keywords from query string */
    this.getFilteredKeywords = function() {
        var keywords = this.ysm.keywords;

        // check if there is quot in the keywrods
        var quot = '"';
        var startPos = keywords.indexOf(quot);
        if (startPos == -1) {
            quot = '%22';
            startPos = keywords.indexOf(quot);
        }

        // if this keywords has quot mark, get the first word only
        if ((startPos > -1) && (keywords.length > startPos + quot.length)) {
            startPos = startPos + quot.length;
            var endPos = keywords.indexOf(quot, startPos);

            endPos = endPos > -1 ? endPos : keywords.length;
            keywords = keywords.substring(startPos, endPos);
        }
        return keywords;
    };

    this.create(arguments);
    this.init();
};

/** 
* ysmAffilDataFailed is called when getting affilData through web service fails.
* It will call createYsm without affilId
* [arguments:1] = 0:params
*/
ninemsn.ysmGenerator.ysmAffilDataFailed = function(params) {
    params.ysm.affilId = undefined;
    ninemsn.ysmGenerator.createYsm(params);
};

/** 
k gets feed from ysm and generate sponsor links
 * [arguments:2] = 0:resultAds, 1:params
 */
ninemsn.ysmCallback = function() {

    /* construct ysmGenerator */
    this.create = function(args) {

        this.results = args[0];
        this.containerId;

        // article pages have only one argument
        var params = args.length == 1 ? this.results : args[1];
        if (params) {
            this.containerId = params.containerId;
            this.ysm = params.ysm;
            this.config = params.config;
            this.queryName = params.queryName;
            this.isDebug = params.isDebug;
         };
    };

    /* initialise this instance */
    this.init = function() {
        try {
            this.container = document.getElementById(this.containerId);

            // ads for article pages need to be converted
            var resultAds;
            if (this.ysm.jsonId) {
                resultAds = eval(this.ysm.jsonId);
                resultAds = this.convertAdsForArticle(resultAds);
            }
            else {
                resultAds = (this.results && this.results.HttpTransferResult && this.results.HttpTransferResult.searchresults && this.results.HttpTransferResult.searchresults.result) ? this.results.HttpTransferResult.searchresults.result : undefined;
            }

            this.execute(resultAds);
        }
        catch (e) {
            if (this.isDebug) {
                nude("[ninemsn.ysmCallback.init] " + e);
            }
        }
    };

    /* get the ads and put them into the container */
    this.execute = function(resultAds) {

        // if container and ads, render them into container
        if (this.container && resultAds) {
            // make branding div 
            var brandingDiv = document.createElement("div");
            brandingDiv.id = this.containerId + "_acon_branding";
            brandingDiv.className = "acon-branding";
            brandingDiv.innerHTML = this.config.brandingTitle;
            this.container.appendChild(brandingDiv);

            var adsDiv = this.container.appendChild(document.createElement("div"));
            adsDiv.id = this.containerId + "_acon_ads";
            adsDiv.className = "acon-ads";

            // get the ads from the start to the required count
            var currentCount = 0;
            var start = this.ysm.start <= 1 ? 0 : this.ysm.start;
            for (var i = start; (i < resultAds.length) && (currentCount < this.ysm.count); i++) {
                var ad = resultAds[i];
                if (ad.type == 1) {
                    currentCount++;
                    var isFirst = i == start;
                    var isLast = (i == resultAds.length - 1) || (currentCount == this.ysm.count);
                    adsDiv.appendChild(this.getAdDiv(ad, isFirst, isLast, brandingDiv));
                }
            }

            if (adsDiv && (adsDiv.innerHTML != "")) {
                this.container.style.display = "block";
            }
        }
        else if (!this.config.isForcedKeywords && this.ysm.forceDefaultKeywords && (this.ysm.keywordCollection.length > 0)) {
            this.config.isForcedKeywords = true;
            this.ysm.searchType = this.ysm.forcedSearchType || this.ysm.searchType;
            this.ysm.keywords = this.ysm.keywordCollection[ninemsn.utils.getRandomNumber(this.ysm.keywordCollection.length)];
			(new ninemsn.ysmGenerator(this.containerId, this.ysm, this.config, this.queryName)).execute();
        }
        else if (this.isDebug) {
            nude("[ninemsn.ysmCallback.execute] " + (this.container ? "No Ads are returned!" : "No container is found for '" + this.containerId + "'"));
        }
    };

    /* get div for each ad */
    this.getAdDiv = function(ad, isFirst, isLast, brandingDiv) {
        var adDiv = document.createElement("div");
        adDiv.className = "acon-ads-panel" + (isLast ? " last-panel" : "");
        adDiv.onclick = function() {
            window.open(this.url);
        };
        adDiv.url = ad.urlencode;

        var title = ad.title;
        var desc = ad.desc[0].value;
        var host = ad.url[0].value;

        // get image if not requested to hide it
        if (!this.config.hideImages) {
            // ignore errors from getting images
            try {
                adDiv.appendChild(this.getAdImage(title, desc, host));
            }
            catch (e) {
                if (this.isDebug) {
                    nude("[ninemsn.ysmCallback.getAdImage] " + e);
                }
            }
        }

        // truncate title and description
        title = title.length > this.config.titleLength ? title.substring(0, this.config.titleLength) + "..." : title;
        desc = desc.length > this.config.descLength ? desc.substring(0, this.config.descLength) + "..." : desc;

        // puit strong tag if requrested
        if (this.config.makeStrong && this.ysm.keywords) {
            title = title.replaceAll(this.ysm.keywords, "<strong>" + this.ysm.keywords + "</strong>", true);
            desc = desc.replaceAll(this.ysm.keywords, "<strong>" + this.ysm.keywords + "</strong>", true);
        }

        // get divs for title, description and sitehost
        var mainDiv = adDiv.appendChild(document.createElement("div"));
        mainDiv.className = "acon-ads-main";

        var titleDiv = mainDiv.appendChild(document.createElement("div"));
        titleDiv.className = "acon-title";
        var titleA = titleDiv.appendChild(document.createElement("a"));
        titleA.innerHTML = title;
        titleA.href = "javascript:void(null);";

        var descDiv = document.createElement("div");
        descDiv.className = "acon-description";
        descDiv.innerHTML = desc;

        var sitehostDiv = document.createElement("div");
        sitehostDiv.className = "acon-sitehost";
        sitehostDiv.innerHTML = host;

        mainDiv.appendChild(descDiv);
        mainDiv.appendChild(sitehostDiv);

        return adDiv;
    };

    /* return a div for image for ad */
    this.getAdImage = function(title, desc, host) {
        var imageDiv = document.createElement("div");
        imageDiv.className = "acon-ads-image";

        // get image from the provider
        var adImage = imageDiv.appendChild(document.createElement("img"));
        adImage.src = this.config.imageType == "brand"
			? GetIABrandImageDetails(this.ysm.keywords, host, "border=0", false)
			: GetIAProductImageDetails(this.ysm.keywords, title, desc, host, "border=0", false);

        // calculate the width from the image dimension
        if (adImage.height && adImage.width && (adImage.width != 0) && (adImage.height != 0)) {
            adImage.style.width = parseInt(adImage.width * this.config.adImageHeight / adImage.height) + "px";
        }
        adImage.style.height = this.config.adImageHeight + "px";

        return imageDiv;
    };

    /* convert ads from article pages to the right format */
    this.convertAdsForArticle = function(resultAds) {
        var ad;
        var index = 0;
        if (resultAds.length > 6) {
            ad = new Array();
            for (var i = 6; i < resultAds.length; i++) {
                var thisAd = {};
                thisAd.type = 1;

                thisAd.desc = new Array();
                thisAd.desc[0] = {}
                thisAd.desc[0].value = resultAds[i++];
                resultAds[i++];

                thisAd.urlencode = resultAds[i++];
                thisAd.title = resultAds[i++];

                thisAd.url = new Array();
                thisAd.url[0] = {}
                thisAd.url[0].value = resultAds[i++];

                ad[index++] = thisAd;
            }
        }
        else {
            ad = resultAds;
        }
        return ad;
    }

    this.create(arguments);
    this.init();
};

/** 
* ysmFailback is called when callback for article pages is failed.
* It will display error message for debug mode. Otherwise nothing.
* [arguments:1] = 0:params
*/
ninemsn.ysmFailback = function() {
    var params = arguments.length == 1 ? arguments[0] : arguments[1];
    if(params && params.isDebug) {
        nude("[ninemsn.ysmFailback] yamCallback failed!"
            + "<br/> - containerId: " + params.containerId
            + "<br/> - affilId: " + params.ysm.affilId
            + "<br/> - jsonId: " + params.ysm.jsonId
            + "<br/> - keywords: " + params.ysm.keywords);
    }
};

/*
 *   ninemsn.utils scope
 */

/** return the current date and time */
ninemsn.utils.getCurrentTime = function() {
    var days = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");

    var months = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

    var now = new Date();
    var day = now.getDay();
    var today = now.getDate();
    var sup = "";
    if (today == 1 || today == 21 || today == 31)
        sup = "st";
    else if (today == 2 || today == 22)
        sup = "nd";
    else if (today == 3 || today == 23)
        sup = "rd";
    else
        sup = "th";

    return days[day] + " " + today
		+ "<SUP>" + sup + "</SUP> "
		+ months[now.getMonth()] + " " + now.getFullYear()
		+ " " + now.getHours() + " : " + now.getMinutes();
};

/* display message on top or bottom of the page with remove bottom
* if option is an id of enelement, the element will have the message
* if option is true, it will add the message to top 
* otherwise, it will add the message to bottom
* also client info from userAgent and location can be included
*/
ninemsn.utils.displayMessage = function(message, onTop, parentId, includeClientInfo, title) {
    parentId = parentId || "body";
    title = title || "ninemsn message panel";
    var panelId = escape(title);

    // check it's alredy used before
    var messagePanel = document.getElementById(panelId);
    if (messagePanel) {
        messagePanel.innerHTML += '<div style="text-align:left;border-top:dashed 1px #000000;">' + message + '</div>';
    }
    else {
        // who's your parent?
        var parent;
        if (parentId.toLowerCase() == "body") {
            parent = document.getElementsByTagName("body")[0];
        }
        else if (parentId) {
            parent = document.getElementById(parentId);
        }

        //no parent, no child
        if (parent) {
            var heading = '<div style="height:24px;background-color:#1770ac;color:#cae9ec;">'
				+ '<div style="float:left;font-weight:bold;font-size:14px;">'
				+ title + " [" + ninemsn.utils.getCurrentTime() + ']</div>'
				+ '<div style="float:right;"><a href="javascript:void(null);" style="color:#ffffff;" onclick="'
				+ (parentId.toLowerCase() == 'body' ? 'document.getElementsByTagName(\'body\')[0]' : 'document.getElementById(\'' + parentId + '\')')
				+ '.removeChild(document.getElementById(\'' + panelId + '\'));">remove</a></div></div>';

            messagePanel = document.createElement("div");
            messagePanel.id = panelId;
            messagePanel.style.backgroundColor = "#cae9ec";
            messagePanel.style.color = "#000000";
            messagePanel.style.border = "solid 2px #000000";
            messagePanel.style.borderBottom = "solid 5px #000000";
            messagePanel.style.padding = "5px 5px 5px 5px";
            messagePanel.style.fontFamily = "arial";
            messagePanel.style.position = "absolute";
            messagePanel.style.top = "0px";
            messagePanel.style.right = "0px";
            messagePanel.style.width = "700px";
            messagePanel.style.opacity = 0.8;
	    	messagePanel.style.filter = "alpha(opacity=80)";
            messagePanel.style.zIndex = 9999;

            messagePanel.innerHTML = heading + '<div style="text-align:left;clear:both;">' + message + '</div>';
            if (onTop) {
                parent.insertBefore(messagePanel, parent.childNodes[0]);
            }
            else {
                parent.appendChild(messagePanel);
            }
        }
    }
};
/** shortcut to displayMessage */
var nudm = function(message, onTop, parentId, includeClientInfo, title) {
	ninemsn.utils.displayMessage(message, onTop, parentId, includeClientInfo, title);
};

/** display exception message */
ninemsn.utils.displayException = function(e, title, onBottom, errorPanelId, clientInfo, excludeObjectError) {
	var displayIt = e == "[object Error]" ? (excludeObjectError ? false : true) : true;

	if(displayIt) {
		var message =  e.name ? (e.name + " at " + e.lineNumber + " : " + e.message) : e;
		if(e && e.stack) {
			message += "<br/>stack: " + e.stack.replaceAll("@","<br/>@");
		}
		nudm(message, !onBottom, errorPanelId, clientInfo, title);
	}
};
/** shortcut to displayException */
var nude = function(e, title, onBottom, errorPanelId, clientInfo, excludeObjectError) {
	ninemsn.utils.displayException(e, title, onBottom, errorPanelId, clientInfo, excludeObjectError);
};

ninemsn.utils.getRandomNumber = function(max) {
	max = !isNaN(max) ? max : 0;
	return Math.round(max*Math.random()) % max;
};


/** return the argument on url as an array. args.param will return the value of param */
ninemsn.utils.getParamValue = function(paramName) {
    var query = window.location.href;
    var value;
    var startPos = query.indexOf(paramName + "=");
    if (startPos > -1) {
        startPos += paramName.length + 1;
        var endPos = query.indexOf("&", startPos + 1);
        if (endPos < 0) {
            endPos = query.length;
        }
        value = query.substring(startPos, endPos);
    }

    return value;
};

/** load the data object to head */
ninemsn.utils.loadData = function(url, id) {
    var head = document.getElementsByTagName("head")[0];
    var scriptHead = document.createElement("script");
    scriptHead.type = "text/javascript";
    scriptHead.src = url;

    // if head has this node already, remove it first
    if (id) {
        var current = document.getElementById(id);
        if (current && (current.parentNode == head)) {
            head.removeChild(current);
        }
        scriptHead.id = id;
    }

    head.appendChild(scriptHead);
};

/** run callback function with recursive call - validates response, if not valid retries until timeout */
ninemsn.utils.runCallback = function(validate, callback, params, timeout, isDebug, failback) {
    /* nothing if no validation condition */
    if (validate) {
        timeout = timeout ? parseInt(timeout) * 1000 : 3000;

        var validUntil = (new Date()).getTime() + timeout;
        var callbackTimer = window.setInterval(
			function() {
			    var call = false;
			    try {
			        call = eval(validate);

			        // if successful, call callback
			        // otherwise, if failback is defined, call failback
			        if (call) {
			            callbackTimer = clearInterval(callbackTimer);
			            callback(params);
			        }
			        else if ((new Date()).getTime() > validUntil) {
			            callbackTimer = clearInterval(callbackTimer);
			            if (failback) {
			                failback(params);
			            }
			            else if (isDebug) {
			                nude("[ninemsn.utils.runCallback] Time expired.", true);
			            }
			        }
			    }
			    catch (e) {
			        callbackTimer = clearInterval(callbackTimer);
			        if (failback) {
			            failback(params);
			        }
			        else if (isDebug) {
			            nude("[ninemsn.utils.runCallback-setInterval] " + e);
			        }
			    }
			}, 100
		);
    }
};
