/* IBE Common-always-loaded utilities. */

var KEY_LEFT = 0x01;
var KEY_UP = 0x02;
var KEY_RIGHT = 0x04;
var KEY_DOWN = 0x08;
var KEY_LSHIFT = 0x10;
var KEY_CTRL = 0x11;
var KEY_ESC = 27;
var KEY_DEL = 46;
var KEY_BACKSPACE = 8;

var logAlertLimit = 5;
var logAlertCounter = 0;

var EVENT_KEYDOWN = "keydown";
var EVENT_KEYUP = "keyup";
var EVENT_KEYPRESS = "keypress";

function clearField(f) {
  if (f.value == f.defaultValue) {
    f.value = "";
  }
}
function checkField(f) {
  if (f.value == "") {
    f.value = f.defaultValue;
  }
}

function getObj(id) {
  if (id == undefined) return null;
  var obj = null;
  if (document.getElementById) {
    obj = document.getElementById(id);
  } else {
    if (document.all) {
      obj = document.all[id];
    }
  }
  return obj;
}

function getObjsByName(id) {
  if (id == undefined) return null;
  return document.getElementsByName(id);
}

function getObjByName(id) {
  if (id == undefined) return null;
  var e = document.getElementsByName(id);
  if (e.length > 0)  return e[0];
  return null;
}

function getObjByIdThenName(id) {
  var e = getObj(id);
  if (e == null) e = getObjByName(id);
  return e;
}

function getEnabledObjByName(id) {
  if (id == undefined) return null;
  var es = document.getElementsByName(id);
  for (var i = 0; i < es.length; i++) {
    var e = es[i];
    if (!e.disabled) return e;
  }
  return null;
}

function getEnabledObjById(id) {
  if (id == undefined) return null;
  var e = document.getElementById(id);
  if (!e.disabled) return e;
  return null;
}

function toggleLayer(whichLayer, show) {
  if (document.getElementById) {
    var obj = getObj(whichLayer);
    if (obj) obj.style.display = show ? "" : "none";
  }
}

function toggleId(id) {
  if (document.getElementById) {
    var obj = getObj(id);
    var show = obj.style.display == "none";
    if (obj) obj.style.display = show ? "" : "none";
  }
}

function activate(id, isActive) {
  var obj = getObj(id);
  if (obj != null) {
    obj.readOnly = !isActive;
    obj.disabled = !isActive;
  }
}

function replaceHtml(e, html) {
  var obj = getObj(e);
  if (!obj) return;
  obj.innerHTML = html;
}

function showHide(e, show, setDisplay) {
  if (show) {
    setVisible(e, setDisplay);
  }
  else {
    setHidden(e, setDisplay);
  }
  return getObj(e);
}

function toggleVisible(elementId) {
  var obj = getObj(elementId);
  if (obj) {
    var s = obj.style;
    if (s.display == '' || s.display == 'visible') {
      setHidden(elementId, true);
    } else {
      setVisible(elementId, true);
    }
  }
}

function setVisible(elementID, setDisplay) {
  // If second arg is true then set style.display to apropriate value depending on type
  var obj = getObj(elementID);
  if (obj != null) {
    if (setDisplay)
    {
      obj.style.display = '';
    }
    obj.style.visibility = 'visible';
  }
}

function setVisibleObj(obj, setDisplay) {
  // If second arg is true then set style.display to apropriate value depending on type
  if (obj != null) {
    if (setDisplay)
    {
      obj.style.display = '';
    }
    obj.style.visibility = 'visible';
  }
}

function setHidden(elementID, setDisplay) {
  // If second arg is true then set style.display to 'none'
  var obj = getObj(elementID);
  if (obj != null) {
    obj.style.visibility = 'hidden';
    if (setDisplay)
    {
      obj.style.display = 'none';
    }
  }
}

function setHiddenObj(obj, setDisplay) {
  // If second arg is true then set style.display to 'none'
  if (obj != null) {
    obj.style.visibility = 'hidden';
    if (setDisplay)
    {
      obj.style.display = 'none';
    }
  }
}

function displayFor(e) {
  var tn = e.tagName.toUpperCase();
  var t = 'block';
  if (tn == 'TR')t = 'table-row';
  if (tn == 'TD')t = 'table-cell';
  if (tn == 'TABLE')t = 'table';
  return t;
}

function winStat(s) {
  window.status = s;
  return true;
}

function omo(e, isOver, cssClass) {
  var cl = e.className;
  if (isOver) {
    e.style.cursor = 'pointer';
    if (cssClass) e.className = (cl ? cl : '') + '___xxx ' + cssClass;
  } else {
    e.style.cursor = 'default';
    if (cssClass) e.className = cl.replace('___xxx ' + cssClass, '');
  }
}

function getPosition(o) {
  var start = getSelectionStart(o);
  if (start == getSelectionEnd(o)) {
    return start;
  } else {
    return -1;
  }
}

function setPosition(o, p) {
  if (o.createTextRange) {
    var r = document.selection.createRange();
    r.moveStart('character', -o.value.length);
    r.moveStart('character', p);
    r.moveEnd('character', 0);
    r.select();
  } else {
    o.selectionStart = p;
    o.selectionEnd = p;
  }
}

function getSelectionStart(o) {
  if (o.createTextRange) {
    var r = document.selection.createRange().duplicate();
    r.moveEnd('character', o.value.length);
    if (r.text == '') {
      return o.value.length;
    }
    return o.value.lastIndexOf(r.text);
  } else {
    return o.selectionStart;
  }
}

function getSelectionEnd(o) {
  if (o.createTextRange) {
    var r = document.selection.createRange().duplicate();
    r.moveStart('character', -o.value.length);
    return r.text.length;
  } else {
    return o.selectionEnd;
  }
}
function airlineWinOpen(doc) {
  var w = window.open(doc, 'CarrierPromo', 'scrollbars=no,resizable=no,height=' + IBE.CarrierPromoHeight + ',width=' + IBE.CarrierPromoWidth);
  if (w) w.focus();
}

