
var allTweets    = new Array();
var hourCount    = new Array(24);
var dayCount     = new Array(7);
var scatterCount = new Array(); 

var names;
    
var tweeter;
var totalTweets;
var tweetsPerPage  = 50;
var pagesPerBlock  = 1;
var maxpages       = 40;
var missing = 0;
var expected;

var fore = '333343bb';
var rply = '000000bb';
var rtwt = '00ff00bb';
var back = '00000000';

$(document).ready(function() {
    $("#slider").slider({
       range: true,
        min: 1,
        values: [1, 1]
    });

    $('#slider').slider('disable');
    $('#slider').css({'visibility' : 'hidden'});
    $('#namecontainer').css({'display' : 'none'});

    $('.ui-slider-handle').each(function() {
        var tip = $(document.createElement('span'));
        tip.addClass('ui-slider-handle-tooltip');
        tip.addClass('ui-corner-all');
        tip.appendTo($(this));
    });

    $('.ui-slider-handle').hover(
        function() {
            $(this).find('.ui-slider-handle-tooltip').css({'display':'block'});
        },
        function() {
            $(this).find('.ui-slider-handle-tooltip').css({'display':'none'});
        }
    );

    resetArrays();

    tweeter = location.pathname.split("/")[2];
    if(tweeter != null && tweeter.length > 0) {
        loadCount(tweeter);
    }
});

function resetArrays()
{
    for(i = 0; i < hourCount.length; i++)
    {
        hourCount[i] = {count: 0, replies: 0, retweets: 0};
    }

    for(i = 0; i < dayCount.length; i++)
    {
        dayCount[i] = {count: 0, replies: 0, retweets: 0};
    }

    for(i = 0; i < hourCount.length; i++)
    {
       scatterCount[i] = new Array(dayCount.length);
       for(var j = 0; j < dayCount.length; j++)
       {
            scatterCount[i][j] = {count: 0, replies: 0, retweets: 0};
       }
    }
    
    names = new Object();
}

function loadCount(tweeter) {
    call('http://xefer.com/statuses/' + tweeter);
}

function tweets(feed) {
    totalTweets = feed.value.items[0].tweets;   
    
    totalPages     = Math.min(Math.ceil(totalTweets / tweetsPerPage), maxpages); 
    totalBlocks    = Math.ceil(totalPages  / pagesPerBlock);
    pagesLastBlock = totalPages - ((totalBlocks - 1) * pagesPerBlock); 
    
    currentBlock = 0;    
    
    /* show name and number */
    $("#headr").html("<span><a href='http://twitter.com/" + tweeter + "'>" + tweeter + "</a> : " + totalTweets + "</span>");
    
    showWorkIndicators();
    
    pages = (currentBlock == totalBlocks - 1) ? pagesLastBlock : pagesPerBlock; 
    loader(currentBlock, pages);
}

function showWorkIndicators() {    
    /** */
    $('#slider').slider('option', 'max', Math.min(tweetsPerPage * maxpages, totalTweets));
    /** set initial tooltip values */
    $('#slider').bind('slidechange', function(event, ui) {
        $(ui.handle).find('.ui-slider-handle-tooltip').html(allTweets[ui.value - 1].date);
    });    
    /* put the pulser in front of the image */
    $('#holder').css({"background" : "#fff url(/image/pulser.gif) no-repeat scroll center center"});
}

function progress(total) { 
    $('#slider').css({'visibility' : 'visible'});
    $('#slider').slider('values', 0, 1);  
    $('#slider').slider('values', 1, total);
}

