/////////////////////////////////////////////////////////////////////
//
// MASTER CLASS
//
/////////////////////////////////////////////////////////////////////
function leaderboardManager(htmlContainerDiv) {
    this.targetDiv = htmlContainerDiv;  //This is the div that the generated HTML will be dumped into.
    this.entries = new Array();         //This is the array of leaderboard entries.
    this.allEntries = null;             //This is the array used when the user selects a specific car type.
    this.entriesPerPage = 25;            //This is the number of entries that show up per page.
    this.curClassFilter = "all";        //This is the filter that will only show certain cars if a user has selected a specific class/type.
    this.midSpanStart = 0;
    this.midSpanEnd = 0;
    
    this.fillLeaderboard = GenerateLeaderboardHTML;
    this.buildPageLinks = GeneratePageLinkHTML;
    this.filterByClass = FilterArrayByCar;
    this.sortByName = SortArrayByName;
    this.sortByComments = SortArrayByComments;
    this.sortByMPG = SortArrayByMPG;    
	this.sortByRank = SortArrayByRank;
    
    //Sorting variables.
    this.currentlySortedBy = "mpg";
    this.mpgSortAsc = false;
    this.rankSortAsc = false;
    this.nameSortAsc = true;
    this.commentsSortAsc = false;
}

/////////////////////////////////////////////////////////////////////
//
// CLASS METHODS
//
/////////////////////////////////////////////////////////////////////

var firstTimeThrough = true;