function openPopupWindow(url) {
  var a = arguments;
  var h = a.length > 1 ? a[1] : 600;
  var v = a.length > 2 ? a[2] : 500;
  if (url.indexOf(':') == -1 && url.indexOf('?') == -1) url += ':popup';
  var w = window.open(url, 'PopupWindow', 'scrollbars=yes,resizable=yes,height=' + h + ',width=' + v);
  if (w) w.focus();
}

function openNewBrowserWindow(url) {
  window.open(url);
}

function goToUrl(url) {
  document.location.href = url
}

/*****************Globals****************/
var ckpaste_currentText = '';//initualizes the text of the text area.
var ckpaste_elem = null;//this will be the textarea.
var ckpaste_pasteMsg = 'Cannot paste into this field';
/****************************************/

/****************************************************************************
 void ckpaste_preventPaste();
 initializes the copy paste monitor.

 ****************************************************************************/

function ckpaste_preventPaste(elem, msg) {
  ckpaste_elem = elem;

  if (msg) {
    ckpaste_pasteMsg = msg
  } else {
    if (msg === false) {
      ckpaste_pasteMsg = msg;
    }
  }

  ckpaste_currentText = ckpaste_elem.defaultValue;
  if (document.all) {//it it is ie do the onpaste function
    ckpaste_elem.onpaste = ckpaste_showMessage;
    ckpaste_elem.oncontextmenu = ckpaste_showMessage;
    ckpaste_elem.onkeyup = ckpaste_checkText;
    ckpaste_elem.onblur = ckpaste_checkText;
    ckpaste_elem.onchange = ckpaste_checkText;
  } else {
    ckpaste_elem.addEventListener("keyup", ckpaste_checkText, true);
    ckpaste_elem.addEventListener("blur", ckpaste_checkText, true);
    ckpaste_elem.addEventListener("change", ckpaste_checkText, true);
  }
}

/****************************************************************************
 void ckpaste_preventPaste()
 checks the length of the string in the textbox and compares it with
 the length of the string in the saved ckpaste_currentText string. If the
 text box text is 10 characters longer than the saved string then it
 assumes that they have pasted.  it puts the current string back into
 the textarea over what they pasted and then shows them the message.
 if it isn't longer then it just puts the text into the saved text.

 ****************************************************************************/

function ckpaste_checkText(event) {
  event = event || window.event; // window.event for IE
  if (ckpaste_elem && event && event.keyCode) {
    var newTextLength = ckpaste_elem.value.length;//gets length of the textarea right now.
    var ckpaste_currentTextLength = ckpaste_currentText.length;//gets length of the saved text from the textarea
    //    if (newTextLength > (1 + ckpaste_currentTextLength)) {
    //      alert('event.keyCode: ' + event.keyCode + ', newTextLength: ' + newTextLength + ", ckpaste_currentTextLength: " + ckpaste_currentTextLength);
    //    }
    var codeForSelectingFromPrevList = 13;
    if (newTextLength > (ckpaste_currentTextLength + 10) && //is the new more then 10 characters longer?
        event.keyCode != codeForSelectingFromPrevList) {
      ckpaste_elem.value = ckpaste_currentText;//put the saved text back in/
      ckpaste_showMessage();//tell them they cannot paste.
    } else {
      ckpaste_currentText = ckpaste_elem.value;//if it is ok then save the text.
    }
  }
}
/****************************************************************************
 void ckpaste_showMessage();
 if they calling function wants to show a message when they paste then
 the message is alerted.
 ****************************************************************************/

function ckpaste_showMessage() {
  if (ckpaste_pasteMsg !== false) {
    alert(ckpaste_pasteMsg);
    return false;
  }
  return true;
}

function validEmail(f) {
  return f && f.length > 4; // Fusk
}
function submitNewsMail(f) {
  var nl = f.CRM_EMAIL;
  if (nl.defaultValue != nl.value && validEmail(nl.value)) {
    f.submit();
  } else {
    alert(UiText.get("Javascript.Util.Email"));
    nl.focus();
    nl.select();
  }
  return false;
}

function clickLink(link) {
  if (!link.nodeName) {
    link = getObj(link);
  }

  if (link.nodeName == 'a' || link.nodeName == 'A') {
    if (!link.onclick || link.onclick()) {
      var target = link.target ? link.target : '_self';
      window.open(link.href, target, '');
    }
    return false;
  }

  return true;
}

function findChildById(root, id) {
  if (nullOrUndefined(root)) {
    return document.getElementById(id);
  }
  else {
    ibeerror("Function not yet implemented.");
  }
}

function findChildrenByName(root, name) {
  if (nullOrUndefined(root)) {
    return document.getElementsByName(name);
  }
  else {
    var list = new Array();
    ibeerror("Function not yet implemented.");
  }
}

function getFieldName(elementId) {
  var d = getObjByIdThenName(elementId);
  if (d != null) return d.name;
  return '';
}

function getFieldValue(elementId, form) {
  var d = findChildById(form, elementId);
  if (d == null || d.type == 'radio') {
    var es = findChildrenByName(form, elementId);
    if (es != null) {
      if (es.length == 1) {
        var e = es[0];
        return e.value;
      } else {
        for (var i = 0; i < es.length; i++) {
          var r = es.item(i);
          if (r.checked) return r.value;
        }
      }
    }
  } else {
    if (d.type == 'checkbox') {
      return field.checked;
    } else {
      return d.value;
    }
  }
  return '';
}