function hideWorkIndicators() {
    $('#progress').css({"visibility" : "hidden"});
    $('#namecontainer').css({'display' : 'block'});
    $('#slider').slider('enable');
    $('#slider').bind('slidechange', function(event, ui) {
        var one = $(this).slider('values', 0) - 1; 
        var two = $(this).slider('values', 1) - 1; 
        
        resetArrays();
        var range = allTweets.slice(one, two + 1);
        processBlock(range);
        render(true);
    });
    $('#slider').bind('slide', function(event, ui) {
        $(ui.handle).find('.ui-slider-handle-tooltip').html(allTweets[ui.value - 1].date);
        $(ui.handle).find('.ui-slider-handle-tooltip').css({'display' : 'block'});
    });
    $('#slider').bind('slidestop', function(event, ui) {
        $(ui.handle).find('.ui-slider-handle-tooltip').css({'display' : 'none'});
    });
}

function render(names) {
    buildScatter();
    buildDayOfWeek();
    buildHourly();
    
    if(names)
    {
        showNames();
    }
}

function loader(block, pages) {
    if(pages == 0) {
        render(false);
    }
    
    start = block * pagesPerBlock + 1; // 1-base counter 
    count = tweetsPerPage * pages;
    if(start * count > totalTweets)
    {
        expected = tweetsPerPage - ((start * count) - totalTweets);
    }
    else
    {
        expected = tweetsPerPage;
    }
    apinm = start % 6;
    
    call('http://pipes.yahoo.com/xeferae/twitterapi' + apinm + '?_render=json&_callback=processor&user=' + tweeter + '&start=' + start + '&count=' + count);
}

function processor(feed) {
    items = feed.value.items.reverse();
    processBlock(items);
    allTweets = items.concat(allTweets);
    
    missed = expected - items.length;
    missing += missed;
    
    // didn't get a full page of tweets back so shrink the slider max size
    if(missed > 0)
    {     
     $('#slider').slider('option', 'max', Math.min(tweetsPerPage * maxpages, totalTweets) - missing);
    }

    $("#holder").css({'background' : '#fff'});
    
    currentBlock++;
    progress(allTweets.length);
    
    lastBlock = (currentBlock == totalBlocks) || (currentBlock == 1);
    if((currentBlock % 3 == 0) || lastBlock)
    {
        render(lastBlock);
    }
    
    // after feed items process call loader again with next block
    if(currentBlock < totalBlocks - 1) {             
        loader(currentBlock, pagesPerBlock);
        return;
    }
    else {
        if((currentBlock == totalBlocks - 1) && (pagesLastBlock > 0)) {
            loader(currentBlock, pagesLastBlock);
            return;
        }
    }
    
    // if we've popped through to here, we must be finished loading blocks
    hideWorkIndicators();  
}

function processBlock(items) 
{
    for (var i = 0; i < items.length; i++) 
    {
        date = new Date();
        date.setISO8601(items[i].title);
        items[i].date = date.toLocaleString();
        
        hourCount[date.getHours()].count++;
        dayCount[date.getDay()].count++;
        scatterCount[date.getHours()][date.getDay()].count++;
  
  if(items[i].retweetId != null)
  {        
   hourCount[date.getHours()].retweets++;
   dayCount[date.getDay()].retweets++;
   scatterCount[date.getHours()][date.getDay()].retweets++;
  }
        
        if(items[i].description != null && items[i].description.length > 0)
        {
            var tweeter = items[i].description.toLowerCase().slice(1);
            
            if(tweeter != "")
            {
                scatterCount[date.getHours()][date.getDay()].replies++;
                dayCount[date.getDay()].replies++;
                hourCount[date.getHours()].replies++;

                if(names[tweeter] == null)
                {
                    names[tweeter] = { count: 0, tweets: new Array() };
                }

                names[tweeter].count++;
                names[tweeter].tweets.push( { name: tweeter, tweet: items[i].tweetId, reply: items[i].replyId, time: date } );
            }
        }
    }
}

function call(url) {
    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    
    head = document.getElementsByTagName('head')[0];
    head.appendChild(script);   
}