function GenerateLeaderboardHTML(pageNum) {	            
    var startingIndex = ((parseInt(pageNum) - 1) * this.entriesPerPage);
    var endingIndex = this.entriesPerPage * pageNum;
    var penaltyBoxShown = false;
    
    var listContainer = document.getElementById(this.targetDiv);
    //Make sure that this container doesn't have anything in it.
    var numChildren = listContainer.childNodes.length
    for(var c=0; c<numChildren; c++) {
        listContainer.removeChild(listContainer.lastChild);
    }
    
    //We need to push all of the penalty box entries to the back.
    var tempArray = new Array();
    for(var p=0; p<this.entries.length; p++) {
        if(this.entries[p].inPenaltyBox) {
            tempArray.push(this.entries[p]);
            this.entries.splice(p,1);
            p=-1;
        }
    }
    for(var a=0; a<tempArray.length; a++) {
        this.entries.push(tempArray[a]);
    }
    
	var pentaltyBoxCount = 1;
	
	var $ = jQuery;

    for(var i=startingIndex; i<endingIndex; i++) {
        if(this.entries[i] != null) {
            //If this user is in the penalty box and the row hasn't been shown yet, show it.
            if(this.entries[i].inPenaltyBox && !penaltyBoxShown) {
                var penaltyBoxTR = document.createElement("tr");
                var penaltyBoxTD = penaltyBoxTR.appendChild(document.createElement("td"));
                
				if($.browser.msie) jQuery(penaltyBoxTD).addClass('penaltyBox');
				else penaltyBoxTD.setAttribute("class", "penaltyBox");
				
				if($.browser.msie) jQuery(penaltyBoxTD).attr({colSpan:5});
                else penaltyBoxTD.colSpan = "5";
                
				penaltyBoxTD.innerHTML = "<span class='right'><a id='ls_link' href='/wp-content/themes/volkswagen/tdi/misc/rules-details.php?width=600&amp;height=400&amp;inlineId=copyright-info'>DETAILS</a></span><span class='left'>PENALTY BOX: If you're going to compete, you have to play by the rules.</span>";
				
                listContainer.appendChild(penaltyBoxTR);
                penaltyBoxShown = true;
            }
            
            var listingTR = document.createElement("tr");
            listingTR.id = this.entries[i].html.mainTRid;
            
            if ($.browser.msie) {
				jQuery(listingTR).addClass(this.entries[i].css.mainTR);
				if(this.entries[i].inPenaltyBox){
					jQuery(listingTR).addClass("inPenaltyBox");
				}
			}else {
				listingTR.setAttribute("class", this.entries[i].css.mainTR + (this.entries[i].inPenaltyBox ? " inPenaltyBox" : ""));
			}
			
            var rankCell = listingTR.appendChild(document.createElement("td"));
            if(this.entries[i].inPenaltyBox) {
				if(firstTimeThrough){
					this.entries[i].rank = pentaltyBoxCount;
					pentaltyBoxCount ++;
				}
                
				if($.browser.msie) jQuery(rankCell).addClass('rankRed pbox');
				else rankCell.setAttribute("class", "rankRed pbox");
            } else {
				if(firstTimeThrough){
					this.entries[i].rank = (i+1);
				}
                
				if($.browser.msie) jQuery(rankCell).addClass('rank');
				else rankCell.setAttribute("class", "rank");
            }
            rankCell.innerHTML = "<strong>" + this.entries[i].rank + "</strong>";
            
            var profileCell = listingTR.appendChild(document.createElement("td"));
            
			if(this.entries[i].inPenaltyBox) {
				if($.browser.msie) jQuery(profileCell).addClass('n pbox');
				else profileCell.setAttribute("class", "n pbox");
			}else{
				if($.browser.msie) jQuery(profileCell).addClass('n');
				else profileCell.setAttribute("class", "n");
			}
			
            profileCell.innerHTML = this.entries[i].profileLogin;
            
            var carInfo = listingTR.appendChild(document.createElement("td"));
			if (this.entries[i].inPenaltyBox) {
				if ($.browser.msie) jQuery(carInfo).addClass('car-info pbox');
				else carInfo.setAttribute("class", "car-info pbox");
			}else{
				if ($.browser.msie) jQuery(carInfo).addClass('car-info');
				else carInfo.setAttribute("class", "car-info");
			}
            
			carInfo.innerHTML = this.entries[i].carInfo;
            
            var comments = listingTR.appendChild(document.createElement("td"));
            if (this.entries[i].inPenaltyBox) {
				if ($.browser.msie) jQuery(comments).addClass('comments pbox-comments');
				else comments.setAttribute("class", "comments pbox-comments");
			}else{
				if ($.browser.msie) jQuery(comments).addClass('comments normal-comments');
				else comments.setAttribute("class", "comments normal-comments");
			}
            comments.innerHTML = this.entries[i].numComments; //"<img src=\"" + TEMPLATE_URL + "/img/comments-white.png\" /> " +
            
            var mpgCell = listingTR.appendChild(document.createElement("td"));
            if(this.entries[i].inPenaltyBox) {
				if($.browser.msie) jQuery(mpgCell).addClass('mpgRed pbox');
				else mpgCell.setAttribute("class", "mpgRed pbox");
            } else {
				if($.browser.msie) jQuery(mpgCell).addClass('mpg');
				else mpgCell.setAttribute("class", "mpg");
            }
            mpgCell.innerHTML = this.entries[i].MPG;
            
            var rankingsTR = document.createElement("tr");
            
			if($.browser.msie) jQuery(rankingsTR).addClass('rankings-profile');
			else rankingsTR.setAttribute("class", "rankings-profile");
			
            if(i != startingIndex) {
				if($.browser.msie) jQuery(rankingsTR).hide();
				else rankingsTR.setAttribute("style", "display:none;");
            }
            
            var mainCell = rankingsTR.appendChild(document.createElement("td"));
            
			if($.browser.msie) jQuery(mainCell).attr({colSpan:5});
			else mainCell.colSpan = "5";
			
            mainCell.innerHTML = "       <div class=\"rankings-panel content-callout clearfix\">\n" + 
					            (this.entries[i].isGuinnessUser ? "<a style=\"float:left;\" >" : "               <a style=\"float:left;cursor:pointer;\" href=\"" + this.entries[i].profileLink + "\">") + 
					            "                <div class=\"photo rankings-panel-fb-profile-image\" style=\"background-image: url(" + this.entries[i].profileImage + ");\"></div>\n" + 
					            "               </a>\n" + 
					            "               <div class=\"rankings-panel-inside\">\n" + 
					            (this.entries[i].isGuinnessUser ? "" : "               <a href=\"" + this.entries[i].profileLink + "\" class=\"alignrightplain fwd\">View Profile</a>") + 
					            "               <h2 class=\"n tight\">" + (this.entries[i].isGuinnessUser ? "" : "<a href=\"" + this.entries[i].profileLink + "\">") + this.entries[i].fullName + (this.entries[i].isGuinnessUser ? "" : "</a>") + "</h2>\n" + 
						        "	                <p class=\"plain small\">" + this.entries[i].location + "</p>\n" + 
						        "	                <div class=\"data\">\n" + 
						        "		                <div class=\"mpg-badge\"><span class=\"accessibility\">MPG:</span> " + this.entries[i].MPG + "</div>\n" + 
						        "		                <ul class=\"kv small stats\">\n" + 
						        "			                <li>\n" + 
						        "				                <strong class=\"key\">Mileage:</strong>\n" + 
						        "				                <span class=\"value\">" + this.entries[i].mileage + "</span>\n" + 
						        "			                </li>\n" + 
						        "			                <li>\n" + 
						        "				                <strong class=\"key\">Tire Pressure:</strong>\n" + 
						        "				                <span class=\"value\">" + this.entries[i].tirePressure + "</span>\n" + 
						        "			                </li>\n" + 
						        "			                <li>\n" + 
						        "				                <strong class=\"key\">Tire Size:</strong>\n" + 
						        "				                <span class=\"value\">" + this.entries[i].tireSize + "</span>\n" + 
						        "			                </li>\n" + 
						        "		                </ul>\n" + 
						        "	                </div>\n" + 
						        "	                <div class=\"small\">\n" + 
						        "		                <strong class=\"car alignleftplain\">" + this.entries[i].carInfo + "</strong>\n" + 
						        (this.entries[i].isGuinnessUser ? "" : "		                <p class=\"plain textalignright\"><a class=\"secondary\" href=\"" + this.entries[i].profileLink + "\">" + this.entries[i].html.commentDesc + "</a></p>\n") + 
						        "	                </div>\n" + 
						        "               </div><!--/rankings-panel-inside-->\n" + 
					            "            </div><!--/rankings-panel-->\n";
    					        
            listContainer.appendChild(listingTR);
            listContainer.appendChild(rankingsTR);
        }
    }
    
    //This is a call to an external function held in the tdi.js file.
    //It will set up the accordian behavior on the leaderboard listings.
    setLeaderboardAccordian();
    
    //Now we need to build out the paging.
    this.buildPageLinks(pageNum);
    firstTimeThrough = false;
    
    cb_init("#ls_link");
}                                               