function getValueFromFieldObject(field) {
  if (field == null || field.type == 'radio') {
    var es = getFieldsFromForm(field.form, field.name);
    if (es != null) {
      if (es.length == 1) {
        var e = es[0];
        return e.value;
      } else {
        for (var i = 0; i < es.length; i++) {
          var r = es.item(i);
          if (r.checked) return r.value;
        }
      }
    }
  } else {
    if (field.type == 'checkbox') {
      return field.checked;
    } else {
      return field.value;
    }
  }
  return '';
}

function stringToBool(s) {
  return s == "true";
}

function doInnerHTML(elementId, html, mode) {
  if (mode == 'append') {
    appendToInnerHTML(elementId, html);
  } else {
    setInnerHTML(elementId, html);
  }
}

function doElementsInnerHTML(element, html, mode) {
  if (mode == 'append') {
    appendToElementsInnerHTML(element, html);
  } else {
    setElementsInnerHTML(element, html);
  }
}

function setInnerHTML(elementID, html) {
  var e = getObj(elementID);
  if (e != null && propertyExists(e.innerHTML)) {
    e.innerHTML = html;
  }
}

function setElementsInnerHTML(e, html) {
  if (e != null && propertyExists(e.innerHTML)) {
    e.innerHTML = html;
  }
}

function appendToInnerHTML(elementId, html) {
  var e = getObj(elementId);
  if (e != null && propertyExists(e.innerHTML)) {
    e.innerHTML = e.innerHTML + html;
  }
}

function appendToElementsInnerHTML(e, html) {
  if (e != null && propertyExists(e.innerHTML)) {
    e.innerHTML = e.innerHTML + html;
  }
}

function getInnerHTML(elementId) {
  var e = getObj(elementId);
  if (e != null && propertyExists(e.innerHTML)) {
    return e.innerHTML;
  }
  return '';
}

function hasInnerHTML(elementId) {
  var e = getObj(elementId);
  if (e != null && propertyExists(e.innerHTML)) {
    return notEmptyString(trimString(e.innerHTML));
  }
  return false;
}

function clearInnerHTML(elementId) {
  setInnerHTML(elementId, '');
}

function notEmptyString(s) {
  return !emptyString(s);
}

function emptyString(s) {
  return s === undefined || s === null || s === "";
}

function trimString(s) {
  return s.replace(/^\s*/, "").replace(/\s*$/, "");
}

function setSrc(id, src) {
  var e = getObj(id);
  if (e != null && propertyExists(e.src)) {
    e.src = src;
  }
}

function propertyExists(property) {
  return typeof(property) !== 'undefined';
}

/**
 * Finds first parent element of type type. Searches recursively upwards the tree.
 * @param type The type to search for.
 * @param fromObj The object whos parent we examine.
 */
function findParentElementOfType(type, fromObj) {
  if (fromObj == null || fromObj == undefined) return null;
  if (fromObj.parentNode == null || fromObj.parentNode == undefined) return null;
  if (fromObj.parentNode.tagName == type) return fromObj.parentNode;
  return findParentElementOfType(type, fromObj.parentNode);
}

function removeAllTrFromTd(e) {
  do {
    var tdes = e.getElementsByTagName('td');
    if (tdes.length < 1) return;
    var tde = tdes[0];
    tde.parentNode.removeChild(tde);
  } while (tdes.length > 0)
}

/**
 * Checks if javascript function exists, returns true if that is the case.
 * @param funcName
 */
function functionExists(funcName) {
  return typeof funcName == 'string' && eval('typeof ' + funcName) == 'function';
}

function stringIsNumeric(s) {
  var validChars = "0123456789.,";
  return stringIncludesValidCharsOnly(s, validChars);
}

function stringIsInteger(s) {
  var validChars = "0123456789";
  return stringIncludesValidCharsOnly(s, validChars);
}

function stringIsPhoneNumber(s) {
  var validChars = "0123456789+-() ";
  return stringIncludesValidCharsOnly(s, validChars);
}

function stringIsDigitsAndDash(s) {
  var validChars = "0123456789-";
  return stringIncludesValidCharsOnly(s, validChars);
}

function stringIncludesValidCharsOnly(s, validChars) {
  if (s === undefined || s === null) return true;
  for (var i = 0; i < s.length; i++) {
    var c = s.charAt(i);
    if (validChars.indexOf(c) == -1) return false;
  }
  return true;
}

/**
 * Logs a string, if id is set, appends it to the element with that id. If not it checks if console.log is available
 * and uses that. If not, see if element with id 'console' is available. If not, alert is used.
 * @param s The string to be logged.
 * @param id The id of the element.
 */
function ibelog(s, id) {
  if (isProdEnvironment()) return;
  var e = getObj('console');
  if (getObj(id) != null) {
    appendToInnerHTML(id, s + '<br>\n');
  }
  else {
    if (typeof console == 'object' && typeof console.log == 'function') {
      console.log(s);
    }
    else {
      if (e != null) {
        appendToInnerHTML('console', s + '<br>\n');
      } else {
        if (isDevEnvironment()) {
          if (logAlertCounter < logAlertLimit) alert(s);
          logAlertCounter++;

          if (logAlertCounter == logAlertLimit) {
            alert('Alert limit has been reached, no more alerts will be shown. Limit=' + logAlertLimit);
          }
        }
      }
    }
  } // Do not allow alert in production environment.
}

/**
 * Logs a warning message to console. Should not output anything if in production!
 * @param s The string to be logged.
 */
function ibewarning(s) {
  if (isProdEnvironment()) return;
  if (typeof console == 'object' && typeof console.warning == 'function') {
    console.warning(s);
  } else {
    ibelog('Warning: ' + s);
  }
}

/**
 * Logs an error message to console. Should not output anything if in production!
 * @param s The string to be logged.
 */
function ibeerror(s) {
  if (isProdEnvironment()) return;
  if (typeof console == 'object' && typeof console.error == 'function') {
    console.error(s);
  } else {
    ibelog('Error: ' + s);
  }
}

/**
 * Checks to see if we are in debug environment, that is, NOT in production environment.
 */
