/* Copyright 2010 Ian George - http://www.iangeorge.net

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/


(function($){$.fn.tagcloud=function(options){var opts=$.extend($.fn.tagcloud.defaults,options);opts.drawing_interval=1/(opts.fps/1000);$(this).each(function(){$('ul',$(this)).css('display','none');new TagCloudClass($(this),opts);});return this;};$.fn.tagcloud.defaults={zoom:90,max_zoom:120,min_zoom:25,zoom_factor:2,rotate_factor:-0.45,fps:10,centrex:250,centrey:250,min_font_size:12,max_font_size:32,font_units:'px',random_points:0};var TagCloudClass=function(el,options){$(el).css('position','relative');var eyez=-500;var rad=Math.PI/180;var global_cos=Math.cos(0);var hex=new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");var dirty=true;var container=$(el);var id_stub='tc_'+$(el).attr('id')+"_";var opts=options;var zoom=opts.zoom;var depth;var lastx=0;var lasty=0;var points=[];points['data']=[];var drawing_interval;var cmx=options.centrex;var cmy=options.centrey;var bg_colour,fg_colour;if(options.background_colour){bg_colour=parsecolour(options.background_colour);}else{bg_colour=parsecolour($(el).css('background-color'));}
if(options.foreground_colour){fg_colour=parsecolour(options.foreground_colour);}else{fg_colour=parsecolour($(el).css('color'));}
function parsecolour(colour){function parse_rgb_colour(colour){rgb=colour.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);if(rgb.length>3){return{"r":parseInt(rgb[1]),"g":parseInt(rgb[2]),"b":parseInt(rgb[3])};}else{return{"r":0,"g":0,"b":0};}}
function parse_hex_colour(colour){var r=0,g=0,b=0;if(colour.length>4)
{r=parseInt(colour.substr(1,2),16);g=parseInt(colour.substr(3,2),16);b=parseInt(colour.substr(5,2),16);}
else
{r=parseInt(colour.substr(1,1)+colour.substr(1,1),16);g=parseInt(colour.substr(2,1)+colour.substr(2,1),16);b=parseInt(colour.substr(3,1)+colour.substr(3,1),16);}
return{"r":r,"g":g,"b":b};}
if(colour.substr(0,1)==='#')
{return parse_hex_colour(colour);}
else if(colour.substr(0,3)==='rgb')
{return parse_rgb_colour(colour);}
else{if(window.console!=undefined)
console.log("unable to parse:'"+colour+"' please ensure background and foreground colors for the container are set as hex values");return null;}}
function getcolour(num){if(num>256){num=256;}
if(num<0){num=0;}
var r=getshade(bg_colour.r,fg_colour.r,num);var g=getshade(bg_colour.g,fg_colour.g,num);var b=getshade(bg_colour.b,fg_colour.b,num);var ret="rgb("+r+", "+g+", "+b+")";return ret;}
function getshade(lbound,ubound,dist){var scope=ubound-lbound;var dist_percent=scope/100;var shade=Math.round(lbound+(dist*dist_percent));return shade;}
function rotx(s,c){for(var p in points.data)
{var temp=s*points.data[p].y+c*points.data[p].z;points.data[p].y=c*points.data[p].y-s*points.data[p].z;points.data[p].z=temp;}}
function roty(s,c){for(var p in points.data){var temp=-s*points.data[p].x+c*points.data[p].z;points.data[p].x=c*points.data[p].x+s*points.data[p].z;points.data[p].z=temp;}}
function rotz(s,c){for(var p in points.data){var temp=s*points.data[p].x+c*points.data[p].y;points.data[p].x=c*points.data[p].x-s*points.data[p].y;points.data[p].y=temp;}}
function zoomed(by){zoom+=by*opts.zoom_factor;if(zoom>opts.max_zoom){zoom=opts.max_zoom;}
if(zoom<opts.min_zoom){zoom=opts.min_zoom;}
depth=-(zoom*(eyez-opts.max_zoom)/100)+eyez;}
function moved(mx,my){if(mx>lastx){var angle=mx-lastx;var sin=-Math.sin(angle*options.rotate_factor*rad);var cos=Math.cos(angle*options.rotate_factor*rad);roty(sin,cos);}
if(mx<lastx){var angle=lastx-mx;var sin=Math.sin(angle*options.rotate_factor*rad);var cos=Math.cos(angle*options.rotate_factor*rad);roty(sin,cos);}
if(my>lasty){var angle=my-lasty;var sin=Math.sin(angle*options.rotate_factor*rad);var cos=Math.cos(angle*options.rotate_factor*rad);rotx(sin,cos);}
if(my<lasty){var angle=lasty-my;var sin=-Math.sin(angle*options.rotate_factor*rad);var cos=Math.cos(angle*options.rotate_factor*rad);rotx(sin,cos);}
lastx=mx;lasty=my;dirty=true;}
function draw(){if(dirty){var smallz=10000;var bigz=-10000;for(var r_p in points.data){if(points.data[r_p].z<smallz){smallz=points.data[r_p].z;}
if(points.data[r_p].z>bigz){bigz=points.data[r_p].z;}}
var minz=Math.min(smallz,bigz);var maxz=Math.max(smallz,bigz);var diffz=maxz-minz;for(var s_p in points.data){var u=(depth-eyez)/(points.data[s_p].z-eyez);var dist=Math.round(((maxz-points.data[s_p].z)/diffz)*100);var dist_colour=getcolour(dist);$('#'+points.data[s_p].id+' a',container).css('color',dist_colour);$('#'+points.data[s_p].id,container).css('z-index',dist);$('#'+points.data[s_p].id,container).css('left',u*points.data[s_p].x+cmx-points.data[s_p].cwidth);$('#'+points.data[s_p].id,container).css('top',u*points.data[s_p].y+cmy);}
dirty=false;}}
points.count=$('li a',container).length;points.largest=1;points.smallest=0;$('li a',container).each(function(idx,val){var sz=parseInt($(this).attr('rel'));if(sz==0)
sz=1;points.data[idx]={id:id_stub+idx,size:sz};var h=-1+2*(idx)/(points.count-1);points.data[idx].theta=Math.acos(h);if(idx==0||idx==points.count-1){points.data[idx].phi=0;}
else{points.data[idx].phi=(points.data[idx-1].phi+3.6/Math.sqrt(points.count*(1-Math.pow(h,2))))%(2*Math.PI);}
points.data[idx].x=Math.cos(points.data[idx].phi)*Math.sin(points.data[idx].theta)*(cmx/2);points.data[idx].y=Math.sin(points.data[idx].phi)*Math.sin(points.data[idx].theta)*(cmy/2);points.data[idx].z=Math.cos(points.data[idx].theta)*(cmx/2);if(sz>points.largest)points.largest=sz;if(sz<points.smallest)points.smallest=sz;container.append('<div id="'+id_stub+idx+'" class="point" style="position:absolute;display:none;"><a href='+$(this).attr('href')+'>'+$(this).html()+'</a></div>');});if(opts.random_points>0){for(b=0;b<opts.random_points;b++){points.count++;points.data[points.count]={id:id_stub+points.count,size:1};points.data[points.count].theta=Math.random()*2*Math.PI;points.data[points.count].phi=Math.random()*2*Math.PI;points.data[points.count].x=Math.cos(points.data[points.count].phi)*Math.sin(points.data[points.count].theta)*(cmx/2);points.data[points.count].y=Math.sin(points.data[points.count].phi)*Math.sin(points.data[points.count].theta)*(cmy/2);points.data[points.count].z=Math.cos(points.data[points.count].theta)*(cmx/2);container.append('<div id="'+id_stub+points.count+'" class="point" style="position:absolute;"><a>.</a></div>');}}
var sz_range=points.largest-points.smallest+1;var sz_n_range=opts.max_font_size-opts.min_font_size+1;for(var p in points.data){var sz=points.data[p].size;var sz_n=parseInt((sz/sz_range)*sz_n_range)+opts.min_font_size;if(!$('#'+points.data[p].id,container).hasClass('background')){$('#'+points.data[p].id,container).css('font-size',sz_n);}
points.data[p].cwidth=$('#'+points.data[p].id,container).width()/2;}
$('ul',container).remove();depth=-(zoom*(eyez-opts.max_zoom)/100)+eyez;moved(cmx,cmy);draw();$('.point',container).css('display','inherit');drawing_interval=setInterval(draw,opts.drawing_interval);container.mousemove(function(evt){moved(evt.clientX,evt.clientY);});container.mousewheel(function(evt,delta){zoomed(delta);evt.preventDefault();return false;});};})(jQuery);