function GeneratePageLinkHTML(curPage) {
    var numPages = new Number(Math.ceil(this.entries.length / this.entriesPerPage));
    var pageLinkTable = "<div class=\"lbpagination\"><p>";
    
    //Figure out which pages should be in the middle span.
    if(this.midSpanStart == 0) {
        this.midSpanStart = 2;
        if(numPages <= 5) {
            this.midSpanEnd = (numPages-1);
        } else {
            this.midSpanEnd = 4;
        }
    } else {
        //The span values have already been set.  
        //If the current page is greater than 2 and less than the total number of pages minus one, 
        //then set the span to one less and one more than the current page.
        //This will ensure that the middle span always follows the current page, but that it doesn't repeat the first or last page.
        if(curPage > 2 && curPage < (numPages - 1)) {
            this.midSpanStart = parseInt(curPage) - 1;
            this.midSpanEnd = parseInt(curPage) + 1;
        } else if(curPage <= 2) {
            this.midSpanStart = 2;
            if(numPages <= 5) {
                this.midSpanEnd = (numPages-1);
            } else {
                this.midSpanEnd = 4;
            }
        } else if(curPage >= (numPages-1)) {
            this.midSpanStart = numPages - 3;
            this.midSpanEnd = numPages - 1;
        }
        
        //Make sure that there's no way for the first or last page to repeat.
        if(this.midSpanStart <= 1)
            this.midSpanStart = 2;
        if(this.midSpanEnd >= numPages) 
            this.midSpanEnd = numPages - 1;
    }
    
    //Build out the left arrow logic        
 	if(curPage > 1) {
		pageLinkTable += "<span><a class=\"newer\" href=\"javascript:lbManager.fillLeaderboard(" + (curPage - 1) + ");\">PREVIOUS</a></span><span><span class=\"pipe\"></span></span>";
	} else {
		//pageLinkTable += "<span><a class=\"newer\" href=\"#\">PREVIOUS</a></span><span><span class=\"pipe\"></span></span>"; 
	}
    //pageLinkTable += "<td class=\"pageCell\">" + (curPage > 1 ? "<a href=\"javascript:lbManager.fillLeaderboard(" + (curPage - 1) + ");\">" : "") + "&lt;" + (curPage > 1 ? "</a>" : "") + "</td>";
    
    //Page 1 will always be shown.         
	if(curPage != 1) {
		pageLinkTable += "<span><a href=\"javascript:lbManager.fillLeaderboard(1);\">1</a></span>" + (numPages == 1 ? "" : "<span><span class=\"pipe\"> </span></span>"); 
	} else {
		pageLinkTable += "<span><a class=\"active-page\" href=\"javascript:void(0);\">1</a></span>" + (numPages == 1 ? "" : "<span><span class=\"pipe\"> </span></span>"); 
	}
    //pageLinkTable += "<td class=\"pageCell\">" + (1 == parseInt(curPage) ? "<strong>1</strong>" : "<a href=\"javascript:lbManager.fillLeaderboard(1);\">1</a>") + "</td>";
    
    //If the span start is greater than 2, then put the ellipse here.
    if(this.midSpanStart > 2) {   
		pageLinkTable += "<span><a href=\"javascript:lbManager.fillLeaderboard(" + (curPage - 3) + ");\">...</a></span><span><span class=\"pipe\"> </span></span>";
        //pageLinkTable += "<td class=\"pageCell\"><a href=\"javascript:lbManager.fillLeaderboard(" + (curPage - 3) + ");\">...</a></td>";
    }
    
    //Fill in the middle pages based on the starting and ending span values.
    for(var j=this.midSpanStart; j<=this.midSpanEnd; j++) {   
		pageLinkTable += "<span>" + (j == parseInt(curPage) ? "<a class=\"active-page\" href=\"javascript:void(0);\">" + j + "</a>" : "<a href=\"javascript:lbManager.fillLeaderboard(" + j + ");\">" + j + "</a>") + "</span><span><span class=\"pipe\"> </span></span>";
        //pageLinkTable += "<td class=\"pageCell\">" + (j == parseInt(curPage) ? "<strong>" + j + "</strong>" : "<a href=\"javascript:lbManager.fillLeaderboard(" + j + ");\">" + j + "</a>") + "</td>";
    }
    
    //If the span end is less than the total number of pages minus one, then put the ellipse here.
    if(this.midSpanEnd < (numPages-1)) {    
		pageLinkTable += "<span><a href=\"javascript:lbManager.fillLeaderboard(" + (curPage + 3) + ");\">...</a></span><span><span class=\"pipe\"> </span></span>";
        //pageLinkTable += "<td class=\"pageCell\"><a href=\"javascript:lbManager.fillLeaderboard(" + (curPage + 3) + ");\">...</a></td>";
    }
    
    //The last page will always be shown, unless it's 1.
    if(numPages > 1) {      
		pageLinkTable += "<span>" + (numPages == parseInt(curPage) ? "<a class=\"active-page\" href=\"javascript:void(0);\">" + numPages + "</a>" : "<a href=\"javascript:lbManager.fillLeaderboard(" + numPages + ");\">" + numPages + "</a></span><span><span class=\"pipe\"> </span></span>");  
        //pageLinkTable += "<td class=\"pageCell\">" + (numPages == parseInt(curPage) ? "<strong>" + numPages + "</strong>" : "<a href=\"javascript:lbManager.fillLeaderboard(" + numPages + ");\">" + numPages + "</a>") + "</td>";
    }
    
    //Build out the right arrow logic     
	if(curPage < numPages) {
		pageLinkTable += "<span><a class=\"older\" href=\"javascript:lbManager.fillLeaderboard(" + (curPage + 1) + ");\">NEXT</a></span>";
	} else {
		//pageLinkTable += "<span><a class=\"older\" href=\"#\">NEXT</a></span>"; 
	}
    //pageLinkTable += "<td class=\"pageCell\">" + (curPage < numPages ? "<a href=\"javascript:lbManager.fillLeaderboard(" + (curPage + 1) + ");\">" : "") + "&gt;" + (curPage < numPages ? "</a>" : "") + "</td>";
    
    pageLinkTable += "</p></div>";
    jQuery("#pageLinks").html(pageLinkTable);
}

