/*
    Gannett - Sitelife Integration JavaScript API 

    This script if responsible communicating with USAToday and SiteLife servers, 
    to deliver custom SiteLife widgets.  These widgets include:
        - User Avatar
        - Comments (Comment form and paginated comment list)
        - Review Widget (Review form and paginated review List)
        - Article Reaction Count Control
        - Article Recommend Control
        - Article Discovery Controls

    Dependancies:
        - SiteLife Direct Access API
            - prototype
            - scriptaculous

    References to integrated technologies: 
        - SiteLife DAAPI    http://sitelifestage.usatoday.com/api/index.htm         
        - AJAX              http://en.wikipedia.org/wiki/Ajax_%28programming%29
        - AHAH              http://microformats.org/wiki/rest/ahah        
        - Pork iFrames      http://www.schizofreend.nl/Pork.Iframe/
        - JSON Transforms   http://goessner.net/articles/jsont/
        - Prototype         http://www.prototypejs.org/
        - Scriptaculous     http://wiki.script.aculo.us/scriptaculous/
 
   Created: 1/10/07 by Josh West of Amentra, Inc for USAToday.com
    Modified: 4/04/2007 by Kevin Meredith and Sophak Phou of Amentra, Inc for GMTI.
        - Added functionality specifically for GMTI purposes
        - Removed USAToday specific functionality.
    Modified: 4/20/2007 by Kevin Meredith
        - Added contentURL to getArticleLink function
        - Added comment/recommend count to Discovery Actions
        - Added decodeURI() function to Discovery Actions title
*/