function isDebugEnvironment() {
  return IBE.debug;
}

/**
 * Checks to see if we are in debug environment, that is, NOT in production environment.
 */
function isProdEnvironment() {
  return IBE.environment === 'prod';
}

function isTestEnvironment() {
  return IBE.environment === 'test';
}

function isDevEnvironment() {
  return IBE.environment === 'dev';
}

function nlToBr(s) {
  var tmp = undefined;
  var limit = 1000;
  while (limit > 0) {
    tmp = s.replace('\n', '<br>');
    if (tmp == s) break;
    s = tmp;
    limit--;
  }
  return tmp;
}
/**
 * Prints all properties for an object.
 * @param o
 */
function printAll(o) {
  ibelog(printAllToString(o));
}

function printArray(a) {
  ibelog('Array[' + a.length + '] =');
  for (var i = 0; i < a.length; i++) {
    var v = a[i];
    ibelog('  [' + i + '] =>');
    ibelog(v);
  }
}

function printAllToString(o) {
  var r = new String();
  r += '-- All variables in Object --\n';
  for (var prop in o) {
    if (typeof prop !== 'string') r += prop + ' (' + typeof prop + ') =' + o[prop] + '\n';
  }
  r += '----\n';
  return r;
}

function getObjectsProperties(o) {
  var l = [];
  var i = 0;
  for (var p in o) {
    l[i++] = p;
  }
  return l;
}

function enableId(id) {
  var e = getObj(id);
  if (e) e.disabled = false;
}

function disableId(id) {
  var e = getObj(id);
  if (e) e.disabled = true;
}

function autoCompleteOff(f) {
  f.setAttribute("autocomplete", "off");
}

function setElementsClass(id, className) {
  var e = getObj(id);
  if (e != null && propertyExists(e.className)) {
    e.className = className;
  }
}

function disableSelection(element) {
  if (typeof element.onselectstart != "undefined") //IE
  {
    element.onselectstart = function() {
      return false;
    };
  }
  else {
    if (typeof element.style.MozUserSelect != "undefined") //Firefox
    {
      element.style.MozUserSelect = "none";
    }
    else //Others
    {
      element.onmousedown = function() {
        return false;
      };
    }
  }
}

function useDefault(value, defaultValue) {
  if (value === undefined || value === null) {
    return defaultValue;
  } else {
    return value;
  }
}

function trim(str) {
  return str.replace(/^\s*|\s*$/g, "");
}

function implode(list, separator) {
  var r = '';
  var isFirst = true;
  for (var i = 0; i < list.length; i++) {
    if (isFirst === true || separator === undefined) {
      isFirst = false;
    } else {
      r = r + separator;
    }
    r = r + list[i];
  }
  return r;
}

function removeListHead(list) {
  var nl = new Array();
  for (var i = 1; i < list.length; i++) {
    nl[i - 1] = list[i];
  }
  return nl;
}

/**
 * Same as split, but for lists. For example.
 * 0: "mattias is"
 * 1: "awesome"
 * separator: " "
 * will result in
 * 0: "mattias"
 * 1: "is"
 * 2: "awesome"
 * @param list
 * @param separator
 */
function splitList(list, separator) {
  var nlist = new Array();
  for (var i = 0; i < list.length; i++) {
    var l = list[i].split(separator);
    for (var j = 0; j < l.length; j++) {
      nlist[nlist.length] = l[j];
    }
  }
  return nlist;
}

function startsWith(str, v) {
  return str.substring(0, v.length) == v;
}

function endsWith(str, v) {
  return str.substring(v.length - 1, v.length) == v;
}

String.prototype.trim = function() {
  return (this.replace(/^[\s\xA0]+/, "").replace(/[\s\xA0]+$/, ""));
};

String.prototype.startsWith = function(str) {
  return (this.match("^" + str) == str);
};

String.prototype.endsWith = function(str) {
  return (this.match(str + "$") == str);
};

function subList(list, startIndex, length) {
  var rlist = new Array();
  var endIndex = startIndex + length;
  if (length < 0) endIndex = list.length - 1;
  for (var i = startIndex; i < endIndex; i++) {
    rlist[rlist.length] = list[i];
  }

  return rlist;
}

function nullOrUndefined(s) {
  var r = s === null || s === undefined;
  return r;
}

function nonFalse(s) {
  return s === undefined || s;
}

function nonTrue(s) {
  return !(s === undefined || !s);
}

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

Array.prototype.indexInArray = function (value) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == value) {
      return i;
    }
  }
  return -1;
};

function getCookie(name) {
  //console.log('getCookie name=' + name);
  if (!name) return null;
  var start = document.cookie.indexOf(name + "=");
  var len = start + name.length + 1;
  if (( !start ) && ( name != document.cookie.substring(0, name.length) )) {
    return null;
  }
  if (start == -1) return null;
  var end = document.cookie.indexOf(';', len);
  if (end == -1) end = document.cookie.length;
  var r = unescape(document.cookie.substring(len, end));
  //console.log('=' + r);
  return r;
}

function setCookie(name, value, expires, path, domain, secure) {
  //console.log('setcookie name=' + name + ' value=' + value);
  if (!name) return;
  var today = new Date();
  today.setTime(today.getTime());
  if (expires) {
    expires = expires * 1000 * 60 * 60 * 24;
  }
  var expires_date = new Date(today.getTime() + (expires));
  document.cookie = name + '=' + escape(value) +
                    ( ( expires ) ? ';expires=' + expires_date.toGMTString() : '' ) + //expires.toGMTString()
                    ( ( path ) ? ';path=' + path : '' ) +
                    ( ( domain ) ? ';domain=' + domain : '' ) +
                    ( ( secure ) ? ';secure' : '' );
}

