/***********************************************
 * @fileoverview
 *
 * nexbyte global script - added to all sites
 *
 * @created   05.06.2001 - tbruederli
 * @modified  31.05.2006 - tbruederli
 * @copyright by nexbyte gmbh, switzerland
 *
 ***********************************************/

/*
 * History:
 *  
 * 22.12.2005/tboonstoppel:  nex_get_event, nex_set_dom_update() added
 * 12.01.2006/tboonstoppel:  nex_size_handler_fix(), nex_resize_is_needed() added
 * 03.04.2006/tbruederli:    added MSIE 7 to browser detection
 * 03.04.2006/tboonstoppel:  added parameter 'key' to find in array
 * 11.04.2006/tbruederli:    fixed IE bug with get_window_size()
 * 03.04.2006/tboonstoppel:  added functions 'urlencode' and 'urldecode'
 * 31.05.2006/tbruederli:    added 'css2' property in nex_browser class
 */


/**
 * Generic browsercheck class
 * 
 * @class
 * @constructor
 * @package globals
 */
function nex_browser()
  {
  /** @type Float */
  this.ver = parseFloat(navigator.appVersion);

  /** @type String */
  this.appver = navigator.appVersion;

  /** @type String */
  this.agent = String(navigator.userAgent);

  /** @type String */
  this.name = navigator.appName;

  /** @type String */
  this.vendor = navigator.vendor ? navigator.vendor : '';

  /** @type Float */
  this.vendver = navigator.vendorSub ? parseFloat(navigator.vendorSub) : 0;

  /** @type String */
  this.product = navigator.product ? navigator.product : '';

  /** @type String */
  this.platform = String(navigator.platform).toLowerCase();

  /**
   * Browser language (2 digits)
   * @type String
   */
  this.lang = (navigator.language) ? navigator.language.substring(0,2) :
              (navigator.browserLanguage) ? navigator.browserLanguage.substring(0,2) :
              (navigator.systemLanguage) ? navigator.systemLanguage.substring(0,2) : 'en';

  /** @type Boolean */
  this.win = (this.platform.indexOf('win')>=0) ? true : false;

  /** @type Boolean */
  this.winxp = (this.agent.indexOf('NT 5.1')>0) ? true : false;

  /** @type Boolean */
  this.mac = (this.platform.indexOf('mac')>=0) ? true : false;

  /** @type Boolean */
  this.linux = (this.platform.indexOf('linux')>=0) ? true : false;

  /** @type Boolean */
  this.unix = (this.platform.indexOf('unix')>=0) ? true : false;

  /**
   * Suport for DOM operation
   * @type Boolean
   */
  this.dom = document.getElementById ? true : false;

  /**
   * Suport for DOM Level 2
   * @type Boolean
   */
  this.dom2 = (document.addEventListener && document.removeEventListener);

  /** @type Boolean */
  this.ie = (document.all) ? true : false;

  /** @type Boolean */
  this.ie4 = (this.ie && !this.dom);

  /** @type Boolean */
  this.ie5 = (this.dom && this.appver.indexOf('MSIE 5')>0);

  /** @type Boolean */
  this.ie6 = (this.dom && this.appver.indexOf('MSIE 6')>0);

  /** @type Boolean */
  this.ie7 = (this.dom && this.appver.indexOf('MSIE 7')>0);

  /** @type Boolean */
  this.mz = (this.dom && this.ver>=5);  // (this.dom && this.product=='Gecko')

  /** @type Boolean */
  this.ns = ((this.ver<5 && this.name=='Netscape') || (this.ver>=5 && this.vendor.indexOf('Netscape')>=0));

  /** @type Boolean */
  this.ns4 = (this.ns && parseInt(this.ver)==4);

  /** @type Boolean */
  this.ns6 = (this.ns && parseInt(this.vendver)==6);  // (this.mz && this.ns) ? true : false;

  /** @type Boolean */
  this.ns60 = (this.ns && this.agent.indexOf('Netscape6/6.0')>0);

  /** @type Boolean */
  this.safari = this.agent.toLowerCase().indexOf('safari')>0;

  /** @type Boolean */
  this.konq   = (this.agent.toLowerCase().indexOf('konqueror')>0); 

  /** @type Boolean */
  this.opera = (window.opera) ? true : false;

  /** @type Boolean */
  this.opera5 = (this.opera5 && this.agent.indexOf('Opera 5')>0) ? true : false;

  /**
   * Browser vendor version
   * @type Float
   */
  this.vendver = 0;

  if(this.opera && window.RegExp)
    this.vendver = (/opera(\s|\/)([0-9\.]+)/i.test(navigator.userAgent)) ? parseFloat(RegExp.$2) : -1;
  else if(!this.vendver && this.safari)
    this.vendver = (/safari\/([0-9]+)/i.test(this.agent)) ? parseInt(RegExp.$1) : 0;
  else if(!this.vendver && this.mz)
    this.vendver = (/rv:([0-9\.]+)/.test(this.agent)) ? parseFloat(RegExp.$1) : 0;
  else if(this.ie && window.RegExp)
    this.vendver = (/msie\s+([0-9\.]+)/i.test(this.agent)) ? parseFloat(RegExp.$1) : 0;

  /**
   * Engine release version
   * @type Float
   */
  if (this.product=='Gecko')
    this.enginerv = (/rv:([0-9\.]+)/.test(this.agent)) ? parseFloat(RegExp.$1) : 0;

  // get real language out of safari's user agent
  if(this.safari && (/;\s+([a-z]{2})-[a-z]{2}\)/i.test(this.agent)))
    this.lang = RegExp.$1;

  /** @type Boolean */
  this.dhtml = ((this.ie4 && this.win) || (this.ie && this.vendver>=5) || this.ns4 || this.mz);

  /** @type Boolean */
  this.layers = this.ns4;  // (document.layers);

  /** @type Boolean */
  this.div = (this.ie4 || this.dom);

  /** @type Boolean */
  this.vml = (this.win && this.ie && this.dom && !this.opera);

  /** @type Boolean */
  this.css2 = ((this.ie && this.vendver>=7) || this.mz || (this.opera && this.vendver>=7));

  /** @type Boolean */
  this.linkborder = (this.ie || this.mz);

  /** @type Boolean */
  this.rollover = (this.ver>=4 || (this.ns && this.ver>=3));  // (document.images) ? true : false;

  /** @type Boolean */
  this.pngalpha = (this.mz || (this.opera && this.vendver>=6) || (this.ie && this.mac && this.vendver>=5) ||
                   (this.ie && this.win && this.vendver>=5.5) || this.safari);

  /** @type Boolean */
  this.opacity = (this.mz || (this.ie && this.vendver>=5.5 && !this.opera) || (this.safari && this.vendver>=100));

  /** @type Boolean */
  this.cookies = navigator.cookieEnabled;

  /**
   * Perform a check for Mozilla Canvas support
   * 
   * @return True if <canvas> is supported, false if not
   * @type Boolean
   */
  this.check_canvas = function()
    {
      var cnvs = false;
      
      if(this.dom)
        {
        var elm = document.createElement('canvas');
      
        if(elm.getContext && typeof(elm.getContext) == 'function')
          cnvs = true;
          
        document.deleteElement(elm);
        }
      
      return cnvs;
    }

  /**
   * Perform a check for ActiveX support
   * 
   * @return True if ActiveX is supported, false if not
   * @type Boolean
   */
  this.check_activeX = function()
    {
    if (this.ie && window.ActiveXObject)
      {
      var ax_test = new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}");
      if (typeof(ax_test)=='function')
        return ax_test();
      else
        return false;
      }
    
    return false;
    };


  /**
   * Redirect browser to a new location
   *
   * @param {String} url Location to redirect
   */
  this.redirect = function(url)
    {
    if (location.replace)
      location.replace(url);
    else
      location.href = url;
    };

  }