function SortArrayByName() {
    //If the user is already sorting by this field, toggle the ascending/descending sort.
    //If it isn't, just use the current setting.
    if(this.currentlySortedBy == "name") {
        //The user is already sorting by name.  Toggle the current sort setting.
        this.nameSortAsc = !this.nameSortAsc;
    } else {
        this.currentlySortedBy = "name";
    }
    
    if(this.nameSortAsc) {
        this.entries.sort(sortNameAsc);
    } else {
        this.entries.sort(sortNameDesc);
    }
    
    //Refill the leaderboard
    this.fillLeaderboard(1);
}

function SortArrayByComments() {
    //If the user is already sorting by this field, toggle the ascending/descending sort.
    //If it isn't, just use the current setting.
    if(this.currentlySortedBy == "comments") {
        //The user is already sorting by name.  Toggle the current sort setting.
        this.commentsSortAsc = !this.commentsSortAsc;
    } else {
        this.currentlySortedBy = "comments";
    }
    
    if(this.commentsSortAsc) {
        this.entries.sort(sortCommentsAsc);
    } else {
        this.entries.sort(sortCommentsDesc);
    }
    
    //Refill the leaderboard
    this.fillLeaderboard(1);
}

function SortArrayByMPG() {
    //If the user is already sorting by this field, toggle the ascending/descending sort.
    //If it isn't, just use the current setting.
    if(this.currentlySortedBy == "mpg") {
        //The user is already sorting by name.  Toggle the current sort setting.
        this.mpgSortAsc = !this.mpgSortAsc;
    } else {
        this.currentlySortedBy = "mpg";
    }
    
    if(this.mpgSortAsc) {
        this.entries.sort(sortRankAsc);
    } else {
        this.entries.sort(sortRankDesc);
    }
    
    //Refill the leaderboard
    this.fillLeaderboard(1);
}    

