function addOnloadEvent(fun) {
  var old = window.onload;
  if (old) {
    window.onload = function () { old(); fun(); }}
  else {
    window.onload = fun; }}

function addEventCatcher(element, event, fun) {
  element["on" + event] =
    function (event) {
      fun();
      return false; }}

// DOM utils

function innerText(element) {
  if (element.innerText != undefined) {
    return element.innerText }
  else {
    var text = "";
    mapArray(element.childNodes,
      function (e) {
        switch (e.nodeType) {
          case 1: text += innerText(e); break;
          case 3: text += e.nodeValue; break; }});
    return text }}

function elementInsertFirst(element, newChild) {
  if (element.firstChild) {
    element.insertBefore(newChild, element.firstChild); }
  else {
    element.appendChild(newChild); }}


function elementInsertAfter(element, newChild, refChild) {
  var before = refChild.nextSibling;
  if (before) {
    element.insertBefore(newChild, before); }
  else {
    element.appendChild(newChild); }}

function elementHasClass(element, className) {
  if (!element.className) { return false }
  var re = new RegExp("(^|\\s+)" + className + "($|\\s+)");
  return re.exec(element.className); }

function elementSetClass(element, className) {
  if (!element.className) {
    return element.className = className }
  else if (!elementHasClass(element, className)) {
    return element.className += " " + className }}

// FIXME: \b does not work when hypens are used in class

function elementRemoveClass(element, className) {
  if (!element.className) { return false }
  var removed = false;
  var re = new RegExp("\\s*\\b" + className + "\\b\\s*");
  element.className = element.className.replace(re,
    function (str, offset, s) {
      removed = true;
      return offset==0 || str.length+offset==s.length ? "" : " " })
  return removed }

function elementsWithClass(elements, className) {
  return filterArray(elements, elementHasClass.rcurry(className)); }

function getElementsByClass(element, className, tagName) {
  return elementsWithClass(element.getElementsByTagName(tagName || "*"),
                           className); }

function getElementsByName(name) {
  return filterArray(document.getElementsByTagName("*"),
    function (e) { return e.name == name; })}

// General utils


// Return a function bound to an object
function delegate(object, methodName) {
  return function () {
    return object[methodName].apply(object, arguments); }}

function doArray(array, fun) {
  for (var i=0; i<array.length; i++) {
    fun(array[i]); }}

function mapArray(array, fun) {
  var collect = new Array();
  for (var i=0; i<array.length; i++) {
    collect.push(fun(array[i])); }
  return collect; }

function filterArray(array, fun) {
  var a = [];
  doArray(array, function (i) { if (fun(i)) { a.push(i); }});
  return a; }

Array.prototype.contains = function (value) {
  for (var i=0; i<this.length; i++) {
    if (this[i]==value) {
      return true; }}
  return false; }

function makeArray(fakeArray) {
  var array = [];
  for (var i=0; i<fakeArray.length; i++) {
    array.push(fakeArray[i]); }
  return array; }

Function.prototype.curry = function () {
  var args = makeArray(arguments), self = this;
  return function () {
    return self.apply(self, args.concat(makeArray(arguments))); }}

Function.prototype.rcurry = function () {
  var args = makeArray(arguments), self = this;
  return function () {
    return self.apply(self, makeArray(arguments).concat(args)); }}


function absoluteLeft(elt) {
  var x = 0;
  while (elt) {
    x += elt.offsetLeft;
    elt = elt.offsetParent;
  }
  return x;
}

function absoluteRight(elt) {
  return absoluteLeft(elt) + elt.offsetWidth;
}

function absoluteTop(elt) {
  var y = 0;
  while (elt) {
    y += elt.offsetTop;
    elt = elt.offsetParent;
  }
  return y;
}

function absoluteBottom(elt) {
  return absoluteTop(elt) + elt.offsetHeight;
}

function cloneMyRow(elt) {
  var tr = elt;
  while (tr.tagName != 'TR') {
    tr = tr.parentNode;
  }
  elementInsertAfter(tr.parentNode, tr.cloneNode(true), tr);
}