/**
 * Return the value of a document cookie
 *
 * @param {String} name Cookie name
 * @return Cookie value or false if not set
 * @type Mixed
 */
function nex_get_cookie(name)
  {
  if(!document.cookie)
    return false;

  // read cookie data and store it as static variable
  if (!nex_get_cookie.cookie_data)
    {
    nex_get_cookie.cookie_data = new Array();
    var a_cookie = document.cookie.split(';');
    for(var i=0; i<a_cookie.length; i++)
      {
      var reg = /\s*([^\s\n]+)\s*=([^\s\n]*)\s*/i;
      var p = reg.exec(a_cookie[i]);

      if(p && p.length)
        nex_get_cookie.cookie_data[p[1]] = unescape(p[2]);
      }
    }

  // find the requested cookie value
  var a_cookie = nex_get_cookie.cookie_data;
  if(a_cookie && a_cookie[name]!==null)
    return a_cookie[name];
    
  return false;
  }

nex_browser.prototype.get_cookie = nex_get_cookie;



/**
 * Write a cookie value to the client
 *
 * @param {String} name   Cookie name
 * @param {String} value  Cookie value
 * @param {String} path   Cookie path
 * @param {String} domain Cookie domain
 * @param {String} expiration Cookie lifetime (eg. 20m, 2h, 5d)
 */
