var $ = function(id) { 
    if (typeof(id) == "string")
	return document.getElementById(id);
    return id;
}

var extend = function(dict1, dict2) {
  for (key in dict2) {
    dict1[key] = dict2[key];
  } 
} 
var createClass = function() {
  return function() {
    this.initialize.apply(this, arguments);
  }
};

var createSubClass = function(superklass) {
  klass = createClass();
  extend(klass.prototype, superklass.prototype);
  return klass;
} 

/**
 * CSS3 support
 */

window.CSS3_PREFIX = '';
if ( RegExp(" AppleWebKit/").test(navigator.userAgent) ) {
  window.CSS3_PREFIX = 'Webkit';
}

if ( RegExp(" Firefox/").test(navigator.userAgent) ) {
  window.CSS3_PREFIX = 'Moz';
}

function css3(prop) {
  return window.CSS3_PREFIX + capitalize(prop);
} 

css3.features  = {
  transitions: false
};

// enable transitions for webkit
if (/webkit/i.test(navigator.userAgent))
  css3.features.transitions = true;

// disable transitions for ipad
if (/iPad; U/.test(navigator.userAgent))
  css3.features.transitions = false;

/**
 * Utils
 */

var capitalize = function(s){
  return s.charAt(0).toUpperCase() + s.substring(1).toLowerCase();
};

var nonWordNonSpaceRegexp = new RegExp('([^\\w| ])+', 'g');
var spaceRegexp = new RegExp('\\s+', 'g');
var slugify = function(s) {
  //remove non alphanum non space
  var result = s.replace(nonWordNonSpaceRegexp,'');
  //replace spaces with dashes
  result = result.replace(spaceRegexp, '-');
  return result.toLowerCase();
} 

function extractScripts(s) {
  var scriptFragment = '<script[^>]*>([\\S\\s]*?)<\/script>';
  var matchAll = new RegExp(scriptFragment, 'img');
  var matchOne = new RegExp(scriptFragment, 'im');
  var matches = s.match(matchAll) || [];
  var results = [];
  for (var i=0; i<matches.length; i++) {
    var scriptTag = matches[i];
    results.push((scriptTag.match(matchOne) || ['',''])[1]);
  } 
  return results;
}

function evalScripts(s) {
  var scripts =  extractScripts(s);
  var results = [];
  for (var i=0; i<scripts.length; i++)
    results.push(eval(scripts[i]))
  return results;
}

var forceRecursiveZindex = function(elt, zIndex) {
  //set zindex for Internet Explorer (make sure it's on top of everything):
  var n = elt;
  while(n && n.tagName.toLowerCase() != 'body') {
    if (!n._previousZIndex)
      n._previousZIndex = n.style.zIndex;
    n.style.zIndex = zIndex;
    n = n.parentNode;
  } 
} 

var revertRecursiveZindex = function(elt) {
  var n = elt;
  while(n && n.tagName.toLowerCase() != 'body') {
    n.style.zIndex = n._previousZIndex
    n = n.parentNode;
  } 
} 

var cumulativeOffset = function(element) {
  var valueT = 0, valueL = 0;
  do {
    valueT += element.offsetTop  || 0;
    valueL += element.offsetLeft || 0;
    element = element.offsetParent;
  } while (element);
  return {left:valueL, top:valueT};
};





var addClassName = function(elt, classname) {
  elt.className += " "+classname;
} 
var removeClassName = function(elt, classname) {
  var classnames = elt.className.toString().split(/\s+/);
  var oknames = Array();
  for (var i=0; i<classnames.length; i++)
    if (classnames[i] != classname)
      oknames.push(classnames[i]);
  elt.className = oknames.join(' ');
} 

var hasClassName = function(elt, classname) {
  var classnames = elt.className.toString().split(/\s+/);
  for (var i=0; i<classnames.length; i++)
    if (classnames[i] == classname)
      return true;
  return false;
} 

var show = function(elt) {
  elt = $(elt);
  elt.style.display='';
} 
var hide = function(elt) {
  elt = $(elt);
  elt.style.display='none';
} 
var toggle = function(elt) {
  elt = $(elt);
  if (elt.style.display == 'none')
    return show(elt);
  return hide(elt);
} 
var _toggle = toggle;

var isChild = function(elt, paren) {
  while (elt.parentNode) {
    if (paren == elt.parentNode)
      return true;
    elt = elt.parentNode;
  } 
  return false;
} 
/** checks recursively if the element is hidden
  * or within a hidden element
  */
var isDisplayed = function(elt) {
  if (elt.style.display == 'none')
    return false;

  var p = elt.parentNode;
  while (p && p.tagName.toLowerCase() != 'html') {
    if (p.style.display == 'none')
      return false;
    p = p.parentNode;
  } 
  return true;
} 