function deleteCookie(name, path, domain) {
  if (getCookie(name)) {
    document.cookie = name + '=' +
                      ( ( path ) ? ';path=' + path : '') +
                      ( ( domain ) ? ';domain=' + domain : '' ) +
                      ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
  }
}

function getElementsByClass(searchClass, node, tag) {
  var classElements = new Array();
  if (node == null)
  {
    node = document;
  }
  if (tag == null)
  {
    tag = '*';
  }
  var els = node.getElementsByTagName(tag);
  var elsLen = els.length;
  var pattern = new RegExp('(^|\\\\s)' + searchClass + '(\\\\s|$)');
  var j = 0;
  for (var i = 0; i < elsLen; i++) {
    if (pattern.test(els[i].className)) {
      classElements[j] = els[i];
      j++;
    }
  }
  return classElements;
}

function removeFnutts(s) {
  if (s.length > 2) {
    if ((s.startsWith('\'') && s.endsWith('\'')) ||
        (s.startsWith('"') && s.endsWith('"')    )) {
      return s.substring(1, s.length - 1);
    }
  }
  return s;
}

function isArray(obj) {
  if (nullOrUndefined(obj)) return false;
  if (obj.constructor.toString().indexOf("Array") == -1)
  {
    return false;
  }
  else
  {
    return true;
  }
}

function addSelectOption(selectbox, text, value, cssClass, selected) {
  if (selectbox) {
    var e = document.createElement("OPTION");
    e.text = text;
    e.value = value;
    if (cssClass) e.className = cssClass;
    if (selected) {
      e.selected = true;
    }
    selectbox.options.add(e);
  }
}

function addSelectOptionObject(selectbox, option) {
  if (selectbox) {
    selectbox.options.add(option);
  }
}

function findOptionByValue(selectbox, value) {
  for (i = selectbox.options.length - 1; i >= 0; i--) {
    if (selectbox.options[i].value == value) return selectbox.options[i];
  }
  return null;
}

function selectOption(selectbox, value) {
  for (i = selectbox.options.length - 1; i >= 0; i--) {
    if (selectbox.options[i].value == value) {
      selectbox.selectedIndex = i;
      return;
    }
  }
}

function clearSelectOptions(selectbox) {
  for (i = selectbox.options.length - 1; i >= 0; i--) {
    // Must be done backwards, otherwise it doesn't work.
    selectbox.options[i] = null;
  }
}

function greatCircleDistance(lat1, lon1, lat2, lon2) {
  var R = 6371; // km
  var d = Math.acos(Math.sin(lat1) * Math.sin(lat2) +
                    Math.cos(lat1) * Math.cos(lat2) *
                    Math.cos(lon2 - lon1)) * R;
  return d;
}

// extend Number object with methods for converting degrees/radians

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
};

Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
  return this * 180 / Math.PI;
};

Number.prototype.toBrng = function() {  // convert radians to degrees (as bearing: 0...360)
  return (this.toDeg() + 360) % 360;
};

function greatCircleDistance2(lat1, lon1, lat2, lon2) {
  var R = 6371; // km
  var dLat = (lat2 - lat1).toRad();
  var dLon = (lon2 - lon1).toRad();
  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
          Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
          Math.sin(dLon / 2) * Math.sin(dLon / 2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  var d = R * c;
  return d;
}

function setInnerHtmlToLoadingAnimation(elementID, className) {
  if (!className) className = "largeLoadingAnimationContainer";
  setInnerHTML(elementID, '<div class="' + className + '">' +
                          '<img src="/system/image/loading_animation_small.gif" alt="Loading"/>' +
                          '</div>');

}

function setInnerHtmlToSmallLoadingAnimation(elementID, width, paddingTop) {
  if (paddingTop === undefined) paddingTop = "2px";
  setInnerHTML(elementID, '<img style="padding-left:8px; padding-top: ' + paddingTop + ';' +
                          (width ? 'width:' + width + ';' : '') +
                          '" src="/system/image/loading_16x16.gif" alt="Loading"/>');

}

function getRandomUnusedId(id) {
  while (getObj(id)) {
    id = id + (Math.random() * 10);
  }
  return id;
}

function clearElement(element) {
  if (element) while (element.firstChild) element.removeChild(element.firstChild);
}

/** Context class **/
function Context(key) {

  this.contextKey = key;

  this.get = function(key) {
    if (key) {
      if (this.contextKey) {
        return YAHOO.util.Cookie.getSub(this.contextKey, key);
      } else {
        return YAHOO.util.Cookie.get(key);
      }
    }
  };

  this.set = function(key, obj) {
    if (key) {
      if (this.contextKey) {
        YAHOO.util.Cookie.setSub(this.contextKey, key, obj);
      } else {
        YAHOO.util.Cookie.set(key, obj);
      }
    }
  };

}


function logoutCustomer() {
  // TODO: Fix ugly hack
  AjaxLogoutUser.startRequest(function(result) {
    if (YAHOO.util.Dom.hasClass(document.body, 'user-profiles')) {
      redirect("");
    } else {
      reloadPage();
    }
  });
}

function getSmallerAnimationHTML() {
  return '<img alt="Loading..." src="/system/image/loading_animation_smaller.gif"/>';
}

function getSmallestAnimationHTML() {
  return '<img alt="Loading..." src="/system/image/loading16x16.gif"/>';
}

/**
 * If used within an iframe, only the iframe will reload!
 */
function reloadPage() {
  window.location.reload();
}

/**
 * Reloads the window, this can be used even if in an iframe. Iframe will not reload, but instead the whole page.
 */
function reloadWindow() {
  top.location.reload();
}

function reloadParent() {
  if (parent) {
    parent.location.reload();
  }
}

function redirectOnTimeout(action, timeOut) {
  timeOut = useDefault(timeOut, 5000);
  setTimeout(function () {
    redirect(action);
  }, timeOut);
}

function redirect(action) {
  redirectPure(checkAction(action));
}

function redirectPure(path) {
  window.location.pathname = path;
}

/**
 * Shows an alert if the message is defined and not empty string, if the condition is undefined or true.
 * @param s
 * @param condition
 */
function ibealert(s, condition) {
  if (condition === undefined || condition === true) {
    if (s) alert(s);
  }
}

function checkAction(url) {
  if (emptyString(url)) return "";
  url = prependIfNotThere(url, "/");
  if (url != "/" && url.indexOf("?") == -1) {
    url = appendIfNotThere(url, ".action");
  }
  return url;
}

function appendIfNotThere(base, add) {
  return (base.endsWith(add) ? base : base + add);
}

function prependIfNotThere(base, add) {
  return (base.startsWith(add) ? base : add + base);
}

/**
 * Returns all fields in a form with a given name. Usually just one, but radio buttons usually have more than one.
 * @param form
 * @param fieldName
 */
function getFieldsFromForm(form, fieldName) {
  var result = new Array();
  if (!form) {
    ibeerror("Trying to get field in form that is undefined.");
    return undefined;
  }
  var elements = form.elements;
  if (elements) {
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      if (element.name == fieldName) {
        result.push(element);
      }
    }
  }
  if (result.length == 0) return null;
  return result;
}

