/* cloudify.js - Paul Seamons - License BSD - Copyright 2007 */
/* $Id: cloudify.js,v 1.8 2007-02-23 21:36:20 paul Exp $ */

function cloudify (args) {
  if (! args) return;
  var el = document.getElementById(args["id"]);
  if (! el) return;

  if (! args.parent) args.parent = el.parentNode;

  el.style.display = "none";
  args.parent.style.background = "#000";
  args.parent.style.color      = "#666";
  args.parent.style.overflow   = "hidden";

  // absolute elements or element positioning in IE are going to be relative to 0 - sort of odd
  var _top  = args.top  ? args.top  : cloudify_object_offset(args.parent).top;
  var _left = args.left ? args.left : cloudify_object_offset(args.parent).left;
  if (navigator.appVersion.indexOf('MSIE') != -1) { _top = 0, _left = 0 }

  return cloudify_create_node({
    tree     : cloudify_parse_el(el),
    parent   : args.parent,
    width    : args.width  ? args.width  : args.parent.clientWidth,
    height   : args.height ? args.height : args.parent.clientHeight,
    left     : _left,
    top      : _top,
    no_pngs  : args.no_pngs,
    img_path : args.img_path ? args.img_path : "./"
  });
}

function cloudify_create_node (args) {

  // add the main text element
  var tree = args.tree;
  var el   = tree.div = document.createElement("DIV");
  el.innerHTML        = "<a style='text-decoration:none;color:#ddd' href='"+(tree.link ? tree.link : "#")+"'><b>"+tree.heading+"</b></a>";
  el.style.position   = "absolute";
  el.style.display    = "block";
  el.style.fontFamily = "sans-serif";
  el.style.zIndex     = 10;
  el.style.cursor     = "pointer";
  el.style.whiteSpace = "nowrap";
  el.style.fontSize   = "10pt";
  args.parent.appendChild(el);
  cloudify_resize_text({
    obj          : el,
    width        : .55 * args.width,
    initial_size : 10
  });
  tree.width  = parseInt(el.clientWidth);
  tree.height = parseInt(el.clientHeight);
  tree.left   = args.left + (args.width  - tree.width)  / 2;
  tree.top    = args.top  + (args.height - tree.height) / 2;
  el.style.left = ""+parseInt(tree.left)+"px";
  el.style.top  = ""+parseInt(tree.top )+"px";
  if (tree.blurb) {
    var show_blurb = function () {
      var t = tree.heading.replace(/<br>/ig,"");
      tree.blurb_div.innerHTML = '<table width=500 height=100% align=center><tr>'
        +'<td valign=middle align=center style="color:black;font-size:larger">'
        +'<b><div style="font-size:larger">'+t+'</div>'+tree.blurb+'</b></td></tr></table>';
      tree.blurb_div.style.fontFamily = "sans-serif";
      tree.blurb_div.style.display    = "block";
      tree.blurb_div.parentNode.style.display = "block";
      return false;
    };
    if (tree.div.firstChild.addEventListener) {
      tree.div.firstChild.addEventListener("mouseover", show_blurb, true);
      if (args.is_child) tree.div.firstChild.addEventListener("mouseout", function () { tree.blurb_div.parentNode.style.display = 'none' }, true);
    } else {
      tree.div.firstChild.onmouseover = show_blurb;
      if (args.is_child) tree.div.firstChild.onmouseout  = function () { tree.blurb_div.parentNode.style.display = 'none' };
    }
  }

  // add the shadow
  var el2 = el.cloneNode(true);
  el2.innerHTML    = "<b>"+tree.heading+"</b>";
  el2.style.left   = ""+(args.width < 100 ? 1 : 2)+"px";
  el2.style.top    = ""+(args.width < 100 ? 1 : 2)+"px";
  el2.style.zIndex = -1;
  el2.style.color  = "#222";
  el.appendChild(el2);

  // create shadow image
  if (! args.no_pngs) {
    var w = tree.width  / .6;
    var h = tree.height / .6;
    var i = tree.img = document.createElement("IMG");
    if (args.is_child) {
      i.src = args.img_path + "/200whitegrad.png";
    } else {
      i.src = args.img_path + "/400hole.png";
      i.style.background = "#000";
    }
    if (navigator.appVersion.indexOf('MSIE') != -1) i.style.behavior = "url("+args.img_path+"/png.htc)";
    i.style.position = "absolute";
    i.style.width    = ""+w+"px";
    i.style.height   = ""+h+"px";
    i.style.left     = ""+parseInt((tree.width  - w) / 2)+"px";
    i.style.top      = ""+parseInt((tree.height - h) / 2)+"px";
    i.style.zIndex   = -2;
    el.appendChild(i);
  }

  // create description background
  if (! tree.blurb_div) {
    var w = tree.width  * 2.5;
    var h = tree.height * 2;
    var div = document.createElement("DIV");
    div.style.display = "none";
    div.style.position = "absolute";
    div.style.width    = ""+w+"px";
    div.style.height   = ""+h+"px";
    div.style.left     = ""+parseInt((tree.width  - w) / 2)+"px";
    div.style.top      = ""+parseInt((tree.height - h) / 2)+"px";
    div.style.zIndex   = 0;
    el.appendChild(div);
    tree.blurb_div = div.cloneNode(true);
    tree.blurb_div.style.left = "0px";
    tree.blurb_div.style.top  = "0px";
    if (tree.blurb_div.addEventListener) {
      tree.blurb_div.addEventListener("mouseup",  function () { div.style.display = "none" }, true);
      tree.blurb_div.addEventListener("mouseout", function () { div.style.display = "none" }, true);
    } else {
      tree.blurb_div.onmouseup  = function () { div.style.display = "none" };
      tree.blurb_div.onmouseout = function () { div.style.display = "none" };
    }
    div.appendChild(tree.blurb_div);
    var i2 = document.createElement("IMG");
    i2.src = args.img_path + "/200whitegrad.png";
    if (navigator.appVersion.indexOf('MSIE') != -1) i2.style.behavior = "url("+args.img_path+"/png.htc)";
    i2.style.position = "absolute";
    i2.style.width    = ""+w+"px";
    i2.style.height   = ""+h+"px";
    i2.style.left     = "0px";
    i2.style.top      = "0px";
    i2.style.zIndex   = -1;
    div.appendChild(i2);
  }

  // now recursively add child nodes
  if (tree.sections && tree.sections.length) {
    var n       = tree.sections.length;
    var cen_x   = tree.cen_x   = tree.width  / 2;
    var cen_y   = tree.cen_y   = tree.height / 2;
    var rad_x   = tree.rad_x   = args.width  * .38;
    var rad_y   = tree.rad_y   = args.height * .32;
    var child_w = tree.child_w = args.width  * .6 * .58;
    var child_h = tree.child_h = args.height * .6 * .58;

    for (var j = 0; j < n; j++) {
      var ang = - 2 * 3.1415926 * j / n + 3.1415926 / 2;
      tree.sections[j].blurb_div = tree.blurb_div;

      cloudify_create_node({
        "tree"    : tree.sections[j],
        parent    : el,
        width     : child_w,
        height    : child_h,
        left      : parseInt( cen_x + rad_x * Math.cos(ang) - child_w / 2),
        top       : parseInt((cen_y - rad_y * Math.sin(ang) - child_h / 2) * (1 + .3*Math.abs(Math.cos(ang)))),
        is_child  : args.is_child ? args.is_child + 1 : 1,
        no_pngs   : args.no_pngs,
        img_path  : args.img_path
      });
    }
  }

  // setup animation and animation link
  if (! args.is_child) {
    var button = tree.button = document.createElement("IMG");
    var w = parseInt(args.width  / 50);
    button.src = args.img_path + "/400hole.png";
    button.style.background = "#000";
    if (navigator.appVersion.indexOf('MSIE') != -1) button.style.behavior = "url("+args.img_path+"/png.htc)";
    button.style.position = "absolute";
    button.style.width    = w+"px";
    button.style.height   = w+"px";
    button.style.left     = ""+(args.left + args.width  - w)+"px";
    button.style.top      = ""+(args.top  + args.height - w)+"px";
    button.style.zIndex   = 10;
    button.style.cursor   = "pointer";
    button.title          = "Start/Stop Animation";
    button.onmouseup = function () {
      if (tree.animation) {
        tree.animation  = false;
        tree.last_count = tree.count;
      } else {
        tree.animation  = true;
        tree.count      = tree.last_count;
        if (tree.timer) clearTimeout(tree.timer);
        cloudify_move(tree);
      }
    };
    args.parent.appendChild(button);

    cloudify_move(tree);
  }
}