function nex_set_cookie(name, value, path, domain, expiration)
  {
  var exp;
  if (expiration && String(expiration).match(/^([0-9]+)\s*([a-z]?)/i))  // cookie expipres in nn (days is default unit)
    {
    expiration = parseInt(RegExp.$1);
    var unit = String(RegExp.$2).toLowerCase();
    var f = unit=='s' ? 1000 : (unit=='m' ? 60000 : (unit=='h' ? 3600000 : 86400000));

    exp = new Date();
    exp.setTime(exp.getTime() + expiration*f);
    }

  var c = name+'='+escape(value) + (exp ? '; expires='+exp.toGMTString() : '') + (path ? '; path='+path : '') + (domain ? '; domain='+domain : '');
  document.cookie = c;

  // update 'cache' of nex_get_cookie()
  if(window.nex_get_cookie && nex_get_cookie.cookie_data)
    nex_get_cookie.cookie_data[name] = value;
  }

nex_browser.prototype.set_cookie = nex_set_cookie;


/**
 * Delete a named cookie value.
 * Achieved by seting expiration date to 01.01.1970
 *
 * @param {String} name   Cookie name
 * @param {String} path   Cookie path
 * @param {String} domain Cookie domain
 */
function nex_delete_cookie(name, path, domain)
  {
  var value = nex_get_cookie(name);
  if (!value) return;

  var c = name+'=' + (path ? '; path='+path : '') + (domain ? '; domain='+domain : '') + '; expires=Thu, 01-Jan-70 00:00:01 GMT';
  document.cookie = c;

  // update 'cache' of nex_get_cookie()
  if(window.nex_get_cookie && nex_get_cookie.cookie_data)
    nex_get_cookie.cookie_data[name] = false;
  }

nex_browser.prototype.del_cookie = nex_delete_cookie;



/**
 * Tell sessionizer to update DOM
 *
 * @param {String} mode 'form' if form element was added
 */
function nex_set_dom_update(mode)
  {  
  if (window.nex_player || window.nex_recorder)
    window.sessionizer_rebuild_dom=true;
  
  if(mode == 'form' && window.nex_recorder)
    window.nex_recorder.extend_form_elements();
  }


/**
 * Getter for event object (sessionizer proof)
 *
 * @param {Object} e Local event object
 * @return Event object
 * @type   Object
 */
function nex_get_event(e)
  {  
  if(!e)
    e = (window.nex_player) ? nex_player.event : window.event;
  
  return e;
  }


