/*
SparqlCloud
*/

/*
Public functions
*/

function SparqlCloud(cloud, loader) {
  this.cloud=document.getElementById(cloud);
  this.cloud=(typeof this.cloud == 'undefined')?null:this.cloud;
  this.loader=document.getElementById(loader);
  this.loader=(typeof this.loader == 'undefined')?null:this.loader;
  this.response='';
  this.excludes={};

  this.layout='center';
  this.msg='?';
  this.minsize=80;
  this.maxsize=180;
  this.mincolor=[81,165,192];
  this.maxcolor=[0,92,137];
  this.highlight=null;

  sc=this;
  if (typeof window.onresize!='function') {
    window.onresize = function() { sc.onresize(); }
  } else {
    var old_onresize = window.onresize;
    window.onresize = function() { old_onresize(); sc.onresize(); }
  }
}

function SparqlCloud_setopts(layout, msg, minsize, maxsize, mincolor, maxcolor, highlight) {
  this.layout=layout;
  this.msg=msg;
  this.minsize=minsize;
  this.maxsize=maxsize;
  this.mincolor=mincolor;
  this.maxcolor=maxcolor;
  this.highlight=highlight;
}
SparqlCloud.prototype.setopts=SparqlCloud_setopts;

function SparqlCloud_exclude(cat) {
  this.excludes[cat]=1;
}
SparqlCloud.prototype.exclude=SparqlCloud_exclude;

function SparqlCloud_show(uri) {
  sc=this;
  // Show loader
  if (sc.loader) sc.loader.style.display = 'block';
  // Fetch...
  var http = new SparqlCloud_HTTP();
  http.open("GET", uri, true);
  http.onreadystatechange = function() {
    if (http.readyState == 4) {
      try {
        sc.response = http.responseText;
      } catch(e) {
        sc.response = '{ "Invalid response" }';
      }
      // Display...
      sc.display();
      // Hide loader
      if (sc.loader) sc.loader.style.display = 'none';
    }
  }
  http.send(null);
}
SparqlCloud.prototype.show=SparqlCloud_show;

function SparqlCloud_HTTP() {
  var xmlhttp;
  if (typeof XMLHttpRequest != 'undefined') {
    xmlhttp=new XMLHttpRequest();
  } else {
    if (typeof ActiveXObject !='undefined') {
      try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {}
    }
  }
  return xmlhttp;
}

function SparqlCloud_showonload(uri) {
  sc=this;
  if (typeof window.onload!="function") {
    window.onload = function() { sc.show(uri); }
  } else {
    var old_onload = window.onload;
    window.onload = function() { old_onload(); sc.show(uri); }
  }
}
SparqlCloud.prototype.showonload=SparqlCloud_showonload;

function SparqlCloud_onresize() {
  this.display();
}
SparqlCloud.prototype.onresize=SparqlCloud_onresize;

function SparqlCloudTag(bindings, highlight) {
  this.slug = bindings.Slug.value;
  this.name = bindings.Name.value.replace('/ /g', '&nbsp;');
  this.highlight = (highlight && bindings.Description.value==highlight)?1:0;
  this.count = parseInt(bindings.Count.value);
  this.link = bindings.Link.value;
  this.color = [];
  this.size = 100;
  this.title = this.name + ': ' + this.count;// + ' fragment' + (this.count != 1?'s':'');
  this.count = Math.log(this.count)+1;
}
function SparqlCloudTag_toString() {
  return '<a style="color: rgb(' + this.color[0] + ',' + this.color[1] + ',' + this.color[2] + '); font-size: ' + this.size + '%" href="' + this.link + '" class="' + (this.link==location.href?'current ':'') + (this.highlight==1?'highlight':'') + '" title="' + this.title + '">' + this.name + '</a> ';
}
SparqlCloudTag.prototype.toString=SparqlCloudTag_toString;

function SparqlCloud_display() {
  if (!this.cloud)
    return;
    
  var res = eval('(' + this.response + ')');

  this.tags = new Array();
  this.min_count = 0;
  this.max_count = 0;
  this.max_id = 0;
  for (var i=0; i<res.results.bindings.length; i++) {
    var cat = new SparqlCloudTag(res.results.bindings[i], this.highlight);
    if (cat.slug in this.excludes) continue;
    this.tags.push(cat);
    if (cat.count > this.max_count) {
      this.max_count = cat.count;
      this.max_id = i;
    }
    if (cat.count < this.min_count || !this.min_count)
      this.min_count = cat.count;
  }
  if (!this.tags.length) {
    this.cloud.innerHTML = '<span class="noresults">' + this.msg + '</span>';
    return;
  }
  /* Count analysis */
  var spread = this.max_count - this.min_count;
  if ( spread <= 0 )
  	spread = 1;
  /* Font size */
  var size_spread = this.maxsize - this.minsize;
  if ( size_spread <= 0 )
  	size_spread = 1;
  var size_step = size_spread / spread;
  /* Font color */
  var color_step = [];
  for (var c=0; c<3; c++) {
  	var color_spread = this.maxcolor[c] - this.mincolor[c];
  	color_step[c] = color_spread / spread;
  }
  /* Set tag size and color */
  for (var i=0; i<this.tags.length; i++) {
    this.tags[i].size = Math.round(this.maxsize - ( ( this.max_count - this.tags[i].count ) * size_step ));
    for (var c=0; c<3; c++)
      this.tags[i].color[c] = Math.round(this.maxcolor[c] - ( ( this.max_count - this.tags[i].count ) * color_step[c] ));
  }
  /* Do actual layout... */
  if (this.layout=='center')
    this.layout_center();
  else
    this.layout_alphabetical();
}
SparqlCloud.prototype.display=SparqlCloud_display;