function cloudify_resize_text (args) {
  var el        = args.obj;
  var font_size = args.initial_size || alert("Missing initial_size");

  var i = 0;
  while (1) {
    if (i++ > 10) break;
    var w = parseInt(el.offsetWidth);
    if (w <= 1.15 * args.width && w >= .95 * args.width) return; // { el.innerHTML += '('+i+')'; return }
    var new_fs = parseInt(font_size * args.width / w);
    if (new_fs == font_size) return i;
    font_size = new_fs;
    el.style.fontSize = ""+(--font_size)+"pt";
  }
}

function cloudify_object_offset (el) {
  if (! el.style) return {top : 0, left : 0};

  if (el.style.position == "absolute") {
    return {top: 0, left: 0};
  } else {
    if (el.offsetParent == null) return {top : 0, left : 0};
    var offset = cloudify_object_offset(el.offsetParent);
    return {top : offset.top + parseInt(el.offsetTop), left : offset.left + parseInt(el.offsetLeft)};
  }
}

function cloudify_move (tree) {

  if (! tree.count) tree.count = 0;
  tree.count++;

  var timeout  = tree.animation ? 125 : 5000;
  var do_move  = tree.animation;
  var do_color = true;
  var color;

  if (do_color) {
    var step = tree.animation ? 3 : 50;
    var info = tree.color_info;
    if (! info) info = tree.color_info = {
      color : [255, 0, 0],
      dir   : [0, 0, -1]
    };

    var c = info.color;
    var d = info.dir;
    var change  = false;
    var j = d[0] ? 0 : d[1] ? 1 : 2;
    var i = (j == 0) ? 2 : j - 1;
    var k = (j == 2) ? 0 : j + 1;

    if (d[j] > 0) {
      if (c[j] == 255) {
        d[i] = -1;
        d[j] = d[k] = 0;
      }
    } else {
      if (c[j] == 0) {
        d[i] = 1;
        d[j] = d[k] = 0;
      }
    }

    for (var i = 0; i < 3; i++) {
      c[i] += d[i] * step;
      if (c[i] > 255) c[i] = 255;
      if (c[i] < 0)   c[i] = 0;
    }

    color = 'rgb('+c+')';
  }

  if (do_color) {
    if (tree.img)    tree.img.style.background    = color;
    if (tree.button) tree.button.style.background = color;
  }

  cloudify_move_helper(tree, color, do_move, tree.count);

  tree.timer = setTimeout(function () { cloudify_move(tree) }, timeout);
}