function buildHourly()
{
    var hmax = 0;
    for(i = 0; i < 24; i++) {
        if(hmax < hourCount[i].count) {
            hmax = hourCount[i].count;
        }
    }
    hmax = hmax * 1.1;
    hflt = hmax * .125;
    
    var hdata = '';
 var hretweet = '';
    var hreply = '';
    var hfloat = '';
    var hlabel = '';
    for(i = 0; i < 24; i++) {
  hretweet += hourCount[i].retweets;
        hreply += hourCount[i].replies;
        hdata += hourCount[i].count - (hourCount[i].replies + hourCount[i].retweets);
        hfloat += hflt;
        numtext = "" + hourCount[i].count;
        if(numtext == "0")
        {
           numtext = "";
        }
        hlabel += "t"+numtext+",000000,3,"+i+",12";
        if(i < 23) {
            hdata += ",";
            hreply += ",";
   hretweet += ",";
            hfloat += ",";
            hlabel += "|";
        }
    }

    barwidth = 18;
    spacing  = 13;
    width = hourCount.length * (spacing + barwidth) + 2;

    $('#hours').attr('src', 'http://chart.apis.google.com/chart'+
        '?chs=750x150' +
        '&chco=' + '00ff00cc' + ',' + '000000cc' + ',' + fore + ',00000000' +
        '&chf=bg,s,' + back +
        '&chd=t:'+hretweet+'|'+hreply+'|'+hdata+'|'+hfloat+
        '&chds='+hmax+',0'+
        '&chxt=x,y'+
        '&chm='+hlabel+
        '&chg=0,20,1,1'+
        '&chxl=0:||1:|'+
        '&cht=bvs'+
        '&chbh='+barwidth+','+spacing+
        '&chxs=0,000000,10,0,_|1,000000,10,0,_');
}

function buildDayOfWeek()
{
    var dmax = 0;
    for(i = 6; i >= 0; i--) {
        if(dmax < dayCount[i].count) {
            dmax = dayCount[i].count;
        }
    }
    dmax = dmax * 1.20;

    var ddata = '';
 var dretweet = '';
    var dreply = '';
    var dfloat = '';
    var dlabel = '';
    for(i = 6; i >= 0; i--) {
  dretweet += dayCount[i].retweets;
        dreply += dayCount[i].replies;
        ddata += dayCount[i].count - (dayCount[i].replies + dayCount[i].retweets);
        dfloat += '.01';
        numtext = "" + dayCount[6-i].count;
        if(numtext == "0")
        {
           numtext = "";
        }
        dlabel += "t%20"+numtext+",000000,3,"+i+",12";
        if(i > 0) {
            ddata += ",";
            dreply += ",";
   dretweet += ",";
            dfloat += ",";
            dlabel += "|";
        }
    }

    barwidth = 18;
    spacing  = 19;
    width = dayCount.length * (spacing + barwidth) + 2;

    $('#days').attr('src', 'http://chart.apis.google.com/chart'+
        '?chs=150x321' +
        '&chco=' + '00ff00cc' + ',' + '000000cc' + ',' + fore + ',00000000' +
        '&chf=bg,s,' + back +
        '&chd=t:'+dretweet+'|'+dreply+'|'+ddata+'|'+dfloat+
        '&chds=0,'+dmax+
        '&chxt=x,y'+
        '&chm='+dlabel+
        '&chg=20,0,1,1'+
        '&chxl=0:||1:|'+
        '&cht=bhs'+
        '&chbh='+barwidth+','+spacing+
        '&chxs=0,000000,10,0,_|1,000000,10,0,_');
}