function SparqlCloud_build() {
  if (!this.cloud)
    return;

  /* Build HTML */
  var html = '';
  for (var i=0; i<this.tags.length; i++) {
    html = html + this.tags[i].toString();
  }
  this.cloud.innerHTML = '<div class="current layout_'+this.layout+'" title="current">' + html + '</div>';
  // Find widest
  var tags = this.cloud.childNodes.item(0).getElementsByTagName('a');
  this.widest=0;
  this.max_width=0;
  for (var i = 0; i < tags.length; i++) {
    if (tags[i].offsetWidth>this.max_width) {
      this.max_width=tags[i].offsetWidth;
      this.widest=i;
    }
  }
}
SparqlCloud.prototype.build=SparqlCloud_build;

function SparqlCloud_layout_center() {
  if (!this.cloud)
    return;

  /* Move largest to front and build */
  if (this.max_id>0) {
    var t = this.tags[0];
    this.tags[0] = this.tags[this.max_id];
    this.tags[this.max_id] = t;
  }
  this.build();

  /* Adjust... */
  var tags = this.cloud.childNodes.item(0).getElementsByTagName('a');
  var last = tags.length;
  var cx = this.cloud.clientWidth / 2;
  var cy = this.cloud.clientHeight / 2;
  var angle = 2 * Math.PI / (last - 1);
  var overlap = false;
  for (var i = 0; i < last; i++) {
    var tag = tags[i];
    tag.w = tag.clientWidth;
    tag.h = tag.clientHeight;
    var x = cx - tag.w / 2;
    var y = cy - tag.h / 2;
    var rx = Math.cos ( angle * ( i % (last - 1) ) ) * ( tags[0].w + tag.w ) / 2;
    var ry = Math.sin ( angle * ( i % (last - 1) ) ) * ( tags[0].h + tag.h ) / 2;
    do {
      overlap = false;
      tag.x = x + ( i ? rx : 0 );
      tag.y = y + ( i ? ry : 0 );
      if (tag.x < 0 || tag.y < 0 || ( tag.x + tag.w ) > this.cloud.clientWidth || ( tag.y + tag.h ) > this.cloud.clientHeight ) {
        tag.style.display = 'none';
      } else {
        for (var j = 0; !overlap && (j < i); j++) {
          if (tags[j].style.display != 'none') {
            if (( tag.x < ( tags[j].x + tags[j].w ) ) &&
                ( tags[j].x < ( tag.x + tag.w ) ) && 
                ( tag.y < ( tags[j].y + tags[j].h ) ) &&
                ( tags[j].y < ( tag.y + tag.h ) )) {
              overlap = true;
              rx = 1.2 * rx;
              ry = 1.2 * ry;
            }
          }
        }
      }
    } while (overlap && ( rx < cx ) && ( ry < cy ) );
    if (overlap)
      tag.style.display = 'none'
    else {
      tag.style.position = 'absolute';
      tag.style.left = Math.round ( tag.x ) + 'px';
      tag.style.top = Math.round ( tag.y ) + 'px' ;
    }
  }
}
SparqlCloud.prototype.layout_center=SparqlCloud_layout_center;

function SparqlCloud_layout_alphabetical() {
  if (!this.cloud)
    return;
  this.build();

  w=this.cloud.offsetWidth*0.94;
  h=this.cloud.offsetHeight;
  var div = this.cloud.childNodes.item(0);
  var tags = this.cloud.childNodes.item(0).getElementsByTagName('a');

  // Expand
  if (div.offsetHeight < h) {
    adjust = h / div.offsetHeight;
    if (adjust > (w / this.max_width))
      adjust=w / this.max_width;
    for (var i = 0; i < tags.length; i++) {
      tags[i].style.fontSize=(tags[i].style.fontSize.replace('%','')*adjust)+'%';
    }
  }

  // Shrink
  while (div.offsetHeight > h) {
    for (var i = 0; i < tags.length; i++) {
      tags[i].style.fontSize=(tags[i].style.fontSize.replace('%','')*0.95)+'%';
    }
  }
}
SparqlCloud.prototype.layout_alphabetical=SparqlCloud_layout_alphabetical;