/**
 * Get any type of HTML/DOM objects by id/name
 *
 * @param {String} id ID or name of object to find
 * @param {Object} d  Root node to search in (default is document)
 * @return DOM node or false if not found
 * @type   Mixed
 */
function nex_get_object(id, d)
  {
  var n, f, obj;
  if(!d) d = document;

  if(!obj && d.getElementById)
    obj = d.getElementById(id);

  if(d.getElementsByName)
    {
    var obj_arr = d.getElementsByName(id);
    if(obj_arr.length && obj_arr.length==1)
      obj = obj_arr[0];
    }

  if(!obj && d.all)
    obj = d.all[id];

  if(!obj && d.images.length)
    obj = d.images[id];

  if(!obj && d.forms.length)
    for(f=0; f<d.forms.length; f++)
      if(d.forms[f].name == id) obj = d.forms[f];
      else if(d.forms[f].elements[id]) obj = d.forms[f].elements[id];

  if(!obj && d.layers)
    {
    if(d.layers[id]) obj = d.layers[id];
    for(n=0; !obj && n<d.layers.length; n++)
      obj = nex_get_object(id, d.layers[n].document);
    }

  return obj;
  }


/**
 * Return the absolute position of an object within the document
 *
 * @param {Mixed} obj Node reference or object name as String
 * @param {Boolean} absolute Ignore scroll offsets
 * @return Hash array with x/y coordinates
 * @type   Object
 */
function nex_get_object_pos(obj, absolute)
  {
  if(typeof(obj)=='string')
    obj = nex_get_object(obj);

  if(!obj) return {x:0, y:0};

  var iX = (bw.layers) ? obj.x : obj.offsetLeft;
  var iY = (bw.layers) ? obj.y : obj.offsetTop;

  if(bw.ie || bw.mz)
    {
    var elm = obj.offsetParent;
    while(elm && elm!=null)
      {
      iX += elm.offsetLeft;
      iY += elm.offsetTop;

      if (elm.nodeName=='BODY')
        absolute = true;

      if (!absolute && elm.scrollLeft)
        iX -= elm.scrollLeft;
      if (!absolute && elm.scrollTop)
        iY -= elm.scrollTop;

      elm = elm.offsetParent;
      }
    }

  if(bw.mac && bw.ie5) iX += Number(document.body.leftMargin);
  if(bw.mac && bw.ie5) iY += Number(document.body.topMargin);

  return {x:iX, y:iY};
  }


/**
 * Find a value in a specific array and returns the index
 *
 * @param {String}  needle   Needle to find in array
 * @param {Object}  haystack Array to search in
 * @param {Boolean} nocase   Ignore case (false by default)
 * @param {String}  key      Compare a specific key in the hash array
 * @return The element's index in the array, -1 if not found
 * @type Int
 */
function find_in_array()
  {
  var args = find_in_array.arguments;
  if(!args.length) return -1;

  var haystack = typeof(args[0])=='object' ? args[0] : args.length>1 && typeof(args[1])=='object' ? args[1] : new Array();
  var needle   = typeof(args[0])!='object' ? args[0] : args.length>1 && typeof(args[1])!='object' ? args[1] : '';
  var nocase   = (args.length>=3 && args[2]) ? args[2] : false;
  var key      = args.length==4 ? args[3] : false;

  if(!haystack.length)
    return -1;
  
  if(key)
    {
    for(var i=0; i<haystack.length; i++)
      {
      if(nocase && haystack[i][key].toLowerCase()==needle.toLowerCase())
       return i;
      else if(haystack[i][key]==needle)
       return i;
      }
    }
  else
    {
    for(var i=0; i<haystack.length; i++)
      {
      if(nocase && haystack[i].toLowerCase()==needle.toLowerCase())
        return i;
      else if(haystack[i]==needle)
        return i;
      }
    }
  
  return -1;
  }


/**
 * Convert the URL query string into an array
 *
 * @param {String} loc URL to parse (optional)
 * @return Hash array with parameters or false if no parameters found
 * @type Mixed
 */