var cloneNode = function(elt, keepId) {
  var e = elt.cloneNode(true);
  if (!keepId) e.id = '';
  e.innerHTML = elt.innerHTML;
  return e;
} 

var observeEvent = function(element, eventName, handler, useCapture) {
  element = $(element);

  if (eventName == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent))
    eventName = 'keydown';

  if (eventName == 'transitionend' && CSS3_PREFIX == 'Webkit')
    eventName = 'webkitTransitionEnd';

  if (element.addEventListener) {
    element.addEventListener(eventName, handler, false, useCapture);
  } else {
    element.attachEvent("on" + eventName, handler);
  }

  return element;
}

var stopObserving = function(element, eventName, handler, useCapture) {
  element = $(element);
  if (eventName == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent))
    eventName = 'keydown';

  if (element.removeEventListener) {
    element.removeEventListener(eventName, handler, false, useCapture);
  } else {
    element.detachEvent("on" + eventName, handler);
  }

  return element;
} 

var eventElement = function(event) {
  return event.target || event.srcElement;
} 

var stopEvent = function(event) {
  if (event.preventDefault) {
    event.preventDefault();
    event.stopPropagation();
  } else {
    event.returnValue = false;
    event.cancelBubble = true;
  }
};



var KEYS = {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34
} 

function avoidDoubleClick(button) {
  button.disabled = true;
  setTimeout(function() {button.disabled = false}, 2000);
  if (button.form) { 
    button.form.submit();
    return false;
  }
  return true;
} 

var ajax = function(url, parameters, oncomplete, onerror, method) {
  method = method || 'POST';
  method = method.toUpperCase();

  parameters = parameters || '';
  var httpRequest;
  if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
  } else if (window.ActiveXObject) { // IE
    try {
      httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
      httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
    } 
  }

  if (!(typeof(parameters) == 'string')) {
    var tmp = '';
    for (k in parameters)
      tmp += encodeURIComponent(k) + '=' + encodeURIComponent(parameters[k]);
    parameters = tmp;
  } 

  var headers = {
    'X-Requested-With': 'XMLHttpRequest',
    'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
    'Content-Type': 'application/x-www-form-urlencoded charset=UTF-8'
  };

  if (httpRequest.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
    headers['Connection'] = 'close';


  httpRequest.onreadystatechange = function() {
    if (httpRequest.readyState == 4) {
      if (httpRequest.status == 200) {
        if (oncomplete)
          oncomplete(httpRequest.responseText, httpRequest.responseXML);
      } else if (onerror) {
        onerror(httpRequest);
      }
    }
  };

  httpRequest.open(method, url + (method == 'GET' ? '?'+parameters : ''), true);
  for (var name in headers) {
    httpRequest.setRequestHeader(name, headers[name]);
  } 
  httpRequest.send(parameters);
} 

RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}

function IEButtonFix(button) {
  for(var i=0; i<button.form.elements.length; i++) {
    if( button.form.elements[i].tagName == 'BUTTON' )
      button.form.elements[i].disabled = true;
  }
  button.disabled=false;
  var value;
  try {
    value = button.attributes.getNamedItem("value").nodeValue ;
  } catch(e) {}

  if (value) button.value = value;
}

var nonwords_re = new RegExp('[^\\w]+');

var highlight = function(str, q) {
  var words = q.split(nonwords_re), result = str;
  for (var i=0; i<words.length; i++) {
    if (!words[i]) continue;
    if (words[i].length == 1) continue;
    var re = new RegExp("("+RegExp.escape(words[i])+")", "gi");
    result = result.replace(re, '<strong>$1</strong>')
  } 
  return result;
};