function cloudify_move_helper (node, color, do_move, count, level) {
  if (! level) level = 0;
  if (color && level >= 2) node.div.firstChild.style.color = color;
  if (! node.sections || ! node.sections.length) return;

  var n = node.sections.length;

  for (var i = 0; i < n; i++) {
    var child = node.sections[i];
    cloudify_move_helper(child, color, do_move, count, level + 1);

    if (! do_move) continue;
    //if (level != 1) continue;
    var ang = - 2 * 3.1415926 * i / n + 3.1415926 / 2 + count * (level + 1) / 100;
    child.div.style.left = ""+parseInt( node.cen_x + node.rad_x * Math.cos(ang) - child.width  / 2) +"px";
    child.div.style.top  = ""+parseInt((node.cen_y - node.rad_y * Math.sin(ang) - child.height / 2) * (1 + .3*Math.abs(Math.cos(ang)))) +"px";
  }
}

function cloudify_parse_el (el) {
  var info = {};

  // top portion should look like
  // <h1><a href="link">heading</a></h1> or <h1>heading</h1>
  var headcont = el.firstChild;
  if (! headcont) return info;
  if (headcont.nodeName == '#text') headcont = headcont.nextSibling;
  if (! headcont || ! headcont.tagName.match(/^H\d$/)) return info;
  var heading = headcont.firstChild;
  var link = '';
  if (heading.tagName == 'A') {
    link    = heading.href;
    heading = heading.innerHTML;
  } else if (heading.textContent) {
    heading = heading.textContent;
  }
  info["heading"] = heading;
  info["link"]    = link;

  // next section should look like
  // <p>A blurb about the topic</p>
  var blurb = headcont.nextSibling;
  var subdiv;
  if (! blurb) return info;
  if (blurb.nodeName == '#text') blurb = blurb.nextSibling;
  if (! blurb) return info;
  if (blurb.tagName == 'P') {
    info["blurb"] = blurb.innerHTML;
    subdiv = blurb.nextSibling;
  } else {
    info["blurb"] = '';
    subdiv = blurb;
  }

  // remaining sections should be sub divs
  // <div class="section"><h1></h1><p></p></div>

  info["sections"] = [];
  while (subdiv) {
    if (subdiv.tagName && subdiv.tagName == 'DIV') info["sections"].push(cloudify_parse_el(subdiv));
    subdiv = subdiv.nextSibling;
  }

  return info;
}