function read_querystring(loc)
  {
  var a_out = new Object();
  var s_loc = loc ? loc : String(location.href);

  // querystring was already read
  if(read_querystring.a_param && !loc)
    return read_querystring.a_param;

  else if(s_loc.indexOf('?')>0)  // window.location.search (workarround for IE6 bug)
    {
    var p;
    var s_query = s_loc.substr(s_loc.indexOf('?')+1);  // String(location.search).substr(1);
    var a_query = s_query ? s_query.split('&') : new Array();
    if(!a_query.length) return false;

    for(var i=0; i<a_query.length; i++)
      {
      if(!a_query[i] || String(a_query[i]).indexOf('=')<1)
        continue;

      p = a_query[i].split('=');
      a_out[p[0]] = p[1].replace(/\+/g, ' ');
      }

    // set static var
    if(!loc) read_querystring.a_param = a_out;

    return a_out;
    }

  return false;
  }


/**
 * Return the value to (a) from the query string
 *
 * @param {String} a   Query parameter to read
 * @param {String} loc URL to search in (optional)
 * @return Parameter value or false if not found
 * @type Mixed
 */
function get_query_param(a, loc)
  {
  var a_query = read_querystring(loc);

  if(a_query && a_query[a])
    return a_query[a];
    
  return false;
  }



/**
 * Return the absolute position of an image in the document
 *
 * @param {String} imgname Name of the image
 * @return Hash array with x/y coordinates
 * @type   Object
 */
function get_image_pos(imgname)
  {
  var img = document.images[imgname];
  if(!img) img = nex_get_object(imgname);
  return nex_get_object_pos(img);

/* now handled by nex_get_object_pos()

  var iX = (bw.layers) ? img.x : img.offsetLeft;
  var iY = (bw.layers) ? img.y : img.offsetTop;

  if(bw.ie || bw.mz)
    {
    var elm = img.offsetParent;
    while(elm && elm!=null)
      {
      iX += elm.offsetLeft;
      iY += elm.offsetTop;
      elm = elm.offsetParent;
      }
    }

  // if(bw.mac && bw.ie5) iX += document.body.leftMargin;
  // if(bw.mac && bw.ie5) iY += document.body.topMargin;

  return {x:iX, y:iY};
*/
  }


/**
 * Return the current mouse position in an array
 *
 * @param {Object} e Event object
 * @return Hash array with x/y coordinates
 * @type   Object
 */
function get_mouse_pos(e)
  {
  e = nex_get_event(e);

  var mX = (e.pageX) ? e.pageX : e.clientX;
  var mY = (e.pageY) ? e.pageY : e.clientY;

  if(document.body && document.all)
    {
    mX += document.body.scrollLeft;
    mY += document.body.scrollTop;
    }

  return { x:mX, y:mY };
  }

  
/**
 * Return the size of the browser window
 *
 * @return Hash array with width/height
 * @type   Object
 */
function get_window_size()
  {
  var w = h = 0;

  if(window.innerWidth)
    {
    w = parseInt(window.innerWidth);
    h = parseInt(window.innerHeight);
    }
  else if(document.body && document.body.clientHeight)
    {
    w = parseInt(document.body.clientWidth);
    h = parseInt(document.body.clientHeight);
    }
  else if(document.documentElement && document.documentElement.clientHeight)
    {
    w = parseInt(document.documentElement.clientWidth);
    h = parseInt(document.documentElement.clientHeight);
    }

  return { width:w, height:h };
  }


/**
 * Return the currently applied value of a css property
 *
 * @param {Object} html_element  Node reference
 * @param {String} css_property  Property name to read in Javascript notation (eg. 'textAlign')
 * @param {String} mozilla_equivalent  Equivalent property name in CSS notation (eg. 'text-align')
 * @return CSS property value
 * @type String
 */
