function isType (element) {
  element = $(element);
  if (element && element.type){
    var element_type = element.type.toLowerCase();
    return $A(arguments).any(function(item, context) { return(context == 0 ? false : item.toLowerCase() == element_type)});
  }
  return false;
};

function text_mutex_handler(target, action) {
  if (action){
    target.enable();
    target.removeClassName('mutex-disabled');
  }
  else {
    target.disable();
    target.addClassName('mutex-disabled');
  }
}

function mutex_handler (source, action, targets) {
  source = $(source);
  var source_type = source.type.toLowerCase();

  switch(source_type){
    case 'checkbox':
      if (source.checked)
        break;
      else
        /* Enable textboxes in the off group
         * textboxes when this checkbox is unchecked.
         * otherwise they'll remain in disabled state */
        if (!action) {
          targets.map(function(name) { return $(name) }).findAll(function(target) {
              return(isType(target, 'text', 'textarea'));
          }).each(function(element){ text_mutex_handler(element, true) });
        }
        return;

    case 'radio':
      /* Ignore unchecked radio buttons */
      if (source.checked)
        break;
      else
        return;

    case 'text':
      /* fall through */
    case 'textarea':
      if (source.value.strip() == "")
        /* Ignore empty source text box */
        return;
      else
        break;
  }
  
  /* check/uncheck every checkbox and radio box in TARGETS according to ACTION 
   * textboxes are disabled in the 'false' ACTION and enabled for 'true' ACTION
   * in order to avoid losing user data
   */
  targets.each(function (s) {
    var target = $(s);
    if (target) {
      if (target.type) {
        switch (target.type.toLowerCase()) {
          case 'checkbox':
           /* fall through */
          case 'radio':
            target.checked = action;
            break;
          case 'text':
           /* fall through */
          case 'textarea':
            text_mutex_handler(target, action);
            break;
        }
      }
    }
  });
}

/* initialize mutex */
/* source_element -- radio, checkbox, textbox
 * targets -- hash of string => array of elements to check/uncheck/clear
 * example: { 'on' : [....], 'off' :  [..] }
 */
function init_mutex(source, targets) {
  var source = $(source);
  mutex_function = function(evt) {
    $H(targets).each(function(pair) { mutex_handler(source, pair.key == 'on', pair.value) })
    //Prevent event from going further up the DOM...
    if (evt)
      evt.cancelBubble = true;
  };

  source.mutex_function = mutex_function;

  if (isType(source, 'checkbox', 'radio')) { 
    Event.observe(source, 'click', mutex_function);
  }
  else if (isType(source, 'text')) { 
    Event.observe(source, 'click', mutex_function);
    Event.observe(source, 'keyup', mutex_function);
  }
}

/* Clicking on cell toggles radio button/checkbox.
 * But avoid toggle when the input control is clicked directly
 */
function click_on_cell_to_select(evt, target_id)
{
  var element = Event.element(evt);
  if (element.id != target_id) { 
    var target = $(target_id);
    if (target && !target.checked)
      target.checked = true;
      if (target.mutex_function) {
          target.mutex_function();
      }
  }
}

function getTime () {
  var date = new Date();
  return date.getTime();
}

function setBandwidth(startTime) {

  var endTime = getTime();

  var diffTimeMilliseconds = endTime - startTime;

  if (diffTimeMilliseconds == 0){
    diffTimeMilliseconds = 0.1;
  }

  var diffTimeSeconds = diffTimeMilliseconds/1000;
  var bits = (datasize*8);   // convert Bytes to bits, 
  var kbits = bits/1024;     // convert bits to kbits
  var throughput = kbits/(diffTimeSeconds);
  throughput = throughput * .93;  // account for IP packet header overhead - averages about 7%
  $('network_speed').value = Math.floor(throughput);
  alert(['speed', Math.floor(throughput)].inspect());
}

function detect_bandwidth(url)
{
  var datasize = 31468; // in Bytes
  var startTime = getTime();

  setBandwidth = function() {
    var endTime = getTime();

    var diffTimeMilliseconds = endTime - startTime;

    if (diffTimeMilliseconds == 0){
      diffTimeMilliseconds = 0.1;
    }

    var diffTimeSeconds = diffTimeMilliseconds/1000;
    var bits = (datasize*8);   // convert Bytes to bits, 
    var kbits = bits/1024;     // convert bits to kbits
    var throughput = kbits/(diffTimeSeconds);
    throughput = throughput * .93;  // account for IP packet header overhead - averages about 7%
    $('network_speed').value = Math.floor(throughput);
  };

  new Ajax.Request(url, { method: 'get', parameters: "size=" + datasize, onComplete: setBandwidth });

}

function page_button_handler(evt) {
  var button = evt.element();
  [button].concat(button.siblings()).each(function(x){ if (x.type == 'submit'){ x.disable() }});
  var f = button.form;
  
  /* disabled elements don't send a value, but we need to know which button was pressed ... */
  f.appendChild(new Element('input', { 'type': 'hidden', 'name': button.name, 'value': '1' }));

  f.submit();
  //TODO - if submit returns no content, re-enable buttons
  evt.stop();
}

/* submits form after given interval has elapsed (in seconds)
 * checks for invalid input
 * accepts interval as number or string
 */
function page_auto_advance(interval) {
  interval = parseInt(interval, 10);
  if (!isNaN(interval) && (interval != 0)){
    $$('input#previous-page', 'input#next-page').each(function(x){ if (x.type == 'submit'){ x.disable() }});
    setTimeout(function(){ $('next-page').form.submit(); }, interval * 1000);
  }
}