function buildScatter()
{    
    var zmax = 0;
    var rmax = 0;
 var tmax = 0;
 
 $('#maxreplydot').css('display','none');
 $('#maxretweetdot').css('display','none');
 
    for(var y = 0; y < 7; y++) {
        for(var x = 0; x < 24; x++) {
            var z = scatterCount[x][y].count;
            if(zmax < z) {
                zmax = z;
            }
            var r = scatterCount[x][y].replies;
            if(rmax < r) {
                rmax = r;
            }   
            var t = scatterCount[x][y].retweets;
            if(tmax < t) {
                tmax = t;
            }              
        }
    }
    
    var xaxis = scatterX();
    var yaxis = scatterY();
    var tweet = scatterZTweet();
    var reply = scatterZReply();
 var retweet = scatterZRetweet();
 
    var inner = "" + zmax;
 if(zmax > 0)
 {
  $('#maxdot').html(zmax + " tweet" + (zmax > 1 ? "s" : ""));
  $('#dotimg').css('z-index',0);
 }
 
    if(rmax > 0)
    {
  $('#maxreplydot').css('display','block');
  $('#maxreply').html(rmax + " repl" + (rmax > 1 ? "ies" : "y"));
  $('#dotimgr').css('z-index',tmax + 1).css('display','inline');
    }
 else
 {
  $('#maxreplydot').css('display','none');
  $('#dotimgr').css('display','none');
 }
 
 if(tmax > 0) 
 {
  $('#maxretweetdot').css('display','block');
  $('#maxretweet').html(tmax + " retweet" + (tmax > 1 ? "s" : ""));
  $('#dotimgt').css('z-index',rmax + 1).css('display','inline');
 }
 else
 {
  $('#maxretweetdot').css('display','none');
  $('#dotimgt').css('display','none');
 }
    
    $('#scatter').attr('src','http://chart.apis.google.com/chart?'+
        'chs=800x350' +
        '&chds=0,24,0,7,0,' + zmax +
        '&chf=bg,s,' + back +
        '&chd=t:' + xaxis + '|' + yaxis + '|' + tweet +                
        '&chxt=t,t,y,x'+
        '&chm=o,' + fore + ',1,1.0,55.0'+
        '&chxl=0:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|1:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|2:||Sun|Mon|Tue|Wed|Thr|Fri|Sat'+
        '&cht=s'+
        '&chxs=0,00000000,12,0,_|1,000000ff,12,0,_|2,000000ff,12,0,_|3,00000000,12,0,_');  
  
    $('#scatterr').attr('src','http://chart.apis.google.com/chart?'+
        'chs=800x350' +
        '&chds=0,24,0,7,0,' + zmax +
        '&chf=bg,s,' + back +
        '&chd=t:' + xaxis + '|' + yaxis + '|' + reply +                
        '&chxt=t,t,y,x'+
        '&chm=o,' + rply + ',1,1.0,55.0'+
        '&chxl=0:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|1:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|2:||Sun|Mon|Tue|Wed|Thr|Fri|Sat'+
        '&cht=s'+
        '&chxs=0,00000000,12,0,_|1,00000000,12,0,_|2,00000000,12,0,_|3,00000000,12,0,_');       
    $('#scatterr').css({'visibility' : 'visible'});
 
    $('#scattert').attr('src','http://chart.apis.google.com/chart?'+
         'chs=800x350' +
         '&chds=0,24,0,7,0,' + zmax +
         '&chf=bg,s,' + back +
         '&chd=t:' + xaxis + '|' + yaxis + '|' + retweet + 
         '&chxt=t,t,y,x'+
         '&chm=o,' + rtwt + ',1,1.0,55.0'+
         '&chxl=0:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|1:||12am|1|2|3|4|5|6|7|8|9|10|11|12pm|1|2|3|4|5|6|7|8|9|10|11|2:||Sun|Mon|Tue|Wed|Thr|Fri|Sat'+
         '&cht=s'+
         '&chxs=0,00000000,12,0,_|1,00000000,12,0,_|2,00000000,12,0,_|3,00000000,12,0,_');     
    $('#scattert').css({'visibility' : 'visible'});
 
    // max reply dot size relative to the max tweet dot size
 dotmargin = 10;
 dotsize = 55;
 boxsize = 175;
    rdot = Math.max(Math.ceil((rmax / zmax) * dotsize), 3);
    tdot = Math.max(Math.ceil((tmax / zmax) * dotsize), 3);
  
 center = (boxsize - dotsize) / 2;
    $('#dotimg').attr('src','http://chart.apis.google.com/chart?cht=v&chs='+55+'x'+55+'&chd=t:100&chco=' + fore + '&chf=bg,s,00000000');
 $('#dotimg').css('top', dotmargin).css('left', center);
    $('#dotimgr').attr('src','http://chart.apis.google.com/chart?cht=v&chs='+rdot+'x'+rdot+'&chd=t:100&chco=' + rply + '&chf=bg,s,00000000');
 $('#dotimgr').css('top', dotmargin + (dotsize - rdot) / 2).css('left', (boxsize - rdot) / 2);
    $('#dotimgt').attr('src','http://chart.apis.google.com/chart?cht=v&chs='+tdot+'x'+tdot+'&chd=t:100&chco=' + rtwt + '&chf=bg,s,00000000');
    $('#dotimgt').css('top', dotmargin + (dotsize - tdot) / 2).css('left', (boxsize - tdot) / 2);
    $('#maxdetail').css({'visibility' : 'visible'});
  
    function scatterX() {
        var xstr = '';
        for(var y = 0; y < 7; y++) {
            for(var x = 0; x < 24; x++) {
                xstr += (x + 1);
                if(x < 23 || y < 6) {
                    xstr += ',';
                }
            }
        }
        
        return xstr;
     }
     
     function scatterY() {    
        var ystr = '';
        for(var y = 0; y < 7; y++) {
            for(var x = 0; x < 24; x++) {
                ystr += (y + 1);
                if(x < 23 || y < 6) {
                    ystr += ',';
                }
            }
        }
        
        return ystr;
     }
     
     function scatterZTweet() {
         var zstr = '';
         for(var y = 0; y < 7; y++) {
             for(var x = 0; x < 24; x++) {
                zstr += scatterCount[x][y].count; 
                if(x < 23 || y < 6) {
                    zstr += ',';
                }           
             }
         }
         
         return zstr;
     }     
     
     function scatterZReply() {
         var zstr = '';
         for(var y = 0; y < 7; y++) {
             for(var x = 0; x < 24; x++) {
                zstr += scatterCount[x][y].replies; 
                if(x < 23 || y < 6) {
                    zstr += ',';
                }           
             }
         }
         
         return zstr;
      }
     
     function scatterZRetweet() {
         var zstr = '';
         for(var y = 0; y < 7; y++) {
             for(var x = 0; x < 24; x++) {
                zstr += scatterCount[x][y].retweets; 
                if(x < 23 || y < 6) {
                    zstr += ',';
                }           
             }
         }
         
         return zstr;
      }
}

