var Color=new Native({initialize:function(b,c){if(arguments.length>=3){c="rgb";b=Array.slice(arguments,0,3)}else{if(typeof b=="string"){if(b.match(/rgb/)){b=b.rgbToHex().hexToRgb(true)}else{if(b.match(/hsb/)){b=b.hsbToRgb()}else{b=b.hexToRgb(true)}}}}c=c||"rgb";switch(c){case"hsb":var a=b;b=b.hsbToRgb();b.hsb=a;break;case"hex":b=b.hexToRgb(true);break}b.rgb=b.slice(0,3);b.hsb=b.hsb||b.rgbToHsb();b.hex=b.rgbToHex();return $extend(b,this)}});Color.implement({mix:function(){var a=Array.slice(arguments);
var c=($type(a.getLast())=="number")?a.pop():50;var b=this.slice();a.each(function(d){d=new Color(d);for(var e=0;e<3;e++){b[e]=Math.round((b[e]/100*(100-c))+(d[e]/100*c))}});return new Color(b,"rgb")},invert:function(){return new Color(this.map(function(a){return 255-a}))},setHue:function(a){return new Color([a,this.hsb[1],this.hsb[2]],"hsb")},setSaturation:function(a){return new Color([this.hsb[0],a,this.hsb[2]],"hsb")},setBrightness:function(a){return new Color([this.hsb[0],this.hsb[1],a],"hsb")}});var $RGB=function(d,c,a){return new Color([d,c,a],"rgb")};var $HSB=function(d,c,a){
return new Color([d,c,a],"hsb")};var $HEX=function(a){return new Color(a,"hex")};Array.implement({rgbToHsb:function(){var b=this[0],c=this[1],j=this[2];var g,f,h;var i=Math.max(b,c,j),e=Math.min(b,c,j);var k=i-e;h=i/255;f=(i!=0)?k/i:0;if(f==0){g=0}else{var d=(i-b)/k;var a=(i-c)/k;var l=(i-j)/k;if(b==i){g=l-a}else{if(c==i){g=2+d-l}else{g=4+a-d}}g/=6;if(g<0){g++}}return[Math.round(g*360),Math.round(f*100),Math.round(h*100)]},hsbToRgb:function(){var c=Math.round(this[2]/100*255);if(this[1]==0){return[c,c,c]}else{var a=this[0]%360;var e=a%60;var g=Math.round((this[2]*(100-this[1]))/10000*255);
var d=Math.round((this[2]*(6000-this[1]*e))/600000*255);var b=Math.round((this[2]*(6000-this[1]*(60-e)))/600000*255);switch(Math.floor(a/60)){case 0:return[c,b,g];case 1:return[d,c,g];case 2:return[g,c,b];case 3:return[g,d,c];case 4:return[b,g,c];case 5:return[c,g,d]}}return false}});String.implement({rgbToHsb:function(){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHsb():null},hsbToRgb:function(){var a=this.match(/\d{1,3}/g);return(a)?a.hsbToRgb():null}});

var viz;
window.addEvent('domready', function(){
  Element.implement({
		getOuterHeight: function() {
			return this.getHeight()
        +this.getStyle('margin-top').toInt()
        +this.getStyle('margin-bottom').toInt()
        +this.getStyle('border-top-width').toInt()
        +this.getStyle('border-bottom-width').toInt();
		}
	});
	Array.implement({
  	shuffle: function() {
  		for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
  		return this;
  	}
  });

  viz = new Vizeddit();
})

