Clay_Banger / bots4 Fight Stats

// ==UserScript==
// @name         bots4 Fight Stats
// @version      1.0
// @description  Displays stats about previous fights while fighting
// @author       Clay Banger
// @match        http://bots4.net/*
// @grant        none
// @require      https://kryogenix.org/code/browser/sorttable/sorttable.js
// @license      MIT
// @updateURL    https://openuserjs.org/meta/Clay_Banger/bots4_Fight_Stats.meta.js
// ==/UserScript==

var $ = window.jQuery;

var WINS=0;
var LOSSES=1;
var TOTAL_DURATION=2;
var TOTAL_EXP=3;
var ENERGY_FIGHTS=4;
var TOTAL_ENERGY=5;
var TOTAL_KUDOS=6;
var OPPONENT_LEVEL=7;
var OPPONENT_COLOUR=8;
var LAST_BATTLED=9;
var OPPONENT_ID=10;

//cosmetic stuff
var BACKGROUND_COLOUR = "#202020";
var BORDER_COLOUR = "#808080";
var TEXT_COLOUR = "#dddddd";

(function() {
    'use strict';

    //add the link, below HoF to /botsstats
    $("#left-nav>ul:first").append("<li><a href='/botsstats'>bots stats</a></li>");


    if(document.title == "home - bots4"){
        //grab the user/bot information and store
        if(!isUserRegistered(getUsername())) {
            console.log("Registering user");
            linkBotUsername();
        }
    } else if((document.title == "train - bots4") || (document.title == "fight - bots4")) {
        //get the battle length
        var battleLength = $("#remaining").html().replace("s","");

        //get the current bot we are fighting.
        var opponentName = $('#battle-header').html();

        //this name isn't stored as neatly as the bots in the fight list, we need to extract it from some HTML.
        var start = opponentName.indexOf("vs. ")+4;
        var end = opponentName.indexOf("</div>");

        var attacker = opponentName.substring(opponentName.indexOf("\">")+2,start-5);
        opponentName = opponentName.substring(start,end);

        //look up existing data
        var fightStats = getStats(attacker, opponentName);

        if(fightStats === null) {
            //new bot, load up the defaults and information we have already collected
            fightStats = new Object();
            fightStats.totalFights = 0;
            fightStats.avgBattleDur = 0;
            fightStats.winPerc = NaN;
            fightStats.timeToKEnergy = NaN;
            fightStats.avgExp = "-";
            fightStats.avgKudos = "-";
            fightStats.wins = 0;
            fightStats.losses = 0;
            fightStats.duration = 0;
            fightStats.totalExp = 0;
            fightStats.energyFights = 0;
            fightStats.totalEnergy = 0;
            fightStats.totalKudos = 0;
            fightStats.expMin = "-";
        }

        //add some stats about this fight to the object
        fightStats.attacker = attacker;
        fightStats.defender = opponentName;
        fightStats.battleLength = battleLength;
        fightStats.speedBuff = 1;
        fightStats.expBuff = 1;
        fightStats.kudosBuff = 1;
        fightStats.energyBuff = 1;

        if (document.title == "fight - bots4") {
            fightStats.opponentLevel = window.location.pathname.match(/\/fight\/(\d+)\//)[1];
            fightStats.opponentId = window.location.pathname.match(/\/fight\/\d+\/(\d+)\//)[1];
        } else if(document.title == "train - bots4") {
            fightStats.opponentLevel = lookupTrainBot(parseInt(window.location.pathname.match(/\/train\/(\d+)\//)[1]));
            fightStats.opponentId = -1;
        }

        //get the buffs
        $(".buff").not(".buff-inactive").each(function(i) {
            //buff is active, we need to modify out battle output accordingly
            switch($(this).find("div[style='font-size: 1.5em;']").html()) {
                case "Spirit of Wolf I":
                    fightStats.speedBuff = 1.5;
                    break;
                case "Spirit of Wolf II":
                    fightStats.speedBuff = 2;
                    break;
                case "Spirit of Wolf III":
                    fightStats.speedBuff = 2.5;
                    break;
                case "Dark Energy I":
                    fightStats.energyBuff = 1.5;
                    break;
                case "Dark Energy II":
                    fightStats.energyBuff = 2;
                    break;
                case "Dark Energy III":
                    fightStats.energyBuff = 2.5;
                    break;
                case "Mindreave I":
                    fightStats.expBuff = 0.75;
                    break;
                case "Mindreave II":
                    fightStats.expBuff = 0.5;
                    break;
                case "Mindreave III":
                    fightStats.expBuff = 0.25;
                    break;
                case "Kodiac's Endless Intellect I":
                    fightStats.expBuff = 1.5;
                    break;
                case "Kodiac's Endless Intellect II":
                    fightStats.expBuff = 2;
                    break;
                case "Kodiac's Endless Intellect II":
                    fightStats.expBuff = 2.5;
                    break;
                case "Blitz's Bounty I":
                    fightStats.kudosBuff = 1.5;
                    break;
                case "Blitz's Bounty II":
                    fightStats.kudosBuff = 2;
                    break;
                case "Blitz's Bounty III":
                    fightStats.kudosBuff = 2.5;
                    break;
                case "Aura of Eternity":
                    fightStats.kudosBuff = 2.5;
                    break;
                case "Hastened Adventure":
                    fightStats.speedBuff = 100;
                    break;
            }
        });

        //output the stats window
        var html = '<div id="botsstats" style="margin: 0 auto 0 auto; ' +
            'border: 1px solid ' + BORDER_COLOUR + '; margin-top: 5px; margin-right: 5px; ' +
            'font-size: small; background-color: ' + BACKGROUND_COLOUR + ';text-align:left;' +
            'color: ' + TEXT_COLOUR + ';right: 0;top: 0;width: 200px;position:fixed;"><p style="margin: 2px 0 1px 0;"> ' +
            '<center><u>Fight Stats</u></center><br/>' +
            '<table border=0>' +
            '<tr><td>Challenger:</td><td>' + attacker + '</td></tr>' +
            '<tr><td>Defender:</td><td>' + opponentName + '</td></tr>' +
            '<tr><td>Total Fights:</td><td>' + numberWithCommas(fightStats.totalFights) + '</td></tr>' +
            '<tr><td>Avg Duration:</td><td>' + fightStats.avgBattleDur + 's</td></tr>' +
            '<tr><td>Win %:</td><td>' + fightStats.winPerc + '%</td></tr>';
        if (!isNaN(fightStats.timeToKEnergy)) {
            html += '<tr><td>1K Energy Time:</td><td>' + fightStats.timeToKEnergy + 's</td></tr>';
        }
        html += '<tr><td>Avg Exp:</td><td>' + numberWithCommas(fightStats.avgExp) + '</td></tr>'+
            '<tr><td>Exp/min:</td><td>' + numberWithCommas(fightStats.expMin) +'</td></tr>' +
            '<tr><td>Avg Kudos:</td><td>' + numberWithCommas(fightStats.avgKudos) + '</td></tr>' +
            '</table><center><input type="button" id="reset" value="Reset" /></center></p></div>';
        $("body").append(html);

        //add event listener to reset button
        $("#reset").bind( "click", function() {
            resetStats(opponentName, attacker);
        });

        //get stats at the end of the battle
        findFinish(fightStats);
    } else if(document.title == "train list - bots4") {
        //show any stats we have alongside the training bots info
        if(!isUserRegistered(getUsername())) {
            //no bot name registered with that username, which is weird.
        } else {
            //find training bot names and look for matches with current logged in botname
            $(".box>a:first-child").each(function(i) {

                var trainInfo = getStats(getBotname(getUsername()), $(this).html());
                if(trainInfo !== null) {
                    //display found matches alongside training bot info
                    $(this).parent().append("<table><tr><th>Fights</th><th>Win %</th><th>Avg Dur</th><th>Avg Exp</th><th>Exp/min</th><th>Avg Kudos</th></tr>"+
                                            "<tr><td class='subtext'>"+numberWithCommas(trainInfo.totalFights)+"</td>" +
                                            "<td class='subtext'>"+trainInfo.winPerc+"%</td>" +
                                            "<td class='subtext'>"+trainInfo.avgBattleDur+"s</td>" +
                                            "<td class='subtext'>"+numberWithCommas(trainInfo.avgExp)+"</td>" +
                                            "<td class='subtext'>"+numberWithCommas(trainInfo.expMin)+"</td>" +
                                            "<td class='subtext'>"+numberWithCommas(trainInfo.avgKudos)+"</td></tr></table>");
                }
            });
        }
    } else if(document.title == "fight list - bots4") {
        //show any stats we have alongside the bots
        if(!isUserRegistered(getUsername())) {
            //no bot name registered with that username, which is weird.
        } else {
            //we good.
            //find botnames that match any in the list
            var botName = getBotname(getUsername());
            //cycle through all of the bots listed on the page
            $(".botrow").each(function(i) {
                //check to see if we have info for the bot
                var rowBot = $(this).children().eq(2).html();
                var fightStats = getStats(botName, rowBot);
                if(fightStats !== null) {
                    //we have some stored details!
                    var divName = rowBot.replace(/\ /g,"_");

                    var html = "<div style='position: relative'><img id='"+divName+"' src='/favicon.ico'/>";
                    html += "<div id='hidden_"+divName+"' style='position: absolute;display:none;width: 350px;' class='buff-details'><table><tr>"+
                        "<th class='sorttable_nosort'>Fights</th>"+
                        "<th class='sorttable_nosort'>Win %</th>"+
                        "<th class='sorttable_nosort'>Avg Dur</th>";
                    if (!isNaN(fightStats.timeToKEnergy)) {
                        html += "<th class='sorttable_nosort'>1k Eng Time</th>";
                    }
                    html += "<th class='sorttable_nosort'>Avg Exp</th>"+
                        "<th class='sorttable_nosort'>Exp/min</th>"+
                        "<th class='sorttable_nosort'>Avg Kudos</th></tr>" +

                        "<tr><td>"+numberWithCommas(fightStats.totalFights)+"</td>" +
                        "<td>"+fightStats.winPerc+"%</td>"+
                        "<td>"+fightStats.avgBattleDur+"s</td>";
                    if (!isNaN(fightStats.timeToKEnergy)) {
                        html += "<td>"+fightStats.timeToKEnergy+"s</td>";
                    }
                     html += "<td>"+numberWithCommas(fightStats.avgExp)+"</td>"+
                         "<td>"+numberWithCommas(fightStats.expMin)+"</td>" +
                         "<td>"+numberWithCommas(fightStats.avgKudos)+"</td></tr>" +
                         "</table></div></div>";
                    $(this).children().eq(11).append(html);

                    //add mouse listeners
                    $("#"+divName).mouseover(function(){
                        $("#hidden_"+this.id).css("display", "block");
                    });
                    $("#"+divName).mouseleave(function() {
                        $("#hidden_"+this.id).css("display", "none");
                    });
                }
            });
        }
    } else if(window.location.href.indexOf("bots4.net/profile/") != -1) {
        //check if we have any stats
        var fightStats = [];
        var botname = $(".block-list:eq(1)>tbody>tr>td:eq(0)>span").html();
        for(var j=0, len=localStorage.length; j<len; j++) {
            if(localStorage.key(j).match("BOTSSTATS_"+botname+"_") !== null) {
                fightStats.push(localStorage.key(j));
            }
        }
        if(fightStats.length !== 0) {
            //we have some stats!
            var html = "<h2>Fight stats</h2><table><thead><tr>" +
                "<th>Challenger</th>" +
                "<th>Fights</th>"+
                "<th>Win %</th>"+
                "<th>Avg Dur</th>"+
                "<th>1k Eng Time</th>"+
                "<th>Avg Exp</th>"+
                "<th>Exp/min</th>"+
                "<th>Avg Kudos</th>"+
                "<th>Last Battled</th></tr></thead><tbody>";

            for(var j=0; j<fightStats.length;j++) {
                var challenger = fightStats[j].split("_")[2];
                var stats = getStats(challenger ,botname);
                var lastBattle = new Date(parseInt(stats.lastBattled));
                var ago = days_between(lastBattle, new Date());
                var challengerDeets = getChallengerDetails(challenger);
                html +="<tr><td>";
                if(challengerDeets === undefined) {
                    html += challenger;
                } else {
                    html += "<a href='/profile/"+challengerDeets.id+"' style='color: "+challengerDeets.colour+";'>"+challenger+"</a>";
                }
                html += "</td>" +
                    "<td>"+numberWithCommas(stats.totalFights)+"</td>" +
                    "<td class='ratio_"+stats.winPercColour+"'>"+stats.winPerc+"%</td>"+
                    "<td>"+stats.avgBattleDur+"s</td>"+
                    "<td>"+stats.timeToKEnergy+"s</td>"+
                    "<td>"+numberWithCommas(stats.avgExp)+"</td>"+
                    "<td>"+numberWithCommas(stats.expMin)+"</td>"+
                    "<td style='color:";
                console.log(fightStats.avgKudos);
                if(parseInt(stats.avgKudos)<0) {
                    html += "red";
                } else {
                    html += "#0f0";
                }
                html += "'>"+numberWithCommas(stats.avgKudos)+"</td>" +
                    "<td >"+lastBattle.toLocaleDateString("en-GB")+"<br><span class='subtext'>[<span class='subsubtext'>";
                if(ago === 0) {
                    html += "today</span>";
                } else {
                    html += ago+" day";
                    if(ago != 1) {
                        html += "s";
                    }
                    html += "</span> ago";
                }
                html += "]</span></td></tr>";
            }

            html += "</tbody></table>";
            $("h2:contains('Energy history')").before(html);
        }

    } else if(window.location.pathname == "/botsstats") {
        document.title = "bots stats - bots4";
        $("#page-title").html("bots stats");

        var html = "<h2>Bot List</h2><table id='bot_list' class='sortable'><thead><tr>"+
            "<th class='sorttable_nosort'>botname</th>"+
            "<th>level</th>"+
            "<th>challenger</th>"+
            "<th>total fights</th>"+
            "<th>win %</th>"+
            "<th>avg duration</th>"+
            "<th>1k energy time</th>"+
            "<th>avg exp</th>"+
            "<th>exp/min</th>"+
            "<th>avg kudos</th>"+
            "<th>last battled</th>"+
            "<th class='sorttable_nosort'></th>"+
            "</tr></thead><tbody>";

        for(var j=0;j<localStorage.length;j++) {
            if(localStorage.key(j).match(/BOTSSTATS_/g) !== null) {
                //we have a bot! do some calcs and output it
                var keyDeets = localStorage.key(j).split("_");
                var fightStats = getStats(keyDeets[2], keyDeets[1]);
                var challengerDeets = getChallengerDetails(fightStats.challenger);

                var lastBattle = new Date(parseInt(fightStats.lastBattled));
                var ago = days_between(lastBattle, new Date());
                html += "<tr class='botrow'><td>";
                if(parseInt(fightStats.opponentId) == -1) {
                    //we have a training bot
                    html += "<a href='/train' style='color: "+fightStats.opponentColour+";'>";
                } else {
                    //regular bot
                    html += "<a href='/profile/"+fightStats.opponentId+"' style='color: "+fightStats.opponentColour+";'>";
                }
                html += fightStats.defender+"</a></td>"+
                    "<td class='subtext' sorttable_customkey='"+fightStats.opponentLevel+"'>[<span class='subsubtext'>"+fightStats.opponentLevel+"</span>]</td>"+
                    "<td><a href='/profile/"+challengerDeets.id+"' style='color:"+challengerDeets.colour+"' sorttable_customkey='"+challengerDeets.name.toLowerCase()+"'>"+challengerDeets.name+"</a></td>"+
                    "<td>"+numberWithCommas(fightStats.totalFights)+"</td>" +
                    "<td sorttable_customkey='"+fightStats.winPerc+"'><span class='ratio_"+fightStats.winPercColour+"'>"+fightStats.winPerc+"%</span></td>" +
                    "<td>"+fightStats.avgBattleDur+"</td>" +
                    "<td>"+fightStats.timeToKEnergy+"</td>" +
                    "<td>"+numberWithCommas(fightStats.avgExp)+"</td>" +
                    "<td>"+numberWithCommas(fightStats.expMin)+"</td>" +
                    "<td style='color: ";
                if(fightStats.avgKudos<0) {
                    html += "red";
                } else {
                    html += "#0f0";
                }
                html += ";'>"+numberWithCommas(fightStats.avgKudos)+"</td>" +
                    "<td sorttable_customkey='"+fightStats.lastBattled+"'>"+lastBattle.toLocaleDateString("en-GB")+"<br><span class='subtext'>[<span class='subsubtext'>";

                if(ago === 0) {
                    html += "today</span>";
                } else {
                    html += ago+" day";
                    if(ago != 1) {
                        html += "s";
                    }
                    html += "</span> ago";
                }

                html += "]</span></td>" +
                    "<td><input class='delete_button' type='button' value='Delete'/></td></tr>";
            }
        }
        html += "</table>";
        html += "<style>table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after {content: ' \\25B4\\25BE' }</style>";

        //add import and export buttons
        html += "<h2>Export</h2><input type='button' value='Export' id='export'/>"+
            "<h2>Import</h2><textarea rows=1 cols=20 id='import_file'></textarea><br/><input type='button' value='Import' id='import'/><span id='import_span'></span>"+
            "<h2>Clear</h2><input type='button' value='Clear' id='clear' /><span id='clear_span'></span>";

        $("#content").append(html);

        //enable buttons
        $(".delete_button").each(function(i) {
            $(this).bind( "click", function() { removeRow($(this).parents("tr")); });
        });
        $("#export").bind( "click", function() { exportBotsStats(); });
        $("#import").bind( "click", function() { importWarning(); });
        $("#clear").bind( "click", function() { clearWarning(); });
    }
})();

function resetStats(opponentName, attacker) {
    localStorage.removeItem("BOTSSTATS_"+opponentName+"_"+attacker);
    $("#botsstats").html("<center>Stats Reset</center>");
}

function getStats(attacker, defender) {
    //loads the supplied bot string into an object, returns null if it doesn't exist
    var rawStats = localStorage.getItem("BOTSSTATS_"+defender+"_"+attacker);
    if(rawStats === null) {
        return rawStats
    } else {
        rawStats = rawStats.split("_");
        var calcStats = new Object();
        calcStats.wins = parseInt(rawStats[WINS]);
        calcStats.losses = parseInt(rawStats[LOSSES]);
        calcStats.duration = parseFloat(rawStats[TOTAL_DURATION]);
        calcStats.totalExp = parseInt(rawStats[TOTAL_EXP]);
        calcStats.energyFights = parseInt(rawStats[ENERGY_FIGHTS]);
        calcStats.totalEnergy = parseInt(rawStats[TOTAL_ENERGY]);
        calcStats.totalKudos = parseInt(rawStats[TOTAL_KUDOS]);
        calcStats.opponentLevel = parseInt(rawStats[OPPONENT_LEVEL]);
        calcStats.opponentColour = rawStats[OPPONENT_COLOUR];
        calcStats.lastBattled = rawStats[LAST_BATTLED];
        calcStats.opponentId = rawStats[OPPONENT_ID];
        calcStats.totalFights = calcStats.wins+calcStats.losses;
        calcStats.avgBattleDur = (calcStats.duration/parseFloat(calcStats.totalFights)).toFixed(2);
        if(calcStats.losses == 0) {
            calcStats.winPerc = 100.00;
        } else if((calcStats.losses == 0) && (calcStats.wins == 0)) {
            calcStats.winPerc = "NaN";
        } else {
            calcStats.winPerc = ((parseFloat(calcStats.wins)/parseFloat(calcStats.totalFights))*100).toFixed(2);
        }
        calcStats.winPercColour = Math.round(calcStats.winPerc/6.666);
        if(calcStats.winPercColour === 0) {
            calcStats.winPercColour = 1;
        }
        calcStats.timeToKEnergy = Math.round((1000/(parseFloat(calcStats.totalEnergy)/parseFloat(calcStats.energyFights)))*calcStats.avgBattleDur);
        calcStats.avgExp = Math.round(parseFloat(calcStats.totalExp)/parseFloat(calcStats.totalFights));
        calcStats.expMin = Math.round((60.0/calcStats.avgBattleDur)*calcStats.avgExp);
        calcStats.avgKudos = Math.round(calcStats.totalKudos/(calcStats.totalFights));
        calcStats.defender = defender;
        calcStats.challenger = attacker;
        return calcStats;
    }
}

function getUsername() {
    return $(".box>div>a[href^='/profile']").html();
}

function getBotname(username) {
    //returns undefined if the bot hasn't been linked
    var botName = localStorage.getItem("BOTSSTATSLINK_"+username);
    if(botName === null) {
        return undefined;
    } else {
        return botName.split("_")[0];
    }
}

function getChallengerDetails(username) {
    var challengerDeets = localStorage["BOTSSTATSLINK_"+username];
    if(challengerDeets !== undefined) {
        var deets = new Object();
        deets.colour = challengerDeets.split("_")[2];
        deets.id = challengerDeets.split("_")[1];
        deets.name = username;
        return deets;
    } else {
        return undefined;
    }
}

function isUserRegistered(username) {
    if(getBotname(username) === undefined) {
        return false;
    } else {
        return true;
    }
}

function removeRow(row) {
    var botname = $(row).find("td:eq(0)>a").html();
    var attacker = $(row).find("td:eq(2)>a").html();
    localStorage.removeItem("BOTSSTATS_"+botname+"_"+attacker);
    $(row).remove();
}

function linkBotUsername() {
    $.ajax($(".box>div>a[href^='/profile']").attr("href"), {
        success: function(data) {
            var user = getUsername();
            var bot = data.match(/\<th\>\s*\<div\>Botname:\<\/div\>\s*\<\/th\>\s*\<td\>\<span style=\"color: #\w+;\"\>([^<]+)<\/span\>\<\/td\>/)[1];
            var id = data.match(/\<th\>\s*\<div\>Id:\<\/div\>\s*\<\/th\>\s*\<td\>(\d+)\<\/td\>/)[1];
            var colour = $(".box>div>a[href^='/profile']").css("color");
            localStorage['BOTSSTATSLINK_'+user] = bot+"_"+id+"_"+colour;
            localStorage['BOTSSTATSLINK_'+bot] = user+"_"+id+"_"+colour;
            console.log("Bot/user linked!");
        },
        error: function(error) {
            console.log(error);
        }
    });
}

function exportBotsStats() {
    var toExport = "";

    for(var j=0, len=localStorage.length; j<len; j++) {
        if(localStorage.key(j).match(/BOTSSTATS/g) !== null) {
            toExport += localStorage.key(j)+"\""+localStorage[localStorage.key(j)]+"\n";
        }
    }
    var today = new Date();
    download(toExport, "bots_stats_export_"+today.getFullYear()+"_"+(today.getMonth()+1)+"_"+today.getDate()+".txt", "text/plain;charset=utf-8");
}

function importWarning() {
    //check import data
    var toImport = $("#import_file").val().split('\n');
    if(toImport!="") {
        $("#import_file").prop("disabled", true);
        var itsOK = 0;
        for(var i=0;i<toImport.length;i++) {
            var line = toImport[i]
            var check1 = line.match(/BOTSSTATS_[^_]+_[^"]+\"(?:-?[\d|.]+_){8}rgb\(\d+,\s*\d+,\s*\d+\)(?:_-?\d+){2}/);
            var check2 = line.match(/BOTSSTATSLINK_[^"]+\"[^_]+_\d+_rgb\(\d+,\s*\d+,\s*\d+\)/);
            if((check1 === null) && (check2 === null) && (line !== "")) {
                //check failed
                itsOK = i+1;
                i=toImport.length+100;
            }
        }
        if(itsOK===0) {
            $("#import_span").html(" <span style='color: red'>WARNING:</span> This will overwrite existing data. Click Import to continue");
            $("#import").bind( "click", function() { importBotsStats(); });
        } else {
            $("#import_span").html("Invalid import data. Issue on line: "+itsOK);
            $("#import_file").prop("disabled", false);
        }
    } else {
        $("#import_span").html("No data found");
    }
}

function importBotsStats() {
    var toImport = $("#import_file").val().split('\n');
    for(var i=0;i<toImport.length;i++) {
        var line = toImport[i];
        //ignores blank lines
        if(line !== "") {
            line = line.split("\"");
            localStorage.setItem(line[0],line[1]);
        }
    }
    $("#import_span").html("Import successful! <input type='button' value='Reload' onClick='window.location.reload()' />");
    $("#import").hide();
}

function clearWarning() {
    $("#clear_span").html(" <span style='color: red'>WARNING: THIS WILL CLEAR ALL DATA!</span> Make sure you have a backup handy, just in case. Click Clear again to proceed.");
    $("#clear").bind( "click", function() { clearStats(); });
}

function clearStats() {
    var listToDelete = [];
    for(var j=0; j<localStorage.length; j++) {
        if(localStorage.key(j).match(/BOTSSTATS/g) !== null) {
            listToDelete.push(localStorage.key(j));
        }
    }
    for(var i=0;i<listToDelete.length;i++){
        localStorage.removeItem(listToDelete[i]);
    }
    $("#clear_span").html("Cleared. <input type='button' value='Reload' onClick='window.location.reload()' />");
    $("#clear").hide();
}

function findFinish(fightStats) {
    if($("#battle-summary").length !== 0) {
        //the fight is over

        //pull the energy obtained from the battle log.
        var battleLog = $("#battle-log").html();
        var kudos = "";

        var energy = battleLog.match(/is exhausted and (?:loses|gives you) \<span class\=\"subsubtext\">(\d+)\<\/span\> energy./m);
        if(energy === null) {
            energy = 0;
        } else {
            energy = energy[1];
            fightStats.energyFights++;
        }
        kudos = battleLog.match(/The B.O.T.S. Union takes \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> kudos/m);
        if(kudos === null) {
            kudos = battleLog.match(/The B.O.T.S. Union hands you \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> kudos/m)[1];
        } else {
            kudos = kudos[1];
        }
        var exp = battleLog.match(/Your bot gains \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> experience points/m)[1];

        //we now know how much energy we have. Now figure out who won.
        var winner = $("#battle-summary>tbody>tr>td:last>span").html();

        var way = "";
        if((winner == fightStats.defender) && (document.title != "train - bots4") && (document.title != "(!) train - bots4")) {
            //challenger lost
            way = "-";
        }
        var addToWins = 0;
        var addToLoss = 0;
        if(winner == fightStats.defender) {
            addToLoss = 1;
        } else {
            addToWins = 1;
        }

        //get the colour of the opponent
        var opponentDisplay = $("#battle-summary>tbody>tr>td:eq(5)>span").css("color");

        //current time, to serve as last battled time
        var lastBattled = (new Date).getTime();

        //store
        var botInfo = [parseInt(fightStats.wins)+addToWins,
                       fightStats.losses+addToLoss,
                       (fightStats.duration+parseFloat(fightStats.battleLength)*fightStats.speedBuff).toFixed(2),
                       parseFloat(fightStats.totalExp)+parseFloat(exp.replace(/\,/g,""))/fightStats.expBuff,
                       fightStats.energyFights,
                       fightStats.totalEnergy+parseInt(way+energy)/fightStats.energyBuff,
                       fightStats.totalKudos+parseInt(way+kudos.replace(/\,/g,""))/fightStats.kudosBuff,
                       fightStats.opponentLevel,
                       opponentDisplay,
                       lastBattled,
                       fightStats.opponentId];
        localStorage["BOTSSTATS_"+fightStats.defender+"_"+fightStats.attacker] = botInfo.join("_");
    } else {
    	//fight has not ended yet, wait another 0.1 second for the fight to end.
		setTimeout(function(){findFinish(fightStats);}, 100);
    }
}

function lookupTrainBot(number) {
    switch(number) {
        case 1: return 1;
        case 2: return 1;
        case 3: return 7;
        case 4: return 10;
        case 5: return 20;
        case 6: return 30;
        case 7: return 45;
        case 8: return 60;
        case 9: return 75;
        case 10: return 90;
        case 11: return 105;
        case 12: return 115;
        case 13: return 125;
        case 14: return 140;
        case 15: return 160;
        case 16: return 180;
        case 17: return 200;
        case 18: return 220;
        case 19: return 240;
        case 20: return 260;
        case 21: return 280;
        case 22: return 300;
        case 23: return 325;
        case 24: return 350;
        case 25: return 375;
        case 26: return 400;
        case 27: return 450;
        case 28: return 500;
        case 29: return 550;
        case 30: return 600;
        case 31: return 750;
        case 32: return 1000;
        case 33: return 1200;
        case 34: return 1500;
        case 35: return 1800;
        case 36: return 2100;
        default: return undefined;
    }
}

function days_between(date1, date2) {
    var ONE_DAY = 1000 * 60 * 60 * 24;
    var date1_ms = date1.getTime();
    var date2_ms = date2.getTime();
    var difference_ms = Math.abs(date1_ms - date2_ms);
    return Math.round(difference_ms/ONE_DAY);
}

//number format function. Only used to format the energy display. Credit for this function goes to mikez302 from StackOverflow.
function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

// Function to download data to a file
//from: https://stackoverflow.com/questions/13405129/javascript-create-and-save-file
function download(data, filename, type) {
    var file = new Blob([data], {type: type});
    if (window.navigator.msSaveOrOpenBlob) { // IE10+
        window.navigator.msSaveOrOpenBlob(file, filename);
    } else { // Others
        var a = document.createElement("a"),
                url = URL.createObjectURL(file);
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        setTimeout(function() {
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);
        }, 0);
    }
}