function getFieldFromForm(form, fieldName) {
  var r = getFieldsFromForm(form, fieldName);
  if (r) {
    return r[0];
  }
  else {
    return null;
  }
}

function getSelectFieldValue(field) {
  var options = field.options;
  for (var i = 0; i < options.length; i++) {
    var option = options[i];
    if (option.selected) return option.value;
  }
  return null;
}

function getSelectedOption(selectField) {
  var options = selectField.options;
  if (options && options.length) {
    for (var i = 0; i < options.length; i++) {
      var option = options[i];
      if (option.selected) return option;
    }
  }
  return null;
}

function getIndexOfOptionWithInnerHtml(selectField, html) {
  var options = selectField.options;
  if (options && options.length) {
    for (var i = 0; i < options.length; i++) {
      var option = options[i];
      if (option.innerHTML === html) return i;
    }
  }
  return -1;
}

function getValueOfOptionWithInnerHtml(selectField, html) {
  var options = selectField.options;
  if (options && options.length) {
    for (var i = 0; i < options.length; i++) {
      var option = options[i];
      if (option.innerHTML === html) return option.value;
    }
  }
  return null;
}

//See ValidationUtil.java for description and ValidationUtilTest.java for tests
function isValidPassword(password) {
  var regex = /^[^\s]{6,}$/;
  return regex.test(password);
}

function isValidEmail(email) {
  var regex = /^\w+([\.\-\+]?\w+)*@\w+([\.\-\+]?\w+)*(\.\w{2,})+$/;
  return regex.test(email);
}

/* Matches 6 to 15 digits, used for phone numbers, see standard E.164 */
function isValidPhoneNumber(phoneNumber) {
  var regex = /^\d{6,15}$/;
  return regex.test(trimPhoneNumber(phoneNumber));
}

/* Trims away " .-" and leading "00" or "+" */
function trimPhoneNumber(phoneNumber) {
  var regex = /^00|^\+|[\s.-]+/;
  return phoneNumber.replace(regex, "");
}

function parseJsonList(s) {
  var e = eval(s);
  return e;
}

function parseJsonObject(s) {
  var e = eval('[' + s + ']');
  return e[0];
}

function isEmptyArray(o) {
  if (o === undefined) return true;
  if (o === null) return true;
  if (o.length) {
    return true;
  }
  else {
    return false;
  }
}

function deleteElementInArray(array, index) {
  array.splice(index, 1);
}

function runSoon(func, delayInMs) {
  setTimeout(func, delayInMs);
}

/****************
 Fading functions
 ****************/

function fade(elementId, timeToFade) {
  if (!timeToFade) timeToFade = 1000.0;

  var element = document.getElementById(elementId);
  if (element == null) return;
  element.FadeState = null;

  if (element.FadeState == null) {
    if (element.style.opacity == null || element.style.opacity == '' || element.style.opacity == '1') {
      element.FadeState = 2;
    } else {
      element.FadeState = -2;
    }
  }

  if (element.FadeState == 1 || element.FadeState == -1) {
    element.FadeState = element.FadeState == 1 ? -1 : 1;
    element.FadeTimeLeft = timeToFade - element.FadeTimeLeft;
  } else {
    element.FadeState = element.FadeState == 2 ? -1 : 1;
    element.FadeTimeLeft = timeToFade;
    setTimeout("animateFade(" + new Date().getTime() + ",'" + elementId + "', " + timeToFade + ")", 33);
  }
}

function animateFade(lastTick, elementId, timeToFade) {
  if (!timeToFade) timeToFade = 1000.0;
  var curTick = new Date().getTime();
  var elapsedTicks = curTick - lastTick;

  var element = document.getElementById(elementId);

  if (element.FadeTimeLeft <= elapsedTicks) {
    element.style.opacity = element.FadeState == 1 ? '1' : '0';
    element.style.filter = 'alpha(opacity = '
      + (element.FadeState == 1 ? '100' : '0') + ')';
    element.FadeState = element.FadeState == 1 ? 2 : -2;
    return;
  }

  element.FadeTimeLeft -= elapsedTicks;
  var newOpVal = element.FadeTimeLeft / timeToFade;
  if (element.FadeState == 1)    newOpVal = 1 - newOpVal;

  element.style.opacity = newOpVal;
  element.style.filter = 'alpha(opacity = ' + (newOpVal * 100) + ')';

  setTimeout("animateFade(" + curTick + ",'" + elementId + "')", 33);
}

function insertArgument(text, arg0, arg1, arg2, arg3) {
  if (arg0) text = text.split('{0}').join(arg0);
  if (arg1) text = text.split('{1}').join(arg1);
  if (arg2) text = text.split('{2}').join(arg2);
  if (arg3) text = text.split('{3}').join(arg3);
  return text;
}