var Vizeddit = new Class({
  initialize: function() {
    this.viz = $('viz');
    this.storybar = $('story');
    this.title = $('title');
    this.upvotes = $('upvotes');
    this.score = $('score');
    this.downvotes = $('downvotes');
    this.comments = $('comments');
    this.storybartimer = false;
    this.storycolor = $('storycolor');
    this.storycolorani = new Fx.Tween(this.storycolor,{duration:500,wait:false});
    this.storycolorrank = this.storycolor.getElement('span');
    this.resetting = false;
    this.updateNum = 0;
    this.runCommentUpdate = false;
    $('storybg').setStyle('opacity',.7);

    [this.title,this.upvotes,this.downvotes,this.score,this.comments].each(function(el){
      el.store('ani',new Fx.Morph(el,{duration:200,wait:false}));
    });

    this.storybar.store('ani',new Fx.Morph(this.storybar,{duration:350,wait:false}));
    this.storybar.addEvents({
      'mouseenter':this.storyCloseStop.bind(this),
      'mouseleave':this.storyCloseQueue.bind(this)
    });

    this.setSizes();
    this.setColors();

    this.bigThingsComing();

    this.request = new Request.JSON({
      'method':'get',
      'url':'/frontpageproxy.php?initial=true&vizeddit=true&nocache='+$random(1,99999),
      'onFailure': this.goFailDamnYou,
      'onSuccess': function(r){
        this.buildColumns(r);
        this.commentsRequest.send({'url':'/comments/commentsproxy.php?initial=true&vizeddit=true&nocache='+$random(1,99999)});
      }.bind(this)
    }).send();

    this.commentsRequest = new Request.JSON({
      'method':'get',
      'onFailure': this.goFailDamnYou.bind(this),
      'onSuccess': this.showComments
    });

    this.request = new Request.JSON({
      'method':'get',
      'onFailure': this.goFailDamnYou,
      'onSuccess':function(r){
        this.columnUpdate(r);
        this.commentsRequest.send({'url':'/comments/commentsproxy.php?vizeddit=true&nocache='+$random(1,99999)});
      }.bind(this)
    });

    this.updateTimer = setInterval(function(){
      this.request.send({'url':'/frontpageproxy.php?vizeddit=true&nocache='+$random(1,99999)});
    }.bind(this),30000);

    window.addEvent('resize',this.handleResize.bindWithEvent(this));
  },

  bigThingsComing: function() {
    var type = $random(0,1) == 1 ? "up":"down";
    var big = new Element('div',{
      'class':'big'+type,
      'styles':{
        'top':'-278px',
        'left': $random(-100,window.getWidth()-100)+'px',
        'opacity':0.2
      }
    }).inject(this.viz);
    var duration = $random(2000,5000)
    var ani = new Fx.Morph(big,{"duration": duration}).start({'top':window.getHeight()+'px'});

    var destroy = function() {
      big.dispose();
      ani = null;
    }

    destroy.delay(duration);
    this.bigThingsComing.bind(this).delay($random(250,6000));
  },
  killColumn: function(col) {
    var block = col.retrieve('block');

    block.retrieve('ani').start({'height':'0px','opacity':0}).chain(function(){
      block.dispose();
      col.dispose();
    });
  },
  moveColumn: function(column) {
    var left = column.getStyle('left').toInt();
    var block = column.retrieve('block');
    var rank = block.retrieve('rank');
    var rankpercent = (rank)*4;
    if(left == rankpercent) {
      return;
    } else {
      column.setStyles({
        'z-index':25,
        'left': (left/100)*window.getWidth()+'px' // Convert % to px
      });

      var pxper = window.getWidth()*(rankpercent/100)+'px';
      block.retrieve('ani').start({'background-color':this.colors[rank].hex});


      var a = new Fx.Morph(column,{duration:500}).start({
        'left':pxper
      }).chain(function(){
        column.setStyles({'left':rankpercent+'%','z-index':7});
        block.getElement('.rank').set('text',rank+1);
      })
      var destroy = function(){a=null;};
      destroy.delay(1000);
    }
  },
  columnUpdate: function(r) {
    if(r == null || r.fail){
      return this.goFailDamnYou();
    }
    this.updateNum++;
    var data = r.data.children;
    var rebuild = false;
    data.each(function(red,i){
      red = red.data;
      var col = $(red.id);
      if(!$chk(col)) {
        var pos = i+1;
        var color = this.colors[i];
        col = this.buildColumn(red,i,color,500);
      }

      var bl = col.retrieve('block');
      bl.store('rank',i);
      col.store('updateNum',this.updateNum);

      var oldData = col.retrieve("redditData");
      var up = red.ups-oldData.ups;
      var down = red.downs-oldData.downs;
      var com = red.num_comments-oldData.num_comments;
      //update if we have negative happenings
      if(up < 0){
        oldData.ups = red.ups;
      }
      if(down < 0){
        oldData.downs = red.downs;
      }
      if(com < 0){
        oldData.num_comments = red.num_comments;
      }
      col.store("redditData", oldData);

      for(var x=0;x<up;x++) {
        setTimeout(function(){this.blockUpvote(col.retrieve('block'),col)}.bind(this),$random(500,60000));
      }

      for(var x=0;x<down;x++) {
        setTimeout(function(){this.blockDownvote(col.retrieve('block'),col)}.bind(this),$random(500,60000));
      }

      for(var x=0;x<com;x++) {
        setTimeout(function(){this.blockComment(col.retrieve('block'),col)}.bind(this),$random(500,60000));
      }

    },this)

    $$('.column').each(function(col){
      if(col.retrieve('updateNum') != this.updateNum) {
        this.killColumn(col);
      } else {
        this.moveColumn(col);
      }
    },this)
  },
  showComments: function(r){
    var commentsArray = {};
    if(r == null || r.fail || r.length < 0){
      return;
    }
    r.each(function(comment, index){
      link_id = comment.link_id.split("_")[1];
      if($chk($(link_id))){
        if(!$defined(commentsArray[link_id])){
          commentsArray[link_id] = new Array({"author":comment.author, "body":comment.body});
        }else{
          commentsArray[link_id].push({"author":comment.author, "body":comment.body});
        }
      }
    })
    for(linkid in commentsArray){
      var oldArray = $(linkid).retrieve("commentsArray");
      if(oldArray){
        commentsArray[linkid] = commentsArray[linkid].concat(oldArray);
      }
      $(linkid).store("commentsArray", commentsArray[linkid]);
    }
  },
  handleResize: function() {
    this.blocksize = Math.floor(window.getWidth()*.04-8);
    this.upheight = (this.viz.getHeight()-Math.ceil(this.blocksize/2)-5);

    $$('.linkblock').each(function(bl){bl.setStyle('width',this.blocksize+'px')},this);
    this.setSizes();
  },
  buildColumns: function(r) {
    if(r == null || r.fail){
      return this.goFailDamnYou();
    }
    if($defined(r[0])){
      var data = r[0].data.children;
    }else{
      var data = r.data.children;
    }

    this.blocksize = Math.floor(window.getWidth()*.04-8);
    this.upheight = (this.viz.getHeight()-Math.ceil(this.blocksize/2)-5);

    data.each(function(d,x){
      this.buildColumn(d.data,x,this.colors[x],x*100);
      new Element('div',{'class':'columnline','styles':{'left':(x*4)+'%'}}).inject(this.viz);
    },this);

    this.columns = $$('div.column');
    if($defined(r[1])){
      this.columnUpdate.delay(5000, this, r[1]);
    }
  },
  buildColumn: function(data,pos,color,showdelay) {
    var col = new Element('div',{'class':'column','id':data.id,'styles':{'left':(pos*4)+'%'}}).inject(this.viz);

    data.title = data.title.replace(/&lt;/g, '<');
    data.title = data.title.replace(/&gt;/g, '>');
    data.title = data.title.replace(/&amp;/g, '&');
    data.title = data.title.replace(/&quot;/g, '"');


    col.store('redditData',{
      title: data.title,
      ups: data.ups,
      downs: data.downs,
      num_comments: data.num_comments,
      url: data.url,
      id: data.id
    });
    col.store('commentsArray', false);

    var bl = new Element('div',{
      'class':'linkblock',
      'styles':{
        'left':'4px',
        'bottom':this.upheight+'px',
        'height':'25px',
        'width':this.blocksize+'px',
        'background-color':color,
        'opacity':0
      }
    }).inject(col).store('bgcol',color);

    var rank = new Element('div',{
      'class':'rank',
      'text': pos+1
    }).inject(bl);

    col.store('block',bl);
    bl.store('ani',new Fx.Morph(bl,{duration:500,wait:false}));
    bl.store('rankel',rank);
    bl.store('rank',pos);
    bl.store('animating','no');

    var showup = function() {
      // Start animations
      bl.retrieve('ani').setOptions({transition:Fx.Transitions.Bounce.easeOut,duration:1500}).start({'bottom':'5px','opacity':1}).chain(function(){
        bl.retrieve('ani').setOptions({transition:Fx.Transitions.Linear,duration:150});

        // Add events now that the animation is done, otherwise mouseenter could stop the ani
        bl.addEvents({
          'mouseenter': this.blockEnter.bind(this,[bl,col]),
          'mouseleave': this.blockExit.bind(this,[bl,col])
        })
      }.bind(this));
    };

    if(!$type(showdelay)) {
      var showdelay = 15;
    }

    showup.delay(showdelay, this);
    return col;
  },
  blockEnter: function(block,column) {
    this.showStoryBar(column,block);
  },
  blockExit: function(block,column) {
    this.storyCloseQueue();
  },
  blockUpvote: function(block, column) {
    var data = column.retrieve('redditData');
    if(data == null){
      return;
    }
    data.ups++;

    if(this.storybar.retrieve('curBlock') == block) {
      this.setNumValue(this.upvotes,data.ups);
      this.setNumValue(this.score,data.ups-data.downs);
    }

    if(block.getHeight() >= this.upheight-20) {
      this.resetting = true;
      var shrink = function(){
        $$('.linkblock').each(function(e){
          e.retrieve('ani').start({'height':Math.ceil(this.blocksize/2)+'px'});
        },this)
      };

      var reset = function(){
        this.resetting=false;
      };

      shrink.bind(this).delay(1000);
      reset.bind(this).delay(2000);
    }

    if(this.resetting) {
      return;
    }

    var left = (this.blocksize-40)/2+4;
    var dropper = new Element('div',{
      'class': 'upper',
      'styles': {
        'top':'-100px',
        'left':left+'px'
      }
    }).inject(column);

    var ani = new Fx.Morph(dropper,{duration:1400,transition:Fx.Transitions.Expo.easeIn}).start({'top':this.viz.getHeight()+'px'});

    var whit = function() {
      if(block.retrieve('animating')=='no') {
        block.store('animating','yes');
        block.retrieve('ani').start({'background-color':'#fff','height':block.getHeight()+2+'px'}).chain(function(){
          this.start({'background-color':block.retrieve('bgcol').hex});
          block.store('animating','no');
        })
      } else {
        block.retrieve('ani').start({'background-color':block.retrieve('bgcol').hex,'height':block.getHeight()+2+'px'});
      }
    }

    var destroy = function() {
      dropper.dispose();
      ani = null;
    }

    whit.delay(1200, this);
    destroy.delay(2000);

  },
  blockDownvote: function(block, column) {
    var data = column.retrieve('redditData');
    if(data == null){
      return;
    }
    data.downs++;

    if(this.storybar.retrieve('curBlock') == block) {
      this.setNumValue(this.downvotes,data.downs);
      this.setNumValue(this.score,data.ups-data.downs);
    }

    var left = (this.blocksize-40)/2+4;
    var dropper = new Element('div',{
      'class': 'downer',
      'styles': {
        'top':'-100px',
        'left':left+'px'
      }
    }).inject(column);

    var shaky = function(){
      if(block.retrieve('animating')=='no') {
        block.store('animating','yes');
        block.retrieve('ani').setOptions({duration:50}).start({'left':'2px','background-color':'#f00'}).chain(
          function(){this.start({'left':'6px','background-color':block.retrieve('bgcol').hex})},
          function(){this.start({'left':'2px','background-color':'#f00'})},
          function(){
            this.start({'left':'4px','background-color':block.retrieve('bgcol').hex}).setOptions({duration:150})
            block.store('animating','no');
          }
        )

      }
    };

    shaky.delay(1400);

    var ani = new Fx.Morph(dropper,{duration:1400,transition:Fx.Transitions.Expo.easeIn}).start({'top':this.viz.getHeight()+'px'});
    var destroy = function() {
      dropper.dispose();
      ani = null;
    }
    destroy.delay(2000);
  },
  blockComment: function(block, column) {
    var data = column.retrieve('redditData');
    if(data == null){
      return;
    }
    data.num_comments++;

    if(this.storybar.retrieve('curBlock') == block) {
      this.setNumValue(this.comments,data.num_comments);
    }
    var commentsArray = column.retrieve('commentsArray');
    if(commentsArray) {
      var comment = commentsArray.shift();
      if(commentsArray.length == 0){
        commentsArray = false;
      }
      column.store('commentsArray', commentsArray);
      var left = column.getStyle("left").toInt()/100*this.viz.getWidth();
      left += Math.floor((column.getWidth()-39)/2);

      var dropper = new Element('div',{
        'class': 'comment',
        'styles': {
          'position':'absolute',
          'width':window.getWidth()-8+'px',
          'opacity':0
        }
      }).inject(this.viz);

      comment.body = comment.body.replace(/&lt;/g, '<');
      comment.body = comment.body.replace(/&gt;/g, '>');
      comment.body = comment.body.replace(/&amp;/g, '&');
      comment.body = comment.body.replace(/&quot;/g, '"');


      new Element('div', {'class':'commentAuthor','text':comment.author}).inject(dropper);
      new Element('div',{'class':'commentBody','text':comment.body}).inject(dropper);
      new Element('div',{
        'class':'commentTip',
        'styles':{
          'left':left+'px'
        }
      }).inject(dropper);

      dropper.setStyles({'top':-dropper.getHeight()+'px','opacity':1});
      var ani = new Fx.Morph(dropper,{duration:$random(5000,7500)}).start({'top':this.viz.getHeight()+100+'px'}).chain(function(){
        dropper.dispose();
        ani = null;
      });
    }
  },
  setSizes: function() {
    this.viz.setStyle('height',window.getHeight()-$('h1').getOuterHeight()+'px');
    this.title.setStyle('width',window.getWidth()-580);
  },
  setTitle: function(title, url) {
    this.title.retrieve('ani').start({'opacity':0}).chain(function(){
      this.title.setStyle('padding-top','0px').set('text',title).set("href", url);
      if(this.title.getHeight()<25) { // It's a single line
        this.title.setStyle('padding-top','13px');
      }
      this.title.retrieve('ani').start({'opacity':1});
    }.bind(this))
  },
  showStoryBar: function(column,block) {
    this.storyCloseStop();
    if($type(column) && $type(block) && this.storybar.retrieve('curBlock')!=block) {
      var data = column.retrieve('redditData');
      this.storycolorani.start('background-color',block.retrieve('bgcol').hex);
      this.storycolorrank.set('text',block.retrieve('rank')+1);
      this.setTitle(data.title, data.url);
      this.setNumValue(this.comments,data.num_comments);
      this.setNumValue(this.upvotes,data.ups);
      this.setNumValue(this.downvotes,data.downs);
      this.setNumValue(this.score,data.ups-data.downs);
      this.comments.set("href", "http://reddit.com/comments/"+data.id);
      this.storybar.store('curBlock',block);
    }

    this.storybar.retrieve('ani').start({'top':'41px'});
  },
  hideStoryBar: function() {
    this.storybar.retrieve('ani').start({'top':'-10px'});
  },
  storyCloseStop: function() {
    $clear(this.storybartimer);
  },
  storyCloseQueue: function() {
    this.storybartimer = this.hideStoryBar.bind(this).delay(1000);
  },
  setColors: function() {
    this.colors = new Array();
    for(var x=0;x<25;x++) {
      this.colors.push(new Color([x*13.8,100,100],'hsb'));
    }
    this.colors.shuffle();
  },
  setNumValue: function(el,value) {
    value = this.numberFormat(value);
    el.retrieve('ani').start({'opacity':0}).chain(function(){
      el.set('text',value);
      this.start({'opacity':1});
    })
  },
  numberFormat: function(n) {
    n = n.toString().split('.');
    var n0 = n[0];
    var n1 = n.length > 1 ? '.'+n[1]:'';
    while(n0.match(/(\d+)(\d{3})/)) {
      n0 = n0.replace(/(\d+)(\d{3})/,'$1,$2');
    }
    return n0+n1;
  },
  goFailDamnYou: function() {
    $clear(this.updateTimer);
    $clear(this.commentTimer);
    $('failnotice').setStyle('display','');
  }
})