function SortArrayByRank() {
    //If the user is already sorting by this field, toggle the ascending/descending sort.
    //If it isn't, just use the current setting.
    if(this.currentlySortedBy == "rank") {
        //The user is already sorting by name.  Toggle the current sort setting.
        this.rankSortAsc = !this.rankSortAsc;
    } else {
        this.currentlySortedBy = "rank";
    }
    
    if(this.rankSortAsc) {
        this.entries.sort(sortRankAsc);
    } else {
        this.entries.sort(sortRankDesc);
    }
    
    //Refill the leaderboard
    this.fillLeaderboard(1);
}

function FilterArrayByCar(carType) {
    this.entries = this.allEntries.slice();
    if(carType != "all") {
        var numEntries = this.entries.length;
        for(var i=(numEntries-1); i>=0; i--) {
            switch(this.curClassFilter) {
                case "classic":
                    //Pull the year from the type.
                    var carStr = new String(this.entries[i].carType);
                    var carYear = new Number(carStr.substr(0, 4));
                    if(carYear >= 2009) {
                        this.entries.splice(i,1);
                    }
                    break;
                default:
                    if(carType != this.entries[i].carInfo) {
                        this.entries.splice(i,1);
                    }
                    break;
            }
        }
    }

    switch(this.currentlySortedBy) {
        case "name":
            this.nameSortAsc = !this.nameSortAsc;
            this.sortByName();
            break;
        case "comments":
            this.commentsSortAsc = !this.commentsSortAsc;
            this.sortByComments();
            break;
        case "mpg":
            this.mpgSortAsc = !this.mpgSortAsc;
            this.sortByMPG();
            break;
        case "rank":
            this.rankSortAsc = !this.rankSortAsc;
            this.sortByRank();
            break;
    }
}