function get_elements_computed_style(html_element, css_property, mozilla_equivalent)
  {
  if (arguments.length==2)
    mozilla_equivalent = css_property;

  var el = html_element;
  if (typeof(html_element)=='string')
    el = nex_get_object(html_element);

  if (el && el.currentStyle)
    return el.currentStyle[css_property];
  else if (el && document.defaultView && document.defaultView.getComputedStyle)
    return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozilla_equivalent);
  else
    return false;
  }


/**
 * Check if ALT-key is pressed on event
 *
 * @param {Object} e Event object
 * @return True if Alt-modifier is set, false if not
 * @type Boolean
 */
function check_altkey(e)
  {
  e = nex_get_event(e);

  if(bw.linux && bw.ns4 && e.modifiers)
    return true;
  else if(bw.opera && e.ctrlKey)
    return true;
  else if((bw.ns4 && e.modifiers & Event.ALT_MASK) || (e && e.altKey))
    return true;
  else
    return false;
  }


/**
 *  Check if Shift-key is pressed on event
 *
 * @param {Object} e Event object
 * @return True if Shift-modifier is set, false if not
 * @type Boolean
 */
function check_shiftkey(e)
  {
  e = nex_get_event(e);

  if(bw.linux && bw.ns4 && e.modifiers)
    return true;
  else if((bw.ns4 && e.modifiers & Event.SHIFT_MASK) || (e && e.shiftKey))
    return true;
  else
    return false;
  }




/**
 * Check if Control-key is pressed on event
 *
 * @param {Object} e Event object
 * @return True if Ctrl-modifier is set, false if not
 * @type Boolean
 */
function check_ctrlkey(e)
  {
  e = nex_get_event(e);

  if(bw.linux && bw.ns4 && e.modifiers)
    return true;
  else if((bw.ns4 && e.modifiers & Event.CTRL_MASK) || (e && e.ctrlKey))
    return true;
  else
    return false;
  }


/**
 * Init the workaround for onresize handler in mozilla ver. 1.5
 *
 */
function nex_size_handler_fix()
  {
  nex_size_handler_fix.width=window.innerWidth;
  nex_size_handler_fix.height=window.innerHeight;
  }


/**
 * Check if just kicked onresize event is a valid resize event
 * just add this in front of your function you call in the onresize event
 * window.onresize=funcion() { if(nex_resize_is_needed()) { do_somthing(); }; }
 *
 * @return True if resizing is needed
 * @type Booelan
 */
function nex_resize_is_needed()
  {
  var status=false;
  var height=0;
  var width=0;
  
  if(bw.mz && bw.vendver=='1.8' && window.nex_size_handler_fix)
    {
    var width=window.innerWidth;
    var height=window.innerHeight;
    
    if(!window.nex_size_handler_fix.width)
      nex_size_handler_fix();
    
    if(nex_size_handler_fix.width>width+1||
       nex_size_handler_fix.height>height+1||
       nex_size_handler_fix.width<width-1||
       nex_size_handler_fix.height<height-1)
      {
      nex_size_handler_fix.width=width;
      nex_size_handler_fix.height=height;
      status=true;
      }
    }
  else
    status=true;
  
  return status;
  }


/**
 * PHP equivalent urlencoding
 *
 * @param {String} value String to encode
 * @return Encoded string
 * @type   String
 */
function urlencode(value)
  {
  return escape(value).replace(/\//g, '%2F').replace(/\*/g, '%2A').replace(/\+/g, '%2B').replace(/%20/g, '+');
  };


/**
 * PHP equivalent urldecoding
 *
 * @param {String} value String to decode
 * @return Decoded string
 * @type   String
 */
function urldecode(value)
  {
  return unescape(value.replace(/\+/g, ' ').replace(/%2B/g, '+'));
  }



// initialisation ...
var loaded = false;
var bw = new nex_browser();


// mapping for old function calls
window.get_param = get_query_param;
window.read_query = read_querystring;

// dummy function for alltext script which is usually included at page bottom
window.alttext = function(){};