function deleteMyRow(elt) {
  var tr = elt;
  while (tr.tagName != 'TR') {
    tr = tr.parentNode;
  }
  tr.parentNode.removeChild(tr);
}



function showOrHideDates() {
  var withinDays = document.getElementById("within-days").value;
  document.getElementById("kkal-start-date-row").style.display = withinDays == -1 ? "" : "none";
  document.getElementById("kkal-end-date-row").style.display = withinDays == -1 ? "" : "none";
}

function showPopup(popup) {
  var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  var scrollBottom = (window.innerHeight || document.documentElement.clientHeight) + scrollTop;
  elementSetClass(popup, "visible");
  if (absoluteBottom(popup) > scrollBottom) {
    popup.style.top = scrollBottom - popup.offsetHeight - 20 + "px";
  }
}

function hidePopup(popup) {
  elementRemoveClass(popup, "visible");
}


function initPostalCodeLookup() {
  var postalCodeInput = document.getElementById("venue.postal-code");
  var postalAreaInput = document.getElementById("venue.postal-area");

  postalCodeInput.onkeyup = function() {
    if (postalCodeInput.value.length == 4) {
      var client;
      try {
	client = new ActiveXObject("Microsoft.XMLHTTP");    // Trying Internet Explorer
      } catch(e) {
	client = new XMLHttpRequest()
      }

      client.onreadystatechange = function() {
	if(client.readyState == 4 && client.status == 200) {
	  // so far so good
	  if(client.responseText != null) {
	    // success!
	    var result = client.responseText;
	    if (result.length > 0 ) {
	      postalAreaInput.value = result;
	    }
	  } else {
	    // No reply?
	  }
	} else if (this.readyState == 4 && this.status != 200) {
	  // fetched the wrong page or network error...
	}
      }

      client.open("GET", "search-postal-area.ajax?postal-code=" + postalCodeInput.value, true);
      client.send(null);
    }
  }
}


function categoryUpdate(tag) {
  var group;
  for (group = tag ; group && !elementHasClass(group, "group") ; group = group.parentNode);
  var tags = group.getElementsByTagName("input");
  maintag = tags[0];
  if (tag == maintag) {
    for (var i = 1; i < tags.length; i++) {
      if (maintag.checked) {
	tags[i].oldChecked = tags[i].checked;
	tags[i].checked = false;
      } else {
	tags[i].checked = tags[i].oldChecked;
      }
    }
  } else {
    maintag.checked = false;
    for (var i = 1; i < tags.length; i++) {
    }
  }
  if (maintag.checked) {
    elementSetClass(group, "disabled");
  } else {
    elementRemoveClass(group, "disabled");
  }
}


function initMunicipalitySelect() {
  var input = document.getElementById("place");
  var tr = document.getElementById("municipality-tr");
  var countySelect = document.getElementById("query.county-code");
  var select = document.getElementById("municipality-select");

  if (countySelect) {
    countySelect.onchange = function () {
      var m = municipalities[countySelect.value];
      if (m) {
	tr.style.display = "";
	for (var i = 0; i < m.length; i++) {
	  select.options[i] = new Option(m[i].title, m[i].id);
	}
	select.options.length = m.length;
      } else {
	tr.style.display = "none";
      }
      select.value = input.value;
      input.value = select.value;
    };

    select.onchange = function () {
      input.value = select.value;
    };

    countySelect.onchange();
  }
}


function initCategorySelect() {
  var input = document.getElementById("query.theme-id");
  var tr = document.getElementById("theme-tr");
  var categorySelect = document.getElementById("query.category-id");
  var select = document.getElementById("theme-select");

  if (categorySelect) {
    categorySelect.onchange = function () {
      var t = themes[categorySelect.value];
      if (t && t.length > 0) {
	tr.style.display = "";
	for (var i = 0; i < t.length; i++) {
	  select.options[i + 1] = new Option(t[i].title, t[i].id);
	}
	select.options.length = t.length + 1;
      } else {
	select.value = "0";
	input.value = "0";
	tr.style.display = "none";
      }
      select.value = input.value;
      input.value = select.value;
    };

    select.onchange = function () {
      input.value = select.value;
    };
    categorySelect.onchange();
  }
}