function setZIndex(elementId, zIndex) {
  var e = getObj(elementId);
  if (e) e.style.zIndex = zIndex;
}

function exceptionToString(e) {
  if (e.description) {
    return e.description;
  }
  else {
    if (e.toString) {
      return e.toString();
    }
    else {
      return e;
    }
  }
}

function elementExists(elementId) {
  return getObj(elementId) ? true : false;
}

function enableOptionDisabledInIE(select) {
  window.select_current = [];
  $(select).focus(function() {
    window.select_current[this.id] = this.selectedIndex;
  });
  /*
   select.onfocus = function() {
   window.select_current[this.id] = this.selectedIndex;
   };
   */
  $(select).click(function() {
    restoreOptionDisable(this);
  });
  /*select.onchange = function() {
   restoreOptionDisable(this);
   };*/
  emulateOptionDisable(select);
}

function restoreOptionDisable(e) {
  if (e.options[e.selectedIndex].disabled) {
    e.selectedIndex = window.select_current[e.id];
  }
}

function emulateOptionDisable(e) {
  for (var i = 0, option; option = e.options[i]; i++) {
    var color;
    if (option.disabled) {
      color = "graytext";
    } else {
      color = "menutext";
    }
    option.style.color = color;
  }
}

function dateStringToDateObject(dateString) {
  if (!dateString) {
    return null;
  } else {
    var arr = dateString.split("-");
    return dateArrayToDateObject(arr);
  }
}

function dateArrayToDateObject(dateArray) {
  return new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
}

var BrowserDetect = {
  init: function () {
    this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
    this.version = this.searchVersion(navigator.userAgent)
      || this.searchVersion(navigator.appVersion)
      || "an unknown version";
    this.OS = this.searchString(this.dataOS) || "an unknown OS";
  },
  searchString: function (data) {
    for (var i = 0; i < data.length; i++) {
      var dataString = data[i].string;
      var dataProp = data[i].prop;
      this.versionSearchString = data[i].versionSearch || data[i].identity;
      if (dataString) {
        if (dataString.indexOf(data[i].subString) != -1)
        {
          return data[i].identity;
        }
      }
      else {
        if (dataProp)
        {
          return data[i].identity;
        }
      }
    }
  },
  searchVersion: function (dataString) {
    var index = dataString.indexOf(this.versionSearchString);
    if (index == -1) return;
    return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
  },
  dataBrowser: [
    {
      string: navigator.userAgent,
      subString: "Chrome",
      identity: "Chrome"
    },
    {         string: navigator.userAgent,
      subString: "OmniWeb",
      versionSearch: "OmniWeb/",
      identity: "OmniWeb"
    },
    {
      string: navigator.vendor,
      subString: "Apple",
      identity: "Safari",
      versionSearch: "Version"
    },
    {
      prop: window.opera,
      identity: "Opera"
    },
    {
      string: navigator.vendor,
      subString: "iCab",
      identity: "iCab"
    },
    {
      string: navigator.vendor,
      subString: "KDE",
      identity: "Konqueror"
    },
    {
      string: navigator.userAgent,
      subString: "Firefox",
      identity: "Firefox"
    },
    {
      string: navigator.vendor,
      subString: "Camino",
      identity: "Camino"
    },
    {                // for newer Netscapes (6+)
      string: navigator.userAgent,
      subString: "Netscape",
      identity: "Netscape"
    },
    {
      string: navigator.userAgent,
      subString: "MSIE",
      identity: "Explorer",
      versionSearch: "MSIE"
    },
    {
      string: navigator.userAgent,
      subString: "Gecko",
      identity: "Mozilla",
      versionSearch: "rv"
    },
    {                 // for older Netscapes (4-)
      string: navigator.userAgent,
      subString: "Mozilla",
      identity: "Netscape",
      versionSearch: "Mozilla"
    }
  ],
  dataOS : [
    {
      string: navigator.platform,
      subString: "Win",
      identity: "Windows"
    },
    {
      string: navigator.platform,
      subString: "Mac",
      identity: "Mac"
    },
    {
      string: navigator.userAgent,
      subString: "iPhone",
      identity: "iPhone/iPod"
    },
    {
      string: navigator.platform,
      subString: "Linux",
      identity: "Linux"
    }
  ]

};
BrowserDetect.init();

function browserIsIE() {
  return BrowserDetect.browser == "Explorer";
}

function sendKeyEvent(eventType, characterToPress, targetElement) {
  var evObj = undefined;
  if (window.KeyEvent) {
    evObj = document.createEvent('KeyEvents');
    evObj.initKeyEvent(eventType, true, true, window, false, false, false, false, characterToPress, 0);
    console.log('KeyEvent');
  } else {
    console.log('UIEvent');
    evObj = document.createEvent('UIEvents');
    evObj.initUIEvent(eventType, true, true, window, 1);
    evObj.keyCode = characterToPress;
  }
  targetElement.dispatchEvent(evObj);
}

function addTooltipToDomIfNotExists(className, id) {
  if (!getObj(id)) {
    var div = document.createElement("div");
    div.id = id;
    div.className = className;
    document.body.appendChild(div);
  }
}

function overlib(text, element, className, effect) {
  if (!className) className = "overlibTooltip";
  if (!effect) effect = "slide";
  $(element).attr("title", text);
  $(element).tooltip({
    tipClass:className,
    effect: effect
  });

  // Show it immediately.
  var api = $(element).data("tooltip");
  api.show();
}

function nd(element) {
  $(element).tooltip("destroy");
}

function setOverLibStartHeight(h) {
  if (stringIsNumeric(h)) {
    // Set height
  } else {
    if (h.toLowerCase().trim() == "auto") {

    } else {
      ibewarning("Invalid overlib start height set: " + h);
    }
  }
}