function showNames() 
{    
    var nameDiv = $('#names');
    nameDiv.html('');
    
    var keys = [];
    for(i in names)
    {
        keys[keys.length] = i;       
    }
    keys.sort();   
    
    for(var k = 0; k < keys.length; k++) 
    {
        var i = names[keys[k]];
        if(i != null) 
        {
            name = keys[k];
            
            var repl = $(document.createElement("div"));
            repl.addClass('college');
            repl.attr('id', 'coll' + name);
            nameDiv.append(repl);
            
            var innerHTML = '<a href="http://xefer.com/twitter/' + name + '">' + name + '</a> <span>(' + i.count + ')</span> <span class="expander" id="' + name + '">[+]</span>';
            
            repl.html(innerHTML);
        }
    }

    $('.expander').toggle(
        function() {
            var name = $(this).attr('id');  

            if(this.loaded != true)
            {
                var tweets = names[name].tweets;
                var conv = $(document.createElement('div'));
                $(conv).addClass('convs');
                $(conv).attr('id', 'convs' + name);
                this.loaded = true;

                var innerHTML = '';            
                for(var j in tweets) 
                {
                   if(tweets[j].tweet)
                   {
                      innerHTML += '<div class="conv"><div class="permalink"><a title="permalink: http://xefer.com/thread/' + tweets[j].tweet + '" href="http://xefer.com/thread/' + tweets[j].tweet + '"><img src="/image/icon_link.gif"/></a></div><div class="tweet" id="' + tweets[j].tweet + '"><span id="t' + tweets[j].tweet + '"></span></div></div>';
                   }
                }     
                $(conv).html(innerHTML);     
                $(this).after($(conv));
                loadConv(name);
            }

            $(this).html("[-]"); 
            $(this).next('.convs').css({'display' : 'block'});            
        },
        function() {
            $(this).html("[+]");
            $(this).next('.convs').css({'display' : 'none'});
        }
    );
    
    sortByDate(true);
}