//Custom JS object array sorting functions
function sortNameAsc(a, b) {
    var x = a.profileLogin.toLowerCase();
    var y = b.profileLogin.toLowerCase();
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortNameDesc(a, b) {
    var x = b.profileLogin.toLowerCase();
    var y = a.profileLogin.toLowerCase();
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortCommentsAsc(a, b) {
    var x = a.numComments;
    var y = b.numComments;
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortCommentsDesc(a, b) {
    var x = b.numComments;
    var y = a.numComments;
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortMPGAsc(a, b) {
    var x = parseFloat(a.MPG);
    var y = parseFloat(b.MPG);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortMPGDesc(a, b) {
    var x = parseFloat(b.MPG);
    var y = parseFloat(a.MPG);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}      
function sortRankAsc(a, b) {
    var x = parseInt(a.rank);
    var y = parseInt(b.rank);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function sortRankDesc(a, b) {
    var x = parseInt(b.rank);
    var y = parseInt(a.rank);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

/////////////////////////////////////////////////////////////////////
//
// SUB CLASSES
//
/////////////////////////////////////////////////////////////////////

//Leaderboard Entry Object
function leaderboardEntry() {
    this.authorID = 0;              //$gp->post_author
    this.fullName = "";             //$gp->profile_full_name
    this.location = "";             //$gp->profile_location
    this.rank = 0;                  //$gp->rank
    this.isGuinnessUser = false;    //$gp->post_author == CFVW_GUINNESS_USER_ID
    this.mileage = "";              //$gp->cfvw_current_odometer_reading
    this.tirePressure = "";         //$gp->cfvw_tire_pressure
    this.tireSize = "";             //$gp->cfvw_tire_size
    this.MPG = "";                  //number_format($gp->cfvw_high_mpg, 1, '.', '') OR 67.9 if isGuinessUser
    this.profileLogin = "";         //$gp->profile_login
    this.profileImage = "";         //$gp->profile_image_url
    this.profileLink = "";          //cfvw_get_profile_link($gp->post_author)
    this.carInfo = "";              //$gp->profile_car_info
    this.numComments = "";          //$number_of_comments
    this.inPenaltyBox = false;      //(This variable hasn't been determined yet)
    this.spam = "";
    
    //These will be any HTML snippets needed.
    this.html = new HTMLSnippets(); //Container for any HTML snippets.
    
    //These will contain the CSS classes required to build the markup.
    this.css = new CSSClasses();    //Container for any CSS classes needed.
}

function HTMLSnippets() {
    this.voteUp = "";
    this.voteDown = "";
    this.commentDesc = "";
    this.mainTRid = "";
    this.templateURL = "";
    this.legalURL = "";
}

function CSSClasses() {
    this.mainTR = ""; //CSS for the main Table Row
    this.voteUp = "";
    this.voteDown = "";
    this.sortAttributesName = "";
    this.sortAttributesMPG = "";
}