var gsl = {
    
    /*************************************************************************/
    /* Site Configurations ***************************************************/
    enabled: true,
    sitelifeApiUrl: "",
    personaHrefEnabled: true,
    personaHrefURL: "",
    commentCountHrefEnabled: true,
    reviewCountHrefEnabled: true,
    recommendCountHrefEnabled: true,

    
    /*************************************************************************/
    /* Default Configuration *************************************************/
    linkLblUrl: new Array(),
    linkUrl: new Array(),
    linkUIDEnabled: new Array(),
    personaHref:" ",
    personaUserKey:" ",

    // Page Configuration Settings (modify on individual pages -or- in environment config)
    exceptionLogging: false,    // on/off - log gsl exceptions    
    apiLogging: false,          // on/off - log sitelife calls
    widgetLogging: false,       // on/off - log interactions with custom sitelife widgets
    Debug: 0,                   // on/off - if debugDiv exists display debugging info
    _updateArticle: false,      // DO NOT MODIFY!
    _keyUsed: false,
  
    /*************************************************************************/
    /* Fronts Controls *******************************************************/
    // Fronts Controls Environment Configuration
    requestsPerBatch: 12,
    
    // Fronts Controls Page Configuration
    discoveryAge: "2",    // number of days for discovery widgets
    
    /*************************************************************************/
    /* GMTI SiteLife Library Initialization **********************************/

    initialSetup: function(userID) {
	
        try {
            if(this.enabled==true) {
                if($("gslRating")) { this.getRatingControl(); }     // Scans for Rating
                if($("gslAvtPhoto")) { this.loadAvatar(userID); }   // Scans for Avatar
				if(typeof(contentID) != "undefined") { this.AddThisArticle(); }
                if(gsl.ArticleControls) { gsl.ArticleControls(); }  // Scans page for Article Controls
            }   
        } catch(e) {
            this.showException("initialSetup", e);
        }
    },

    /*************************************************************************/
    /* SiteLife User *********************************************************/
    
    getUserPhotoLink: function(pid, photo) {
        if(pid != "anonymous"){
            var personaHtml= "<img src='" + photo + "' alt='User Image'/>"; 
            gsl.personaHref = photo;
            if(gsl.personaHrefEnabled){
                var personaHtmlHref = "<a href='" + gsl.personaHrefURL + pid + "'>" +personaHtml+ "</a>";
                personaHtml = personaHtmlHref;
            }
            return personaHtml;
        }
        else return "";
    },

    getUserLoginLink: function(pid, photo) {
        if(pid != "anonymous"){
        var LoginHtml = "<table class='gmti_log'><div class='gmti_thumbnail'>";
            LoginHtml += "<tr><td class='gmti_thumbnail01' rowspan='"+gsl.linkUrl.length+1+"'>"+ gsl.getUserPhotoLink(pid, photo) +"</td></tr></div>";
            
            for(x = 0; x < gsl.linkUrl.length; x++)
            {
                if(gsl.linkUrl[x] != "")
                    LoginHtml += "<tr><td class='gmti_linkUrl0"+x+"'><a href='"+ gsl.linkUrl[x];
                if(gsl.linkUIDEnabled[x])
                    LoginHtml += pid;
                LoginHtml += "' >"+ gsl.linkLblUrl[x] +"</a></td></tr>";
            }
            LoginHtml+= "</table>";
            return LoginHtml;
        }
        else return "";
    },
               
    /*************************************************************************/
    /* Article - art *********************************************************/ 
    
    getArticleKey: function() {   
    /* need to know where they have their articleKey */ 
        var id = (typeof(contentID)!='undefined') ? contentID : null;
        if (id == null) {gsl.showDebug("No contentID found.  Returned null");}
        return id;
    },


    getArticleTitle: function() {
        // if usat.contentTitle is not set, then parse it out of the browser title bar
        var title= contentTitle || "";
        if(title == ""){
            title= document.title;   // Will need to strip off what ever comes in as the title
            title= title.split('#')[0];  
        }                   // strip off any #anchor/fragment
        return title;
    },

	getArticleLink: function(artId) {
        var linkURL = (typeof(contentURL) != 'undefined') ? contentURL : document.location.toString().split('#')[0];
        return linkURL;
    },
          
    // Using the 'section' discovery variable for content type (story, blog, photo, etc)   
    getArticleSection: function() {
        return new Section(this.getArticleKey().split(".")[3]);  
    },     
       
    // Using 'categories' discovery array for listing which news sections the article appears in 
    getArticleCats: function(cats) {
        if(!cats) {
            var sArtKey = gsl.getArticleKey().split(".");
            cats = new Array();
            for (x=4; x<sArtKey.length; x++) {
                cats[x-4] = sArtKey[x];
            }
        } else {
            cats= (cats && cats!='')? cats.split(".") : new Array();
        }
        var categories= new Array();            // SiteLife Category object array
        for (i=0; i<cats.length; i++) {
            categories[i]= new Category(cats[i]);
        }
        return categories;
    }, 

    _compareArticleInfo: function(article) {
        
        // Call UpdateArticleAction if no article info
        if(!article || (article && (!article.Section || article.Categories.length==0))) {
           return true;
        }   
        
        // Call UpdateArticleAction if section has changed
        var sec= this.getArticleSection();  
        if ( article && (article.Section && sec.Section && (article.Section.Name.toLowerCase() != sec.Section.Name))) {
            return true;
        }
        
        // Call UpdateArticleAction if categories have changed
        var cats= this.getArticleCats();  
        if ( article && article.Categories && article.Categories.length > 0) { 
            
            if (article.Categories.length != cats.length) {
                return true;
            }
            
            var i=0;
            for (i=0; i<article.Categories.length; i++) {
                if(cats[i].Category.Name.toLowerCase() != article.Categories[i].Name) {
                    return true;
                }  
            }
        } 
		 if ((typeof(contentTitle) != "undefined") && article && article.PageTitle && (article.Categories.length > 0)) { 
            if (article.PageTitle != contentTitle) {
                return true;
            }
        } 
	   
        return false;       
    },
       
    /*************************************************************************/
    /* Comments - com ********************************************************/
       
    getCommentCountControl: function(count, link) {
        var comCntCtl="";
        var strCount= gsl.niceNumber(count);
        var strLabel= gsl.commentLbl || "Comments";
        if (count==0) {
            strCount= "0";
            strLabel= gsl.NocommentLbl || "Comment";
        }
        comCntCtl+= "<span class='gslCommentsLink'>";
        if(gsl.commentCountHrefEnabled)
            comCntCtl+= "<a href='"+link+"' title='Go to comments' alt='Go to comments'>";
			
        comCntCtl+= "<span class='gslCommentsLabel'>"+strLabel+"</span>";
		if (count!=0){
        comCntCtl+= "<span class='gslCommentsCount'>("+strCount+")</span>";
		}
        if(gsl.commentCountHrefEnabled)
            comCntCtl+= "</a>";
        comCntCtl+= "</span>";
        
        return comCntCtl;        
    },
                 
    /*************************************************************************/
    /* Reviews - rev *********************************************************/ 
       
    getReviewCountControl: function(count, link) {    
        var revCntCtl="";
        var strCount= gsl.niceNumber(count);
        var strLabel= gsl.reviewLbl || "Reviews";
        if (count==0) {
            strCount= "0";
            strLabel= gsl.reviewLbl || "Review";
        } 
        revCntCtl+= "<span class='gslReviewsLink'>";
        if(gsl.reviewCountHrefEnabled)
            revCntCtl+= "<a href='"+link+"' title='Go to reviews' alt='Go to reviews'>";
        revCntCtl+= "<span class='gslReviewsLabel'>"+strLabel+"</span>";
        revCntCtl+= "<span class='gslReviewsCount'>("+strCount+")</span>";
        if(gsl.reviewCountHrefEnabled)
            revCntCtl+= "</a>";
        revCntCtl+= "</span>";                     
        
        return revCntCtl;        
    },
    
    /*************************************************************************/
    /* Recommend - rec *******************************************************/ 
    
    getRecommendCountControl: function(type, key, recCount, recommended) {
        var recHtml= "";

        if (key==null || key.split('.')[0]=="") {
            recHtml += "<span class='gslDisabledRecommendLink'>";
            recHtml += "<span class='gslRecommendLabel'>"+gsl.recommendLbl+"</span>"
            recHtml += "<span class='gslDisabledRecommendCount'>(0)</span>";
            recHtml += "</span>";    
        } else {
            if (recommended==true) {
                recHtml += "<span class='gslRecommended'>";
                recHtml += "<span class='gslRecommendLabel'>"+gsl.recommendedLbl+"</span>";
                recHtml += "<span class='gslRecommendedCount'>(" + gsl.niceNumber(recCount) + ")</span>";
                recHtml += "</span>";            
            } else {  
                var strCount= gsl.niceNumber(recCount);             
                if (recCount==0) {
                    strCount= "0";
                }
                recHtml += "<span id='gslRecommend:" + type + ":" + key + "'>"; 
                recHtml += "<span class='gslRecommendLink'>";
                if(gsl.recommendCountHrefEnabled)
                    recHtml += "<a href=\"javascript:void(\'Recommend\')\" title='Recommend this article' alt='Recommend this article' onclick=\"gsl.Recommend('" + type + "','" + key + "','" + recCount + "');\">";
                recHtml += "<span class='gslRecommendLabel'>"+gsl.recommendLbl+"</span>";
                recHtml += "<span class='gslRecommendCount'>(" + strCount + ")</span>";
                if(gsl.recommendCountHrefEnabled)
                    recHtml += "</a>";
                recHtml += "</span>";      
                recHtml += "</span>";
            }
        }
        return recHtml;
    },
   
    Recommend: function(type, key, recCount) {        
        var recKey= null;
        if (type=='comments') {
            recKey= new CommentKey(key);
        } else if (type=='reviews') {
            recKey= new ReviewKey(key);
        } else if (type=='articles') {
            recKey= new ArticleKey(key);
        } 
        
        var rb= new RequestBatch();	 
        rb.AddToRequest(new RecommendAction(recKey)); 
        this.sitelifeRequest(rb, "SubmitRecommend", this._recommendCallback);
        
        var recLink= $("gslRecommend:"+type+":"+key);
        if(recLink) {
            var num= parseInt(recCount,10);
            num += 1;
            recLink.innerHTML= this.getRecommendCountControl(type, key, num, true);
        }
    },
    
    _recommendCallback: function(res) {
        if(res.Messages.length > 0 && res.Messages[0].Message=="ok") {
            gsl.showDebug("Recommend Successful");  
        } else {
            gsl.showDebug("Recommend Failed: " + res.Messages[0].Message);
        }   
        
        // save responses page for debugging purposes (javascript:alert(gsl.lastRecommendRes.toJSONString().replace(/:{/g, ":\n{").replace(/},/g, "},\n"));)
        if (gsl.Debug && res.Responses) { gsl.lastRecommendRes= res.Responses; } 

    },
           
    /*************************************************************************/
    /* Rating ****************************************************************/        
    
    
    getRatingCountControl: function(ratValue, ratCount) {
        var ratHtml = "";
        ratHtml += "<span id=\"gslRatingControl\" class=\"gslTemplate\">";
        ratHtml += "<span class='gslRatingLabel'>Rating</span>";
        ratHtml += "<span class='gslRatingImage'>";
        ratHtml += "<img alt=\"\" src=" + this._getRatingImageUrl(ratValue) + " id=\"gslRatingStars\" border=\"0\">";
        ratHtml += "</span>";
        if (gsl.showNumOfRatingsFront) {
            ratHtml += "<span class='gslRatingTotal'>(" + ratCount + ")";
            ratHtml += "</span>";
        }
        ratHtml += "</span>";
        return ratHtml;
    },

    getRatingControl: function() {
        if (gsl.getArticleKey() == null ) {
            gsl.rateable = false;
            gsl.showUserRating = false;
            gsl.showNumOfRatings = false;
            gsl.buildRating("0", null, null);
        } else {
            if (gsl.showAvgB4Rate || gsl.showUserRating || gsl.showNumOfRatings) {
                var rb = new RequestBatch();
                rb.AddToRequest(new ArticleKey(gsl.getArticleKey()));
                gsl.sitelifeRequest( rb, "Retrieving Rating Control", this.ratingCB );
            } else {
                gsl.buildRating("0", null, null);
            }
        }
    },
    
    ratingCB: function (response) {
        if (response.Messages[0].Message == "ok") {
            if (response.Responses[0].Article != null ) {
                art = response.Responses[0].Article;
                var avgRating = (gsl.showAvgB4Rate) ? art.Ratings.AverageRating : "0";
                if (art.Ratings.CurrentUserRating == 0) {
                    if (gsl.showUserRating) {
                        gsl.showUserRating = false;
                    }
                } else {
                    gsl.rateable = false;
                }
                var userRating = art.Ratings.CurrentUserRating;
                var numRating = art.Ratings.NumberOfRatings;
                gsl.buildRating(avgRating, userRating, numRating);
            }
        } else {
            gsl.buildRating('0','0','0');
        }
    },

    buildRating: function(initialValue, userValue, numOfRatings) {
        var ratHtml = "";
        ratHtml += "<span id=\"ratingControl\" class=\"gslTemplate\">";
        ratHtml += "  <input id=\"gslRatingValue\" value=\"" + initialValue + "\" type=\"hidden\" />";
        ratHtml += "  <span id=\"gslRatingImage\">";
        if (gsl.rateable) {
            ratHtml += "    <img alt=\"\" src=" + this._getRatingImageUrl(initialValue) + " id=\"gslRatingStars\" ismap=\"ismap\" usemap=\"#gslRatingStarMap\" border=\"0\">";
            ratHtml += "  </span>";
            ratHtml += "  <map name=\"gslRatingStarMap\" style=\"display:inline\">";
            var i = 0;
            var ll = 0;
            var ul = 0;
            for (i=0;i < gsl.ratingScale; i++) {
                ll = (i * gsl.widthPerRating) - gsl.widthPerRating;
                ul = ((i+1) * gsl.widthPerRating) - gsl.widthPerRating;
                ratHtml += "  <area shape=\"rect\" coords=\"" + ll + ",0," + ul + ","+ gsl.heightOfRating + "\" onmouseover=\"gsl._fillRatingStar('gslRatingStars', 'gslRating', " + i + ");\" onmouseout=\"gsl._fillRatingStar('gslRatingStars', 'gslRating', -1);\" onclick=\"gsl._setRating('gslRating'," + i + ");\" />";
            }
            ratHtml += "  </map>";
        } else {
            ratHtml += "    <img alt=\"\" src=" + this._getRatingImageUrl(initialValue) + " id=\"gslRatingStars\" border=\"0\">";
            ratHtml += "  </span>";
        }
        if (gsl.showNumOfRatings) {
            ratHtml += "  <span id=\"gslRatingTotal\">(" + numOfRatings + ")";
            ratHtml += "  </span>";
        }
        if (gsl.showUserRating) {
            ratHtml += " <span id=\"gslUserRatingImage\">";
            ratHtml += "    <img alt=\"\" src=" + this._getRatingImageUrl(userValue) + " id=\"gslRatingStars\" border=\"0\">";
            ratHtml += " </span>";
        }    
        ratHtml += "</span>";
        document.getElementById("gslRating").innerHTML = ratHtml;
    },
      
    getRatingImage: function(rating) {
        var ratHtml= "<img alt='' src='" + this._getRatingImageUrl(rating) + "' border='0'>";
        return ratHtml;  
    },

    _getRatingImageUrl: function(rating) {
        if (rating < gsl.ratingScale) {
            var ratNum = (gsl.halfStars) ? parseInt(Math.round(rating))*5 : parseInt(Math.round(rating))*10;
            var starsUrl = (ratNum<10) ? this.ratingStarsUrl + "0" + ratNum + ".gif" : this.ratingStarsUrl + ratNum + ".gif";
        } else {
            var ratNum = (gsl.halfStars) ? parseInt(Math.round((gsl.ratingScale-1)))*5 : parseInt(Math.round(gsl.ratingScale))*10;
            var starsUrl = (ratNum<10) ? this.ratingStarsUrl + "0" + ratNum + ".gif" : this.ratingStarsUrl + ratNum + ".gif";
        }

        return starsUrl;
    },

    _fillRatingStar: function(ratingStars, ratingField, rating) {
        var ratStars= $(ratingStars);
        var ratField= $(ratingField);
        
        var oldRating= parseInt(ratField.value,10);
        var newRating= rating;
        
        if (newRating < 1 && oldRating >= newRating) { newRating = oldRating};
        
        if (newRating >=1 && newRating <= 9) {
            ratStars.src = this._getRatingImageUrl(newRating);
        } else {
            ratStars.src = this._getRatingImageUrl('0');
        }
    },

    _setRating: function(ratingField, rating) {
        var ratField = $(ratingField);
        ratField.value = rating;
        rb = new RequestBatch();
        rb.AddToRequest(new RateAction(new ArticleKey(gsl.getArticleKey()), parseInt(rating))); 
        gsl.sitelifeRequest(rb, "RatingAction", this._subRatingCB);
    },

    _subRatingCB: function(response) {
        if (response.Messages[0].Message == "ok") {
            var rb = new RequestBatch();
            rb.AddToRequest(new ArticleKey(gsl.getArticleKey()));
            gsl.sitelifeRequest(rb, "RePopulateRatingControl", gsl._updateRatingCB);
        }
    },

    _updateRatingCB: function(response) {
        if (response.Messages[0].Message == "ok") {
            if (response.Responses[0].Article != null ) {
                art = response.Responses[0].Article;
                var aveRating = art.Ratings.AverageRating;
                var userRating = art.Ratings.CurrentUserRating;
                var numRating = (gsl.showNumOfRatings) ? art.Ratings.NumberOfRatings : null;
                gsl.rateable = false;
                gsl.showUserRating = gsl.showUserRatingAfter;
                gsl.buildRating(aveRating, userRating, numRating);
            }
        }
    },    
              
    /*************************************************************************/
    /* AJAX Transport Functions **********************************************/
   
    sitelifeRequest: function(slBatch, action, callback) {

        // Add UpdateArticleAction to batch, if update article flag is set then 
        if (this._updateArticle==true) {
            var articleKey= this.getArticleKey();
            var articleLink= this.getArticleLink();
            var title= this.getArticleTitle();
            var section= this.getArticleSection();
            var cats= this.getArticleCats();
            slBatch.AddToRequest(new UpdateArticleAction(new ArticleKey(articleKey), articleLink, title, section,cats));
            gsl.showDebug("Updating Article:"+articleKey+" title:"+title+" URL:"+articleLink+" section:"+section+" cats:"+cats);
        }

        this.logSiteLife("gslRequest:"+action);
        
        var This= this;
        var callbackWrap= function(response) {
            try {
                gsl.logSiteLife("gslResponse:"+action);
                callback(response);
            } catch(e) {
                gsl.showException("SL Request Callback Wrapper", e);
            }
        };     
        try {    
            slBatch.BeginRequest(this.sitelifeApiUrl, callbackWrap); 
        } catch(e) {
            this.showException("SL Request", e);
        }
    },
    
    isSitelifeAvailable: function() {
        // check for the existence of a sitelife class 
        if(typeof(DiscoverArticlesAction)!='undefined') {
            return true;
        } else {
            return false;
        }    
    },
    
    logSiteLife: function(msg) {         
        gsl.showDebug(msg);
    },
    
    /*************************************************************************/
    /* Utility Functions *****************************************************/
  
    niceNumber: function(num) {
        num= num.toString();
        if(num.length<=3) {
            return (num=="")? "0" : num;
        } else {
            var niceNum= "";
            try {
                if(mod=(num.length%3)) {
                    niceNum= num.substr(0, mod)+",";
                }                
                for(i=0; i<=(num.length/3)-1; i++) {
                    if(i!=0) { niceNum= niceNum + ","; }
                    niceNum= niceNum + num.substr((3*i)+mod, 3);
                }
            } catch(e) {
                return num;
            }     
            return niceNum;
        }
    },
     
    /*************************************************************************/
    /* Debugging Functions ***************************************************/
    
    showDebug: function(debugtext) {
        if (this.Debug==1) {
            if($("debug"))
            {
                if(($("debug")).innerHTML == "")
                    ($("debug")).innerHTML += "<br /><br />DEBUG LOG<br />==========<br />";
                datestamp = new Date();
                ($("debug")).innerHTML += datestamp.toLocaleTimeString() +": "+ debugtext + "<br>";
            }
        }
    },
    
    showException: function(location, ex) {
        var msg= " ";
        if(ex && ex.name && ex.message) {
            msg= "Javascript Exception in " + location + ": " + ex.name + " - " + ex.message;
        } else {
            msg= "Error in " + location + " - " + ex;
        }
        this.showDebug(msg);
        
    },

    /*************************************************************************/
    /* Article Functions - art ***********************************************/ 
	 AddThisArticle: function(){
        var rb= new RequestBatch();
        rb.AddToRequest(new ArticleKey(gsl.getArticleKey()));
        try{
            gsl.sitelifeRequest(rb, "Add this article", this._loadATACallback);
        } catch(e) {
            this.showException("SL Request", e);
        }
    },
    
    _loadATACallback: function(result) {
        for (var i=0; i<result.Responses.length; i++) {
            var res= result.Responses[i];
            if(res.Article != null) { 
                gsl._updateArticle = gsl._compareArticleInfo(res.Article);
                if (gsl._updateArticle && gsl.updateOnLoad) {
                    var rb = new RequestBatch();
                    gsl.sitelifeRequest(rb, "UpdateArticle", gsl._upArtCB);
                }
            }
        }
    },
		
    ArticleControls: function() {   
        // 1. Find set of HTML elements with class "gslArticleControl" on the page. 
        // 2. Parse out Article or Discovery Widget info from the HTML element's id
        // 3. Build batch(es) of Article and Discovery requests
        // 
        // Article Controls:
        //      <div id="gslCtl|[ControlType]|[ArticleKey]" class="gslArticleControl"></div>
        //      Ex: <div id="gslCtl|comments|123456789.story" class="gslArticleControl"></div>
        // Article control element id breakdown - 
        //      gslCtl | [control type] | [article id]
        //      [ControlType] = comments, reviews, or recommend
        //      [ArticleId] = unique id of article (not containing a pipe |)
        // 
        // Discovery Widgets:
        //     <div id="gslCtl|[ControlType]|[Activity]|[Section]|[Categories]|[Index]" class="gslArticleControl"></div>
        //     Ex: <div id="gslCtl|discovery|Recent|story|money.life" class="gslArticleControl"></div>
        // Discovery widget element id breakdown -
        //     gslCtl | [ControlType] | [Activity] | [Section] | [Categories] | [Index]
        //     [ControlType]= discovery
        //     [Activity]   = Recent, Commented, Reviews, or Recommended
        //     [Section]    = article type - story, blog, etc.
        //     [Categories] = period deliminated article sections - news, money, travel, money.life, news.sports, etc.
        //     [Index]      = Index of discovery widget (valid index is 1 through 10 per discovery search)

        // 1. Find set of HTML elements with class "gslArticleControl" on the page. 
        var artCtls= document.getElementsByClassName("gslArticleControl");
        if (artCtls.length > 0) {
            var controls= new Array();
            var i=0;
            
            var reqBatch;  
            var ctlCount=0;
            for(i=0; i<artCtls.length; i++) {
                
                // 2. Parse out Article or Discovery Widget info from the HTML element's id
                var ctlIda= artCtls[i].id.split("|");   //split control id attribute by pipe delimiter
                
                var cid;
                var type="";
                // Will need to find gslCtl in all templates and switch to new name, gslCtl
                if (ctlIda[0]=='gslCtl' && ctlIda.length==3) { 
                    cid= ctlIda[2];
                    type= ctlIda[1];    // count or recommend
                } else if (ctlIda[0]=='gslCtl' && ctlIda.length==6) {
                    cid= ctlIda[2]+ctlIda[3]+ctlIda[4]; //activity + section + categories;
                    type= ctlIda[1];    // discovery
                } else {
                    this.showDebug("Malformed gslArticleControl Id (1)");
                }
                
                // if the article id "<articleNum>.<articleType>" is blank then 
                // clear the contents of the control and skip adding it to batch 
                if(cid.split(".")[0]=="") {
                    try {
                        // clear node contents
                        if (artCtls[i]) { artCtls[i].innerHTML= ""; }
                    } catch(e) { }
                    this.showException("Empty Article Id"); // log the issue in omniture
                    continue;   // skip the rest of the loop
                }            
                
                // 3. Build batch(es) of Article and Discovery requests 
                if(!controls[cid]) {                 
                    controls[cid]=cid;
                    ctlCount += 1;
                    
                    if(!reqBatch) {
                        reqBatch= new RequestBatch(); 
                    }
                    if (type=="comments" || type=="reviews" || type=="recommends" || type=="ratings") { 
                        this.showDebug("adding article control to batch: " + type + " cid:"+ cid);   
                        reqBatch.AddToRequest(new ArticleKey(cid));  
                    } else if (type=="discovery") {
                        var activity= ctlIda[2];
                        var section= ctlIda[3];
                        var categories= ctlIda[4];
                        var contribs= new Array(new UserTier("All"));
                        var maxIndex= this._findDiscoveryMaxIndex(activity, section, categories);
                        this.showDebug("adding discovery control to batch: " + type + " cid:"+ cid);   
                        reqBatch.AddToRequest(new DiscoverArticlesAction(new Array(new Section(section)), this.getArticleCats(categories), contribs, new Activity(activity), this.discoveryAge, maxIndex));    
                    } else {
                        this.showDebug("Malformed gslArticleControl Id (2) - type: " + type + " cid: "+cid);
                    }
                                 
                    if(ctlCount!=1 && (ctlCount%this.requestsPerBatch)==0) {
                        this.sitelifeRequest(reqBatch, "LoadArticleCtls", this._ArticleControlsCallback);     
                        reqBatch = null;
                    }
                }
            }
            
            if(ctlCount > 0 && (ctlCount%this.requestsPerBatch)!=0) {
                this.sitelifeRequest(reqBatch, "LoadArticleCtls", this._ArticleControlsCallback); 
            }
        }
    }, 

    _findDiscoveryMaxIndex: function(activity, section, categories) {
        // find max disovery widget index
        var j=1;
        for(j=1; j<=10; j++) {
            var discElem= $('gslCtl|discovery|'+activity+'|'+section+'|'+categories+'|'+j);
            if(!discElem) {
                return j-1;
            }
        }   
        return 10; 
    },

    _ArticleControlsCallback: function(result) {
        var j=0;
        var k=0;
        // Process Controls Successfully Retrieved
        for ( j=0; j<result.Responses.length; j++) {
            if (result.Responses[j].Article) {
                
                // Process Article Control
                var article= result.Responses[j].Article;
                gsl._processArticleControl(article.ArticleKey.Key, article);
                
            } else if (result.Responses[j].DiscoverArticlesAction) {
            
                // Process Discovery Widget
                var disovAction= result.Responses[j].DiscoverArticlesAction;
                var discArts= result.Responses[j].DiscoverArticlesAction.DiscoveredArticles;
                var k=0;
                for ( k=0; k<discArts.length; k++) {
                    var discov= discArts[k]; 
                    if (discov) {
                        gsl._processDiscoveryControl(discov, k+1, disovAction.SearchSections, disovAction.SearchCategories, disovAction.Activity.Name);
                    }
                }                
            } 
        } 
        
        // Process ArticlesKeys That Were Not Found
        for ( j=0; j<result.Messages.length; j++) {
            // When ArticleKey is not found, this is returned as a message
            // "Unable to find data on request:[ArticleRequest] ArticleKey = [RequestedArticleKey]; Key = [RequestedArticleKey]"
            var msg="";
            article= {}; // clear out article
            // If the msg is the unable to find message
            if( (msg=result.Messages[j].Message) && msg.substr(0,14)=="Unable to find") {
                // get the article key
                var key=""
                try {
                    // No article record -> Populate article control anyway
                    key= msg.split("= [")[1].split("];")[0];
                    gsl._processArticleControl(key, article);
                    
                } catch(e) {
                    gsl.showException("Unable to extract ArticleKey from batch", e);
                    continue;
                }
            }
        }  
        if (gsl.Debug && result.Responses) { gsl.lastArtCtlRes= result.Responses; }     
    },

    _processArticleControl: function(key, article) {
        // Populate all controls that coorespond to the SiteLife article object <acticle>    
        this.showDebug("processing article control - key: "+key);    
        var revCtl;
        if (revCtl=$('gslCtl|reviews|'+key)) {
            var revCnt= (article.Reviews)? article.Reviews.NumberOfReviews : 0;    // get review count 
            var revLink="";
            if (typeof(gslReviewLinks)!='undefined') {
                revLink= (link=gslReviewLinks[key])? link: gsl.getArticleLink(key);
                revLink += "#gslPageReturn";
            } else {
                revLink= gsl.getArticleLink(key) + "#gslPageReturn";
            }        
            revCtl.innerHTML= gsl.getReviewCountControl(revCnt, revLink); 
        }
        //#gslPageReturn is the anchor to link to on the page
        var comCtl;
        if (comCtl=$('gslCtl|comments|'+key)) {
            var comLink="";   
            var comCnt= (article.Comments)? article.Comments.NumberOfComments : 0;    // get comment count                  
            if (typeof(gslComCountOffset)!='undefined') {
                comCnt = parseInt(comCnt) + parseInt((offset=gslComCountOffset[key])? offset: 0); // add offset to review count (typepad legacy support)
            }
            if (typeof(gslCommentLinks)!='undefined') {
                comLink= (link=gslCommentLinks[key])? link: gsl.getArticleLink(key);
                comLink += "#gslPageReturn";
            } else {
                comLink= gsl.getArticleLink(key) + "#gslPageReturn";
            }
            comCtl.innerHTML= gsl.getCommentCountControl(comCnt, comLink);                     
        }
        
        var recCtl;
        if (recCtl=$('gslCtl|recommends|'+key)) {
            var recCount=0; 
            var recd=false;
            if (article.Recommendations) {
                recCount= article.Recommendations.NumberOfRecommendations;
                recd= (article.Recommendations.CurrentUserHasRecommended=="True")? true : false;
            }
            recCtl.innerHTML= gsl.getRecommendCountControl('articles', key, recCount, recd);
        }
        
        var ratCtl;
        if (ratCtl=$('gslCtl|ratings|'+key)) {
            var ratCount=0; 
            var ratValue=0;
            if (article.Ratings) {
                ratCount= article.Ratings.NumberOfRatings;
                ratVal = article.Ratings.AverageRating;
            }
            ratCtl.innerHTML= gsl.getRatingCountControl(ratCount, ratVal);
        }

    },

    _processDiscoveryControl: function(article, index, sections, categories, activity) {
        // Populate the discovery widget
        var strSections= this._getNameValues(sections);
        var strCats= this._getNameValues(categories);
        
        this.showDebug("processing article: "+article.ArticleKey.Key+" index: "+index+" sections: "+strSections+" cats: "+categories+" activity: "+activity);
        
        var ctlNode= $('gslCtl|discovery|'+activity+'|'+strSections+'|'+strCats+'|'+index);
        if (ctlNode) {
            var key= article.ArticleKey.Key;
            var title= (article.PageTitle)? article.PageTitle : activity+' '+strSections+' '+strCats;
            var link= (article.PageUrl)? article.PageUrl : this.getArticleLink(key);
             if (activity == "Commented") 
                var number = article.Comments.NumberOfComments;
            else if (activity == "Rated")
                var number = article.Ratings.NumberOfRatings;
            else if (activity == "Recommended")
                var number = article.Recommendations.NumberOfRecommendations;
            else if (activity == "Reviewed")
                var number = article.Reviews.NumberOfReviews;
            else 
                var number = null;
            ctlNode.innerHTML= this.getDiscoveryLinkControl( index, title, link, activity, number);

        }
    },

    _getNameValues: function(arr, delim) {
        var valArray= new Array();
        var i=0;
        for (i=0; i<arr.length; i++) {
            valArray[i]= arr[i].Name;
        }
        return valArray.join(delim);
    },

    getDiscoveryLinkControl: function(index, title, href, type, count) {
        var discCtl="";
      
        discCtl+= "<span class='gslDiscoveryControl'>";
        discCtl+= " <span class='gslDiscoveryIndex'>"+index+".</span>";
        discCtl+= " <span class='gslDiscoveryLink'>";
        discCtl+= "  <span class='gslDiscovery" + type + "'>";
        discCtl+= "   <a href='"+href+"' title='Go to article' alt='Go to article'>"+decodeURI(title)+"</a>";
        if (count != null) {discCtl+= "    <span class='gslDiscoveryCount'>("+count+")</span>";}
        discCtl+= "  </span>";
        discCtl+= "  <div class='gslDiscoverySeparator'></div>";
        discCtl+= " </span>";
        discCtl+= "</span>";
        
        return discCtl;  
    },
    
    /*************************************************************************/
    /* SiteLife Thumbnail Functions ******************************************/
    
    getUserAvatarAddress: function(){
        var rb= new RequestBatch();
        rb.AddToRequest(new UserKey());
        try{
            gsl.sitelifeRequest(rb, "LoadAvatarAddress", this._loadUAACallback);
        } catch(e) {
            this.showException("SL Request", e);
        }
    },
    
    _loadUAACallback: function(result)
    {
        for (var i=0; i<result.Responses.length; i++) {
            var res= result.Responses[i];
            if (res.User != null) {
                var user=res.User;
                gsl.personaUserKey = user.UserKey.Key;
                gsl.personaHref = user.AvatarPhotoUrl;
            }
        }
    },
    
    loadAvatar: function(key) {      
            gsl._keyUsed = (key) ? true : false;
            var rb= new RequestBatch();
            var artKey = gsl.getArticleKey();
            if (artKey!=null) { rb.AddToRequest(new ArticleKey(artKey)) }
            if(key){rb.AddToRequest(new UserKey(key));}
            else{   rb.AddToRequest(new UserKey());}
            try {
                gsl.sitelifeRequest(rb, "LoadAvatar", this._loadAvatarCallback);
            } catch(e) {
                this.showException("SL Request", e);
            }
    },

    _loadAvatarCallback: function(result) {
        for (var i=0; i<result.Responses.length; i++) {
            var res= result.Responses[i];
            if (res.User != null) {
                var user= res.User;
                // populate avatar and display
                gsl.personaUserKey = user.UserKey.Key;
                if (gsl._keyUsed) 
                    gsl.populateLinks(user.UserKey.Key, user.AvatarPhotoUrl);
                else
                    gsl.populateAvatar(user.UserKey.Key, user.AvatarPhotoUrl);
            } else if(res.Article != null) { 
                gsl._updateArticle = gsl._compareArticleInfo(res.Article);
                if (gsl._updateArticle && gsl.updateOnLoad) {
                    var rb = new RequestBatch();
                    gsl.sitelifeRequest(rb, "UpdateArticle", gsl._upArtCB);
                }
            }
        }
    },

    _upArtCB: function(response) {
        if (response.Messages[0].Message != "ok") 
            showDebug("SiteLife Error: "+response.Messages[0].Message);
    },

    populateAvatar: function(pid, photo) {
        if($("gslAvtPhoto"))
           $("gslAvtPhoto").innerHTML = gsl.getUserPhotoLink(pid, photo);
    }, 
    populateLinks: function(pid, photo) {
        if($("gslAvtPhoto"))
           $("gslAvtPhoto").innerHTML = gsl.getUserLoginLink(pid, photo);
    }
};