function sortByCount(dir)
{
   keys = [];
   for(name in names)
   {
      keys[keys.length] = names[name];   
   }
   keys.sort(function(a, b) {
      if(a.count == b.count)
      {
        return (a.tweets[0].name > b.tweets[0].name) ? 1 : -1;
      }
      else
      {
        val = dir ? b.count - a.count : a.count - b.count;
        return val;
      }
   });
   for(i = 0; i < keys.length; i++)
   {
       keys[i] = keys[i].tweets[0].name;
   }
   
   sortNameElements(keys);
}

function sortByDate(dir)
{
   keys = [];
   for(name in names)
   {
      keys[keys.length] = names[name].tweets[0];  
   }
   keys.sort(function(a, b) {
      return dir ? b.time - a.time : a.time - b.time;
   });
   for(i = 0; i < keys.length; i++)
   {
       keys[i] = keys[i].name;
   }
   
   sortNameElements(keys);
}

function sortByName(dir)
{
    var keys = [];
    for(name in names)
    {
        keys[keys.length] = name;       
    }
    keys.sort(function(a, b) {
        if(dir)
        {
            return (a > b) ? -1 : 1;
        }
        else
        {
            return (b > a) ? -1 : 1;
        }
    });
       
    sortNameElements(keys);
}

function sortNameElements(keys)
{
   var nodes = $('#names');
   for(var i = 0; i < keys.length; i++)
   {
      $('#coll' + keys[i]).appendTo(nodes);
   }
}

function sort(ordering)
{
    if(ordering != null)
    {
        ordering = ordering.slice(1);
        var asc = ordering.indexOf("-") != -1;
        if(ordering.indexOf("name") >= 0)
        {
            sortByName(asc);
        }
        else if(ordering.indexOf("date") >= 0)
        {
            sortByDate(asc);
        }
        else if(ordering.indexOf("freq") >= 0)
        {
            sortByCount(asc);
        }
    }
}

function loadConv(tweeter)
{
  var ids = $('#convs' + tweeter).find(".tweet");
  for(var i = 0; i < ids.length; i++)
  {
    var id = ids[i].getAttribute('id');
    if(id != null && id.length > 0)
    {
        loadTweet(ids[i].getAttribute('id'));
    }
  }
}

/*
 * See: http://delete.me.uk/2005/03/iso8601.html
 */
Date.prototype.setISO8601 = function (string)
{
    var regexp = "(.{3}) ((.{3})) ([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([-+])([0-9]{4}) ([0-9]{4})";
    var d = string.match(new RegExp(regexp));

    var date = new Date(d[10], 0, 1);
    var offset = 0;
    
    date.setMonthStr(d[3]);
    date.setDate(d[4]);
    date.setHours(d[5]);
    date.setMinutes(d[6]);
    date.setSeconds(d[7]);
    
    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    this.setTime(Number(time));
}

Date.prototype.setMonthStr = function (string)
{
    var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
    var month = months.indexOf(string);
    this.setMonth(month);
}

if(!Array.indexOf)
{
    Array.prototype.indexOf = function(obj)
    {
        for(var i=0; i<this.length; i++)
        {
            if(this[i]==obj)
            {
                return i;
            }
        }
        return -1;
    }
}