/**********************************************
 Request methods that use jQuery instead of YUI
 **********************************************/

function sendRequest(url, successFunction, failFunction, customObject, loadAnimation, forceAutoMessage, disableAlerts) {
  if (loadAnimation) setInnerHtmlToSmallLoadingAnimation(loadAnimation);
  $.ajax({
    url: url,
    dataType: 'json',
    success: function(response, textStatus, XMLHttpRequest) {

      if (forceAutoMessage === true) ibealert(response.message, !disableAlerts);

      if (response.resultType == 'OK') {
        if (!forceAutoMessage) ibealert(response.message, !disableAlerts);
        if (successFunction && typeof successFunction == 'function') successFunction(response, customObject);
      } else {
        // Not "OK", exception in server request
        if (failFunction && typeof failFunction == 'function') {
          failFunction(response, customObject);
        } else {
          if (!forceAutoMessage) ibealert(response.message, !disableAlerts);
        }
        if (loadAnimation) clearInnerHTML(loadAnimation);
      }

    },
    error: function(request, textStatus, error) {
      // Invalid JSON received, there is no response or response.message.
      if (loadAnimation) clearInnerHTML(loadAnimation);
      if (failFunction && typeof failFunction === 'function') {
        failFunction(undefined, customObject, error);
      } else {
        ibealert('An internal system error occured, please try again later. If the problem persists, please contact us.', !disableAlerts);
      }
    }
  });
}

function sendPostRequest(url, postData, successFunction, failFunction, customObject, loadAnimation, forceAutoMessage,
                         disableAlerts) {
  if (loadAnimation) setInnerHtmlToSmallLoadingAnimation(loadAnimation);
  if (typeof postData === "object" && typeof postData.length === "number") postData = postData.join("&");
  $.ajax({
    url: url,
    dataType: 'json',
    data: postData,
    type: 'POST',
    success: function(response, textStatus, XMLHttpRequest) {

      if (forceAutoMessage === true) ibealert(response.message, !disableAlerts);

      if (response.resultType == 'OK') {
        if (!forceAutoMessage) ibealert(response.message, !disableAlerts);
        if (successFunction && typeof successFunction == 'function') successFunction(response, customObject);

      } else {
        // Not "OK", exception in server request
        if (failFunction && typeof failFunction == 'function') {
          failFunction(response, customObject);
        } else {
          if (!forceAutoMessage) ibealert(response.message, !disableAlerts);
        }
        if (loadAnimation) clearInnerHTML(loadAnimation);
      }

    },
    error: function(request, textStatus, error) {
      // Invalid JSON received, there is no response or response.message.
      if (loadAnimation) clearInnerHTML(loadAnimation);
      if (failFunction && typeof failFunction === 'function') {
        failFunction(undefined, customObject, error);
      }
      else {
        ibealert('An internal system error occured, please try again later. If the problem persists, please contact us.', !disableAlerts);
      }
    }
  });
}

function sendFormRequest(form, successFunction, failFunction, customAction, customObject, loadAnimation,
                         forceAutoMessage, disableAlerts) {
  if (loadAnimation) setInnerHtmlToSmallLoadingAnimation(loadAnimation);
  if (!customAction) customAction = form.action;
  var postData = $(form).serialize(); //formParametersToStringFormat(form);
  sendPostRequest(customAction, postData, successFunction, failFunction, customObject, loadAnimation, forceAutoMessage, disableAlerts);
}

/**
 * Takes all fields of a form and assembles them into a GET formatted string with all variable names and values.
 * Example: id=35&name=mattias&age=12
 * @param form The form to use.
 */
function formParametersToStringFormat(form) {
  if (!form) {
    ibeerror('Form element is null.');
    return null;
  }
  var parameters = new RequestParameters(form);
  return parameters.toString();
}

function RequestParameters(form) {
  this.parameters = new Array();

  this.addParameter = function (parameterName, parameterValue) {
    this.parameters.push({"name":parameterName, "value":parameterValue});
  };

  if (form) {
    var es = form.elements;
    if (nullOrUndefined(es)) {
      ibeerror('No elements attribute in formElement with id=' + form.id);
      return;
    }
    for (var i = 0; i < es.length; i++) {
      var inputElement = es[i];
      if (inputElement.type != "radio") {
        this.addParameter(inputElement.name, inputElement.value);
      } else {
        if (inputElement.checked) {
          this.addParameter(inputElement.name, inputElement.value);
        }
      }
    }
  }

}


RequestParameters.prototype.toString = function() {
  var output = new Array();
  for (var i = 0; i < this.parameters.length; i++) {
    var p = this.parameters[i];
    var val = p.value;
    if (typeof val === "string" ||
        typeof val === "double" ||
        typeof val === "float") {
      val = encodeURIComponent(val);
    }
    output.push(p.name + "=" + val);
  }
  return output.join("&");
};


/**
 * Opens a dialogue box. Requires jQuery UI.
 * @param title
 * @param text
 * @param buttons
 */
function openDialogueBox(title, text, buttons, height) {
  if (!height) height = 140;
  var dialogueHtml = '<div id="dialogueBoxDiv" title="Are you sure?" style="display:none;">' +
                     '<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>' +
                     '<span id="dialogueBoxDivText">Are you sure?</span></p>' +
                     '</div>';

  if (!getObj('dialogueBoxDiv')) {
    $('body').append(dialogueHtml);
  } else {
    $("#dialogueBoxDiv").dialog("destroy"); // Restore it to pre-dialog state, with title attribute, etc.
  }
  $("#dialogueBoxDiv").attr("title", title);
  $("#dialogueBoxDivText").html(text);
  $("#dialogueBoxDiv").dialog({
    resizable: false,
    zIndex:10100,
    height:height,
    modal: true,
    buttons: buttons
  });
}