function open_overlay(args) {

  overlay_args = {
    node: undefined,
    innerHTML: undefined,
    url: undefined,
    onClose: undefined,
    evalScripts: true

  };
  extend(overlay_args, args);
  

  // Content node can be a URL
  if (overlay_args['url']) {
    ajax(overlay_args.url, '', function(responseText) {
      var e = document.createElement('div');
      var args = {};
      extend(args, overlay_args);
      extend(args, {innerHTML: ""+responseText, url:undefined});
      open_overlay.call(undefined, args);
    }, undefined, 'GET');
    return;
  } 


  var overlay = window.__overlay;

  // create the overlay if necessary
  if (!overlay) {
    overlay = document.createElement('div');
    overlay.id = 'overlay';
    overlay.style.position = 'absolute';
    window.__overlay = overlay;
    document.body.appendChild(overlay);

    // Observe clicks outside
    overlay.__clickhandler = function(e) {
      if (!isChild(eventElement(e), overlay)) {
        close_overlay();
      } 
    }; 
  } 

  show(overlay);
  addClassName(overlay, 'visible');
  // default width and height
  width = overlay.clientWidth;
  height = overlay.clientHeight;

  observeEvent(window, 'click', overlay.__clickhandler);

  // Assign onClose
  if (overlay_args.onClose) overlay.__onClose = overlay_args.onClose;

  var windowHeight = window.innerHeight||document.body.clientHeight; // IE support
  var windowWidth = window.innerWidth||document.body.clientWidth; // IE support
  var scrollTop = window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop // IE support
  var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft  || document.body.scrollLeft // IE support

  var top = (scrollTop + (windowHeight-height)/2);
  var left = (scrollLeft + (windowWidth - width)/2);

  // Overlay top must be in the viewport:
  // Safari doesn't support Math.max
  top = scrollTop > top ? scrollTop : top;

  // append content
  if (overlay_args.node) {
    // Remember the previous parent
    contentNode.__previousParent = overlay.__contentNode.parentNode;
    // empty overlay
    overlay.innerHTML = '';
    // append
    overlay.appendChild(overlay_args.node);
    overlay.__contentNode = overlay_args.node;

  } 

  if (overlay_args.innerHTML) {
    overlay.innerHTML = overlay_args.innerHTML;
    if (overlay_args.evalScripts)
      evalScripts(overlay_args.innerHTML);
  } 


  // Show
  overlay.className = 'beforeAnimation';
  overlay.style.left = left+"px";
  overlay.style.top = top+"px";

  setTimeout(function() {
    overlay.className = 'on';
  }, 1);


  // fade out the rest of the page
  for(i in document.body.childNodes) {
    var c = document.body.childNodes[i];
    if (c != overlay && c.style) {
      c.style.opacity = .2;
    } 
  } 

  return;
} 

function close_overlay() {
  if (window.__overlay && window.__overlay.style.display != 'none') {
    var overlay = window.__overlay;

    stopObserving(window, 'click', overlay.__clickhandler);

    overlay.className = '';
    // fade out the rest of the page
    for(i in document.body.childNodes) {
      var c = document.body.childNodes[i];
      if (c != overlay && c.style)
        c.style.opacity = 1;
    } 


    // put back content in its original place
    var content = overlay.__contentNode;
    if (content && content.__previousParent) {
      content.__previousParent.appendChild(content);
    } 

    // call onClose callback
    if (overlay.__onClose) overlay.__onClose();
  } 
} 

function build_overlay_nav(current_overlay_name) {
  if (!window.__overlays) return;
  if (!current_overlay_name) return;

  // Find ourselves in the list
  var indexOfUs = -1;
  for (var i=0; i<window.__overlays.length; i++) {
    var o = window.__overlays[i];
    if (o.name == current_overlay_name) {
      indexOfUs = i;
      break;
    } 
  } 

  // If we're not in the list, return
  if (indexOfUs == -1) return;

  // Find the previous and next items
  var previous = undefined;
  var next = undefined;
  if (indexOfUs > -1)
    previous = window.__overlays[indexOfUs-1];
  if (indexOfUs < window.__overlays.length -1)
    next = window.__overlays[indexOfUs+1];


  // find the links
  var overlaynav = $('overlaynav');
  var links = overlaynav.getElementsByTagName('a');
  if (links.length != 2) return;

  for (var i=0; i<links.length; i++) {
    if (hasClassName(links[i], 'previous')) previousLink = links[i];
    if (hasClassName(links[i], 'next')) nextLink = links[i];
  } 

  if (previous) {
    previousLink.onclick = function() { replace_overlay(previous); return false;} 
    previousLink.getElementsByTagName('span')[0].appendChild(document.createTextNode(previous.title));
    show(previousLink);
  } 

  if (next) {
    nextLink.onclick = function() { replace_overlay(next); return false;}
    nextLink.getElementsByTagName('span')[0].appendChild(document.createTextNode(next.title));
    show(nextLink);
  } 
  show(overlaynav);
} 

function replace_overlay(overlay) {
  var elts = ['overlaytitle', 'overlaycontent', 'overlaynav'];
  for (var i=0; i<elts.length; i++) 
    removeClassName($(elts[i]), 'on');

  ajax(overlay.url, '', function(responseText) {
     $('overlay').innerHTML = responseText;
     evalScripts(responseText);
  }, undefined, 'GET');
} 

function rotate_child_nodes(elt, tagName, interval) {
  elt = $(elt);
  if (!interval) interval = 2000;

  // get the children
  var children = elt.getElementsByTagName(tagName);

  // if not enough children, return
  if (children.length < 2)  {
    if (children) children[0].style.opacity = 1;
    return;
  }
  elt.__counter = 0;

  // the rotate function
  var rotate = function() {
    var prev = (children.length + elt.__counter - 1) % children.length;
    var next = (elt.__counter + 1) % children.length;
    children[prev].style.opacity = 0;
    children[elt.__counter].style.opacity = 1;
    elt.__counter = next;
  };

  // rotate now and setInterval
  rotate();
  setInterval(rotate, interval);
} 

