//#######################################################
//############  Firebugx-Script          ################
//#######################################################

function writeToConsole(level, args) {
  if (mbDebug) {
    if (window.console) if (console[level]) console[level].apply(this, args);
  }
}

function createArgumentsArray(args) {
  var arr = [];
  for (var i=0; i<args.length;i++) {
    arr[i]=args[i];
  }
  return arr;
};

function log() {
  	if (mbDebug) {
		args = createArgumentsArray(arguments);
		args.unshift('LOG: ');
		writeToConsole("log", args, true);
	}
}

function info() {
	if (mbDebug) {
		args = createArgumentsArray(arguments);
		args.unshift('INFO: ');
		writeToConsole("info", args);
	}
}

function debug() {
	if (mbDebug) {
		args = createArgumentsArray(arguments);
		args.unshift('DEBUG: ');
		writeToConsole("debug", args);
	}
}

function error() {
	if(mbDebug)	{
		args = createArgumentsArray(arguments);
	  	args.unshift('ERROR: ');
  		writeToConsole("error", args);	
	}
}

function warn() {
	if (mbDebug) {
		args = createArgumentsArray(arguments);
		args.unshift('WARNING: ');
		writeToConsole("warn", args);
	}
}

function trace() {
  writeToConsole('trace');
}

//disable all fades
jQuery.fn._fadeIn = jQuery.fn.fadeIn;
jQuery.fn._fadeOut = jQuery.fn.fadeOut;

jQuery.fn.fadeIn = function(speed, cb) {
  this.show();
  if (cb) cb.call(this);
};
jQuery.fn.fadeOut = function(speed, cb) {
  this.hide();
  if (cb) cb.call(this);
};

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

function composeElementId(element) {
  var id = $(element).attr("id");
  var cls = $(element).attr("class");
  var name = element.nodeName.toLowerCase();
  
  if (cls) cls.replace(" ", ".");
  
  if (id && cls) return name+"#"+id+"."+cls;
  else if (id) return name+"#"+id;
  else if (cls) return name+"."+cls;
  else return name; 
  
};


// batchloader -------------------------------------------------------------------

LovelyBatchLoader = function() {
  this.batch = [];
  this.loadedItems_ctr = 0;
  this.blCallback;
};

LovelyBatchLoader.prototype.addItem = function (je, url, cb) {
  this.batch.push({je:je, url:url, callback:cb});
};

LovelyBatchLoader.prototype.clearItems = function() {
  this.batch = [];
};

LovelyBatchLoader.prototype.load = function(cb) {
  
  var self=this;
  this.blCallback = cb;
  
  for (var i=0; i<this.batch.length; i++) {
    var item = this.batch[i];
    item.je.load(item.url, function() {
          item.callback.call(this);
          self.onItemLoaded(this);
        });
  }
};

LovelyBatchLoader.prototype.onItemLoaded = function(item) {
  this.loadedItems_ctr++;
  if (this.batch.length == this.loadedItems_ctr) this.onBatchLoaded();
};

LovelyBatchLoader.prototype.onBatchLoaded = function() {
  if (this.blCallback) this.blCallback.call(this);
};


// LovelyJsValidator Classes -------------------------------------------------------------------

LovelyFieldValidator = function() {
  this.field; //the field to validate
  this.serviceurl; //the url where to send the values
  this.type; //single or multiple-field validation
  this.form; //the form containing the field (important for multiple validation)
  this.errorhandler; //the elmeent receiving the error class;
  this.msghandler; //the element displaying the errormessage after validation
  this.event; //the event activating the validation, normally 'blur'
  this.additionalfields; //optionally needed fields for multiple validation
  
  this.errorClass; //class set on the errorhandler if a validationerror occurs
  this.okClass; //class set on the errorhandler the validation succeeds
  
  this.groupvalidator; //pointer to a possible groupvalidator
  this.groupvalidation; //indicates wether a groupvalidation is done

};

LovelyFieldValidator.prototype.init = function(init) {
  this.fieldname = init.field.attr("name");
  this.field = init.field;
  this.serviceurl = init.serviceurl;
  this.type = init.type;
  this.form = init.form;
  this.errorhandler = init.errorhandler;
  this.msghandler = init.msghandler;
  this.event = init.event;
  this.additionalfields = init.additionalfields;
  
  this.errorClass = init.errorClass;
  this.okClass = init.okClass;
  
  var self=this;
  this.field.bind(this.event, function() {
    self.validate();
  });
};

LovelyFieldValidator.prototype.validate = function(groupvalidation, groupvalidator) {
  
  if (groupvalidation) {
    this.groupvalidation = true;
    this.groupvalidator = groupvalidator;
  }
  
  var self=this;
  var fieldname=this.field.attr("name");
  
  //if the value equals the title we ignore the value
  //the title just is the caption
  var val = this.field.val() != this.field.attr("title") ? this.field.val() : "";
  
  if (val) {
    if (val.length > 50) val = val.substr(0, 50);
  }
  
  var vals = fieldname+"="+encodeURIComponent(val);
  
  if (this.type == "multiple") {
    if (this.additionalfields) vals += this.serializeAdditionalFields();
    else vals = this.form.formSerialize();
  }
  
  $.getJSON(
    this.serviceurl+"?field="+fieldname+"&"+vals,
    function(response) {
      self.handleValidation(response.field, response.success, response.message);
    });
};

LovelyFieldValidator.prototype.serializeAdditionalFields = function() {
  
  var fields = this.additionalfields;
  var ret = "";
  
  for (var i=0;i<fields.length;i++) {
    ret += fields[i].attr("name") + "=" + encodeURIComponent(fields[i].val());
    if (i < fields.length-1) ret += "&";
  }
  return "&" + ret;
};

LovelyFieldValidator.prototype.handleValidation = function(fieldid, success, message) {
  
  if (success==true) {
    if (this.errorClass) this.errorhandler.removeClass(this.errorClass);
    if (this.okClass) this.errorhandler.addClass(this.okClass);
  } else {
    if (this.errorClass) this.errorhandler.addClass(this.errorClass);
    if (this.okClass) this.errorhandler.removeClass(this.okClass);
  }
  
  if (this.groupvalidation) {
    this.groupvalidator.handleFieldValidation(this, success);
  }
  
  //show the error message in the info-span of the errorhandler
  this.msghandler.html(message);
};


LovelyGroupValidator = function() {
  this.queue = {};
  this.validators;
};
LovelyGroupValidator.prototype.init = function(validators, stepnr) {

  this.queue = {};
  this.validators = validators;
  this.stepnr = stepnr;

  for (var i=0; i < this.validators.length; i++) {

    this.queue[this.validators[i].fieldname] = {
      validated : false,
      success : false,
      validator : this.validators[i]
    };
  }
};

LovelyGroupValidator.prototype.validate = function (cbobj, cbfunc){
  
  this.cbObj = cbobj;
  this.cbFunc = cbfunc;
  
  for (var p in this.queue) {
    this.queue[p].validator.validate(true, this);
  }
};

LovelyGroupValidator.prototype.handleFieldValidation = function(validator, success) {
  
  for (var p in this.queue) {
    if (this.queue[p].validator.fieldname==validator.fieldname) {
      this.queue[p].success = success;
      this.queue[p].validated = true;
    }
  }
  
  if (this.allValidated()) {
    this.cbObj[this.cbFunc](this.stepnr, this.allSuccessful());
  }
};

LovelyGroupValidator.prototype.allValidated = function (){
  for (var p in this.queue) {
    if (this.queue[p].validated==false) return false;
  }
  return true;
};

LovelyGroupValidator.prototype.allSuccessful = function (){
  for (var p in this.queue) {
    if (this.queue[p].success==false) return false;
  }
  return true;
};


// LovelyFadeTransition Class -------------------------------------------------------------------

TransitionManager = function() {
  this.queueByTarget = {};
};

TransitionManager.prototype.start = function(transition) {
  transition.start();
  return;
};

LovelyFadeTransition = function(init) {
  this.before = init.before;
  this.between = init.between;
  this.after = init.after;
  this.target = init.target;
  this.speed = init.speed || "fast";
  this.url = init.url;
};

LovelyFadeTransition.prototype.setUrl = function(url) {
  this.url = url;
};

LovelyFadeTransition.prototype.start = function(url) {
  
  url = url || this.url;
  
  if (!url) error("no url for fadetransition set: ", this, url);
  
  this.url = url;
  this.fadedOut=false;
  this.loaded=false;
  
  if (this.before) this.before.call(this.target);

  this.load();
  this.fadeOut();
  this.checkStatus();
};

LovelyFadeTransition.prototype.load = function() {
  var self=this;
  $.get(this.url, function(response){
    self.response=response;
    self.loaded=true;
//    if (self.fadedOut) self.onReady();
  });
};

LovelyFadeTransition.prototype.fadeOut = function() {
  var self=this;
  this.target.fadeOut(this.speed, function() {
    self.fadedOut=true;
//    if (self.loaded) self.onReady();
  });
};

LovelyFadeTransition.prototype.fadeIn = function() {
  var self=this;
  this.target.fadeIn(this.speed, function() {
    self.onFinished();
  });
};

LovelyFadeTransition.prototype.checkStatus = function() {
  var self=this;
  clearInterval(this.checkInt);
  this.checkint = setInterval(function(){
    if (self.fadedOut && self.loaded) {
      self.onReady();
    }
  }, 200);
};

LovelyFadeTransition.prototype.onFinished = function() {
  if (this.after) this.after.call(this.target);
};

LovelyFadeTransition.prototype.onReady = function() {
  clearInterval(this.checkint);
  this.target.empty().append(this.response);
  this.fadeIn();
  
  if (this.between) this.between.call(this.target);
};

LovelyFadeTransition.prototype.onFinished = function() {
  if (this.after) this.after.call(this.target);
};

// cache client -------------------------------------------------------------------

function CacheEntry(){
    this.data = null;
    this.params = {};
    this.expire_date = null;
    this.url = null;
    this.key = null; 
    this.callbacks = [];
    this.ready = false;
};

CacheEntry.prototype.addCallback = function(cb){
    this.callbacks.push(cb);
    if (this.ready){
        log("result ready. immediately call callback");
        this.callback();
    };
};

CacheEntry.prototype.callback = function(){
    while(this.callbacks.length>0){
        var cb = this.callbacks.pop();
        cb(this.data);
    };
};

CacheEntry.prototype.load = function(){
    var ptr = this;
    $.get(this.url, this.params, function(data){
        ptr.onLoad(data);
    });
};

CacheEntry.prototype.onLoad = function(data){
    this.data = data;
    this.ready = true;
    this.callback();
};

CacheEntry.prototype.isExpired = function(){
    return (this.expire_date < (new Date()));
};

CacheEntry.prototype.matchExpresion = function(expr){
    return (this.url.search(expr) != -1); 
};

CacheEntry.prototype.setExpiration = function(expiration){
    // @param expiration: seconds from now
    this.expire_date = new Date();
    this.expire_date = this.expire_date.setTime(this.expire_date.getTime() + 1000 * expiration);
};

    
function CacheManager(){
    this.cache = [];
    this.max_entries = null;
    
    log("CacheManager initialized");
};

CacheManager.prototype.ajaxGet = function(url,
                                          settings,
                                          params,
                                          callback){

    
    var key = url;
    if (url.indexOf("?") == -1) url+="?";
    for (p in params){
        key += p+"="+params[p] + "&";
    };
    
    for (var i=0; i<this.cache.length; i++){
        if (this.cache[i].key == key){
            log("client-cache hit: "+url);
            this.cache[i].addCallback(callback); 
            this.sortCache(this.cache[i],i);
            return;
        };
    };

    log("client-cache miss: "+url);
   
    var entry = new CacheEntry();
    entry.addCallback(callback);
    entry.url = url;
    entry.key = key;
    entry.setExpiration(settings.max_age);
    entry.params = params;
    entry.load();
    this.cache.push(entry);
    log("CacheManager added "+entry.url+" for "+settings.max_age+" seconds");
};

CacheManager.prototype.purgeExpiredEntries = function(){
    var amount = this.cache.length;
    for(var i=this.cache.length-1; i>=0; i--){
        if (this.cache[i].isExpired() == true){
            this.cache.splice(i, 1);
        };
    };
    if (amount!=this.cache.length){
        log("expired entries purged: "+(amount-this.cache.length)+" from "+amount);
    };
};

CacheManager.prototype.sortCache = function(entry,position){
    var amount = this.cache.length;

    this.cache.splice(position,1);
    this.cache.push(entry);
    
    if (this.max_entries) {
      if(amount == this.max_entries){
          info("Removing cache entry (caused by max_entries): ", this.cache[0]);
          this.cache.shift();
      };
    };
};

CacheManager.prototype.purge = function(expr){
    log("purging "+expr);
    var amount = this.cache.length;
    for(var i=this.cache.length-1; i>=0; i--){
        if (this.cache[i].matchExpresion(expr) == true){
            this.cache.splice(i, 1);
        };
    };
    log("force purged entries: "+(amount-this.cache.length)+" from "+amount);
};


LCM = new CacheManager();
LCM.max_entries=500;
setInterval("LCM.purgeExpiredEntries()", 10000);

/* ToolTipps ################################################################ */

function ToolTipManager(){
    this.wait_time = null;
    this.z_index = 10000;
    this.offset_x = null;
    this.offset_y = null;
    this.timeouts=[];

    log("starting tooltip");
};

ToolTipManager.prototype.createTip = function(obj,id,text){
    var self = this;
    var div = '<div class="'+ this.css_class +'" id="'+id+'">';
    div= div+'<div class="tb"></div><div class="text">'+text+'</div>';
    div = div+ '<div class="bb"></div></div>'; 
    var identify = "div#"+id;

    if($(identify).length == 0){
            $('body').append(div);
    };
};

ToolTipManager.prototype.showTip = function(obj,pos){
    var self = this;
    
    self.purgeTimeout();
    self.setStyle(obj,pos);
    self.setWait(obj);
};

ToolTipManager.prototype.hideTip = function(obj){
    obj.hide();
};
ToolTipManager.prototype.purgeTimeout = function(){
    var self = this;
    var i = 0;    
    for(i;i<=self.timeouts.length;i++){
        clearTimeout(self.timeouts[i]);
    };
    self.timeouts=[];
};

ToolTipManager.prototype.setWait = function(obj){
    var self = this;
    var timeout_id = setTimeout(function(){
            obj.show();
            }, self.wait_time);
    self.timeouts.push(timeout_id);
};

ToolTipManager.prototype.setStyle = function(obj,pos){
    var self = this;
    var width = parseInt(obj.css('width'));
    var docX = $(document).width();
    var docY = $(document).height();
    var posTop = pos.pageY + self.offset_y;
    var posLeft = pos.pageX + self.offset_x;
    
    if(posLeft+width > docX){
        posLeft = posLeft - width;
    };

    var newstyle ='top:'+posTop+'px;left:'+posLeft+'px;z-index:'+self.z_index;
    obj.attr('style', newstyle);
};

TTM = new ToolTipManager();
TTM.wait_time = 1000;
TTM.css_class='tooltip';
TTM.offset_x=10;
TTM.offset_y=10;

/*
 * jQuery Form Plugin
 * version: 2.12 (06/07/2008)
 * @requires jQuery v1.2.2 or later
 *
 * Examples and documentation at: http://malsup.com/jquery/form/
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id$
 */
(function($) {

/*
    Usage Note:  
    -----------
    Do not use both ajaxSubmit and ajaxForm on the same form.  These
    functions are intended to be exclusive.  Use ajaxSubmit if you want
    to bind your own submit handler to the form.  For example,

    $(document).ready(function() {
        $('#myForm').bind('submit', function() {
            $(this).ajaxSubmit({
                target: '#output'
            });
            return false; // <-- important!
        });
    });

    Use ajaxForm when you want the plugin to manage all the event binding
    for you.  For example,

    $(document).ready(function() {
        $('#myForm').ajaxForm({
            target: '#output'
        });
    });
        
    When using ajaxForm, the ajaxSubmit function will be invoked for you
    at the appropriate time.  
*/

/**
 * ajaxSubmit() provides a mechanism for immediately submitting 
 * an HTML form using AJAX.
 */
$.fn.ajaxSubmit = function(options) {
    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
    if (!this.length) {
        log('ajaxSubmit: skipping submit process - no element selected');
        return this;
    }

    if (typeof options == 'function')
        options = { success: options };

    options = $.extend({
        url:  this.attr('action') || window.location.toString(),
        type: this.attr('method') || 'GET'
    }, options || {});

    // hook for manipulating the form data before it is extracted;
    // convenient for use with rich editors like tinyMCE or FCKEditor
    var veto = {};
    this.trigger('form-pre-serialize', [this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
        return this;
   }

    var a = this.formToArray(options.semantic);
    if (options.data) {
        options.extraData = options.data;
        for (var n in options.data)
            a.push( { name: n, value: options.data[n] } );
    }

    // give pre-submit callback an opportunity to abort the submit
    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
        log('ajaxSubmit: submit aborted via beforeSubmit callback');
        return this;
    }    

    // fire vetoable 'validate' event
    this.trigger('form-submit-validate', [a, this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
        return this;
    }    

    var q = $.param(a);

    if (options.type.toUpperCase() == 'GET') {
        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
        options.data = null;  // data is null for 'get'
    }
    else
        options.data = q; // data is the query string for 'post'

    var $form = this, callbacks = [];
    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });

    // perform a load on the target only if dataType is not provided
    if (!options.dataType && options.target) {
        var oldSuccess = options.success || function(){};
        callbacks.push(function(data) {
            $(options.target).html(data).each(oldSuccess, arguments);
        });
    }
    else if (options.success)
        callbacks.push(options.success);

    options.success = function(data, status) {
        for (var i=0, max=callbacks.length; i < max; i++)
            callbacks[i](data, status, $form);
    };

    // are there files to upload?
    var files = $('input:file', this).fieldValue();
    var found = false;
    for (var j=0; j < files.length; j++)
        if (files[j])
            found = true;

    // options.iframe allows user to force iframe mode
   if (options.iframe || found) { 
       // hack to fix Safari hang (thanks to Tim Molendijk for this)
       // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
       if ($.browser.safari && options.closeKeepAlive)
           $.get(options.closeKeepAlive, fileUpload);
       else
           fileUpload();
       }
   else
       $.ajax(options);

    // fire 'notify' event
    this.trigger('form-submit-notify', [this, options]);
    return this;


    // private function for handling file uploads (hat tip to YAHOO!)
    function fileUpload() {
        var form = $form[0];
        
        if ($(':input[@name=submit]', form).length) {
            alert('Error: Form elements must not be named "submit".');
            return;
        }
        
        var opts = $.extend({}, $.ajaxSettings, options);

        var id = 'jqFormIO' + (new Date().getTime());
        var $io = $('<iframe id="' + id + '" name="' + id + '" />');
        var io = $io[0];

        if ($.browser.msie || $.browser.opera) 
            io.src = 'javascript:false;document.write("");';
        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });

        var xhr = { // mock object
            responseText: null,
            responseXML: null,
            status: 0,
            statusText: 'n/a',
            getAllResponseHeaders: function() {},
            getResponseHeader: function() {},
            setRequestHeader: function() {}
        };

        var g = opts.global;
        // trigger ajax global events so that activity/block indicators work like normal
        if (g && ! $.active++) $.event.trigger("ajaxStart");
        if (g) $.event.trigger("ajaxSend", [xhr, opts]);

        var cbInvoked = 0;
        var timedOut = 0;

        // add submitting element to data if we know it
        var sub = form.clk;
        if (sub) {
            var n = sub.name;
            if (n && !sub.disabled) {
                options.extraData = options.extraData || {};
                options.extraData[n] = sub.value;
                if (sub.type == "image") {
                    options.extraData[name+'.x'] = form.clk_x;
                    options.extraData[name+'.y'] = form.clk_y;
                }
            }
        }
        
        // take a breath so that pending repaints get some cpu time before the upload starts
        setTimeout(function() {
            // make sure form attrs are set
            var t = $form.attr('target'), a = $form.attr('action');
            $form.attr({
                target:   id,
                encoding: 'multipart/form-data',
                enctype:  'multipart/form-data',
                method:   'POST',
                action:   opts.url
            });

            // support timout
            if (opts.timeout)
                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);

            // add "extra" data to form if provided in options
            var extraInputs = [];
            try {
                if (options.extraData)
                    for (var n in options.extraData)
                        extraInputs.push(
                            $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
                                .appendTo(form)[0]);
            
                // add iframe to doc and submit the form
                $io.appendTo('body');
                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
                form.submit();
            }
            finally {
                // reset attrs and remove "extra" input elements
                $form.attr('action', a);
                t ? $form.attr('target', t) : $form.removeAttr('target');
                $(extraInputs).remove();
            }
        }, 10);

        function cb() {
            if (cbInvoked++) return;
            
            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);

            var operaHack = 0;
            var ok = true;
            try {
                if (timedOut) throw 'timeout';
                // extract the server response from the iframe
                var data, doc;

                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
                
                if (doc.body == null && !operaHack && $.browser.opera) {
                    // In Opera 9.2.x the iframe DOM is not always traversable when
                    // the onload callback fires so we give Opera 100ms to right itself
                    operaHack = 1;
                    cbInvoked--;
                    setTimeout(cb, 100);
                    return;
                }
                
                xhr.responseText = doc.body ? doc.body.innerHTML : null;
                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
                xhr.getResponseHeader = function(header){
                    var headers = {'content-type': opts.dataType};
                    return headers[header];
                };

                if (opts.dataType == 'json' || opts.dataType == 'script') {
                    var ta = doc.getElementsByTagName('textarea')[0];
                    xhr.responseText = ta ? ta.value : xhr.responseText;
                }
                else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
                    xhr.responseXML = toXml(xhr.responseText);
                }
                data = $.httpData(xhr, opts.dataType);
            }
            catch(e){
                ok = false;
                $.handleError(opts, xhr, 'error', e);
            }

            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
            if (ok) {
                opts.success(data, 'success');
                if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
            }
            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
            if (g && ! --$.active) $.event.trigger("ajaxStop");
            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');

            // clean up
            setTimeout(function() {
                $io.remove();
                xhr.responseXML = null;
            }, 100);
        };

        function toXml(s, doc) {
            if (window.ActiveXObject) {
                doc = new ActiveXObject('Microsoft.XMLDOM');
                doc.async = 'false';
                doc.loadXML(s);
            }
            else
                doc = (new DOMParser()).parseFromString(s, 'text/xml');
            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
        };
    };
};

/**
 * ajaxForm() provides a mechanism for fully automating form submission.
 *
 * The advantages of using this method instead of ajaxSubmit() are:
 *
 * 1: This method will include coordinates for <input type="image" /> elements (if the element
 *    is used to submit the form).
 * 2. This method will include the submit element's name/value data (for the element that was
 *    used to submit the form).
 * 3. This method binds the submit() method to the form for you.
 *
 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
 * passes the options argument along after properly binding events for submit elements and
 * the form itself.
 */ 
$.fn.ajaxForm = function(options) {
    return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
        $(this).ajaxSubmit(options);
        return false;
    }).each(function() {
        // store options in hash
        $(":submit,input:image", this).bind('click.form-plugin',function(e) {
            var $form = this.form;
            $form.clk = this;
            if (this.type == 'image') {
                if (e.offsetX != undefined) {
                    $form.clk_x = e.offsetX;
                    $form.clk_y = e.offsetY;
                } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
                    var offset = $(this).offset();
                    $form.clk_x = e.pageX - offset.left;
                    $form.clk_y = e.pageY - offset.top;
                } else {
                    $form.clk_x = e.pageX - this.offsetLeft;
                    $form.clk_y = e.pageY - this.offsetTop;
                }
            }
            // clear form vars
            setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
        });
    });
};

// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
    this.unbind('submit.form-plugin');
    return this.each(function() {
        $(":submit,input:image", this).unbind('click.form-plugin');
    });

};

/**
 * formToArray() gathers form element data into an array of objects that can
 * be passed to any of the following ajax functions: $.get, $.post, or load.
 * Each object in the array has both a 'name' and 'value' property.  An example of
 * an array for a simple login form might be:
 *
 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 *
 * It is this array that is passed to pre-submit callback functions provided to the
 * ajaxSubmit() and ajaxForm() methods.
 */
$.fn.formToArray = function(semantic) {
    var a = [];
    if (this.length == 0) return a;

    var form = this[0];
    var els = semantic ? form.getElementsByTagName('*') : form.elements;
    if (!els) return a;
    for(var i=0, max=els.length; i < max; i++) {
        var el = els[i];
        var n = el.name;
        if (!n) continue;

        if (semantic && form.clk && el.type == "image") {
            // handle image inputs on the fly when semantic == true
            if(!el.disabled && form.clk == el)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
            continue;
        }

        var v = $.fieldValue(el, true);
        if (v && v.constructor == Array) {
            for(var j=0, jmax=v.length; j < jmax; j++)
                a.push({name: n, value: v[j]});
        }
        else if (v !== null && typeof v != 'undefined')
            a.push({name: n, value: v});
    }

    if (!semantic && form.clk) {
        // input type=='image' are not found in elements array! handle them here
        var inputs = form.getElementsByTagName("input");
        for(var i=0, max=inputs.length; i < max; i++) {
            var input = inputs[i];
            var n = input.name;
            if(n && !input.disabled && input.type == "image" && form.clk == input)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
        }
    }
    return a;
};

/**
 * Serializes form data into a 'submittable' string. This method will return a string
 * in the format: name1=value1&amp;name2=value2
 */
$.fn.formSerialize = function(semantic) {
    //hand off to jQuery.param for proper encoding
    return $.param(this.formToArray(semantic));
};

/**
 * Serializes all field elements in the jQuery object into a query string.
 * This method will return a string in the format: name1=value1&amp;name2=value2
 */
$.fn.fieldSerialize = function(successful) {
    var a = [];
    this.each(function() {
        var n = this.name;
        if (!n) return;
        var v = $.fieldValue(this, successful);
        if (v && v.constructor == Array) {
            for (var i=0,max=v.length; i < max; i++)
                a.push({name: n, value: v[i]});
        }
        else if (v !== null && typeof v != 'undefined')
            a.push({name: this.name, value: v});
    });
    //hand off to jQuery.param for proper encoding
    return $.param(a);
};

/**
 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
 *
 *  <form><fieldset>
 *      <input name="A" type="text" />
 *      <input name="A" type="text" />
 *      <input name="B" type="checkbox" value="B1" />
 *      <input name="B" type="checkbox" value="B2"/>
 *      <input name="C" type="radio" value="C1" />
 *      <input name="C" type="radio" value="C2" />
 *  </fieldset></form>
 *
 *  var v = $(':text').fieldValue();
 *  // if no values are entered into the text inputs
 *  v == ['','']
 *  // if values entered into the text inputs are 'foo' and 'bar'
 *  v == ['foo','bar']
 *
 *  var v = $(':checkbox').fieldValue();
 *  // if neither checkbox is checked
 *  v === undefined
 *  // if both checkboxes are checked
 *  v == ['B1', 'B2']
 *
 *  var v = $(':radio').fieldValue();
 *  // if neither radio is checked
 *  v === undefined
 *  // if first radio is checked
 *  v == ['C1']
 *
 * The successful argument controls whether or not the field element must be 'successful'
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.  If this value is false the value(s)
 * for each element is returned.
 *
 * Note: This method *always* returns an array.  If no valid value can be determined the
 *       array will be empty, otherwise it will contain one or more values.
 */
$.fn.fieldValue = function(successful) {
    for (var val=[], i=0, max=this.length; i < max; i++) {
        var el = this[i];
        var v = $.fieldValue(el, successful);
        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
            continue;
        v.constructor == Array ? $.merge(val, v) : val.push(v);
    }
    return val;
};

/**
 * Returns the value of the field element.
 */
$.fieldValue = function(el, successful) {
    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
    if (typeof successful == 'undefined') successful = true;

    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
        (t == 'checkbox' || t == 'radio') && !el.checked ||
        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
        tag == 'select' && el.selectedIndex == -1))
            return null;

    if (tag == 'select') {
        var index = el.selectedIndex;
        if (index < 0) return null;
        var a = [], ops = el.options;
        var one = (t == 'select-one');
        var max = (one ? index+1 : ops.length);
        for(var i=(one ? index : 0); i < max; i++) {
            var op = ops[i];
            if (op.selected) {
                // extra pain for IE...
                var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
                if (one) return v;
                a.push(v);
            }
        }
        return a;
    }
    return el.value;
};

/**
 * Clears the form data.  Takes the following actions on the form's input fields:
 *  - input text fields will have their 'value' property set to the empty string
 *  - select elements will have their 'selectedIndex' property set to -1
 *  - checkbox and radio inputs will have their 'checked' property set to false
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 *  - button elements will *not* be effected
 */
$.fn.clearForm = function() {
    return this.each(function() {
        $('input,select,textarea', this).clearFields();
    });
};

/**
 * Clears the selected form elements.
 */
$.fn.clearFields = $.fn.clearInputs = function() {
    return this.each(function() {
        var t = this.type, tag = this.tagName.toLowerCase();
        if (t == 'text' || t == 'password' || tag == 'textarea')
            this.value = '';
        else if (t == 'checkbox' || t == 'radio')
            this.checked = false;
        else if (tag == 'select')
            this.selectedIndex = -1;
    });
};

/**
 * Resets the form data.  Causes all form elements to be reset to their original value.
 */
$.fn.resetForm = function() {
    return this.each(function() {
        // guard against an input with the name of 'reset'
        // note that IE reports the reset function as an 'object'
        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
            this.reset();
    });
};

/**
 * Enables or disables any matching elements.
 */
$.fn.enable = function(b) { 
    if (b == undefined) b = true;
    return this.each(function() { 
        this.disabled = !b 
    });
};

/**
 * Checks/unchecks any matching checkboxes or radio buttons and
 * selects/deselects and matching option elements.
 */
$.fn.select = function(select) {
    if (select == undefined) select = true;
    return this.each(function() { 
        var t = this.type;
        if (t == 'checkbox' || t == 'radio')
            this.checked = select;
        else if (this.tagName.toLowerCase() == 'option') {
            var $sel = $(this).parent('select');
            if (select && $sel[0] && $sel[0].type == 'select-one') {
                // deselect all other options
                $sel.find('option').select(false);
            }
            this.selected = select;
        }
    });
};

// helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
    if ($.fn.ajaxSubmit.debug && window.console && window.console.log && mbDebug)
        window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
};

})(jQuery);


AJAXNAMESPACE = 'ajax';

var AjaxCommands = {
    init : function(start_node){
        
        if (!start_node) start_node = $("body");
        $(".ajaxCommand", start_node).each(function(i){
            var ptr = AjaxCommands;
            
            var node = $(this);
            var cmd = node.attr("ajax:command");
            
            //get all attributes in the AJAXNAMESPACE and pass them as params
            var params = {};
            for (var i=0;i<this.attributes.length;i++) {
              var attr = this.attributes[i];
              if (attr.name.indexOf(AJAXNAMESPACE+":") == 0) {
                var name = attr.name.split(AJAXNAMESPACE+":")[1];
                params[name] = attr.value;
              }
            }

            if (ptr[cmd]) ptr[cmd](node, params);
            else error("unknown ajax command ", cmd, "for", node);
            if ((node.attr("ajax:multiple")!="1")){
                node.removeClass("ajaxCommand"); // avoid double events
            }
        });
    },

    mainPageContainer : '.ajax_magpagetarget',
    initMagazinePageLink : function(node, params) {
     
      if (node.attr("href")) {
        var url = node.attr("href").replace(".html", ".ajax");
  
        var page = new LovelyAjaxPage();
        page.url = url;
        page.itemId = params.itemid;
        page.target = $(this.mainPageContainer);
  
        var id = LPM.registerAjaxPage(page);
        
        node.attr("ajax:url", url);
        node.attr("href", "JavaScript:LPM.showMagazinePage('"+id+"')");
      
        return page;
      
      } else {
        error('hijackLink: no href for link: ' + node);
      }
    },
    
    hoverItemContainer : '#hover-container',
    initHoverItemLink : function(node, params) {
        if (node.attr("href")) {

            var url = node.attr("href").replace(".html", ".ajax");
            var page = new LovelyAjaxPage();

            page.url = url;
            page.itemId = params.itemid;
            page.target = $(this.hoverItemContainer);
            var id = LPM.registerAjaxPage(page);

            node.attr("id", id);
            node.attr("href", "JavaScript:LPM.showItemPage('"+id+"')");
        } else {
           error('hijackLink: no href for link: ' + node);            
        }
    },
    
    initHood : function(node, params) {
        node.attr("href", "javascript:LPM.gotoHood("+params.lat+","+params.lon+")")
    },
    
    showSubSection : function(node, params) {
      if (node.attr("href")) {
        var url = node.attr("href").replace(".html", ".ajax");
  
        var page = new LovelyAjaxPage();
        page.url = url;
        page.target = $(params.target);
  
        var id = LPM.registerAjaxPage(page);
        
        node.attr("ajax:url", url);
        node.attr("href", "JavaScript:LPM.showSubPage('"+id+"')");
      
      } else {
        error('hijackLink: no href for link: ' + node);
      }
    },
    
    initModeSwitch : function(node, params) {
        //capture the gossip page
        
        var page = this.initMagazinePageLink(node, params)
        LPM.registerModePage(params.mode, page);
        node.attr("href", 'javascript:LPM.toggleMode("'+params.mode+'")');
        
        if (params.startpage=="true") LPM.currentPage = page;
    },

    initHover : function(node, params) {
      if (node.attr("href")) {
        var type = params.hovertype;
        var href = node.attr("href").replace('.html', '.ajax');
        
        if (type=="login") {
          //special case loginform
            node.attr("href", "JavaScript:LPM.login.showForm('"+href+"')");
        } else {
            var controller = params.controller;
            
            if (!controller) {
                if (type=="form") controller = "LovelyHoverForm";
                else controller="LovelyHoverPage";
            }

            var hover = new window[controller]();
            hover.controller = controller;
            hover.url = href;
            hover.refreshOnClose = params.refreshonclose;
            hover.forceRefresh = params.forcerefresh;
        
            var id = LPM.registerHover(hover);
            node.attr("href", "JavaScript:LPM.showHover('" + id + "')");
        }
      } else{
        error('initHover: no href for link: ' + node);
      }
    },

    initBatch : function(node, params) {
        //normally the Batch-class is used to control a batchs behaviour
        //specialized controllers are possible, e.g. BatchedBox
        
        if (params.controller) {
            var batch = new window[params.controller]();
            batch.controller = params.controller;
        } else {
            var batch = new Batch();
        }

        batch.init(params.context);
    },

    initLogo : function(node, params) {
      node.bind("click", function() {
        window.location.href=LPM.getGlobals().portalUrl;
      });
    },

    registerListSorter : function(node, params) {
        node.addClass("ajax_listsorter");
    },
    
    initSearch : function(node, params) {

      var config = {
        field : node,
        target : $(params.target),
        baseurl : params.base,
        viewurl : params.view,
        consumers : params.consumers
      };
    
      var controller = params.controller || 'LiveSearch';
      var search = new window[controller]();
      search.init(LPM, config);
    },
    
    initForm : function(node, params) {
      var config = {
        form : node,
        target : $(params.target),
        iframebased : params.iframebased
      };
    
      var form = new LovelyInlineForm();
      form.init(LPM, config);
    },
    
    initNavControl : function(node) {
      var nav = new NavigationControl();
      nav.init(node);
      LPM.nav=nav;
    },

    initGossipRefresh : function(node){
        GR = new GossipRefresher();
        GR.init(node);
    }
}

$(function(){
    AjaxCommands.init();
});


LiveSearch = function() {}
LiveSearch.prototype.init = function(manager, config) {
  this.manager = manager;

  this.BASE_URL = config.baseurl;
  this.VIEW_URL = config.viewurl;
  this.FIELD = config.field;
  this.TARGET = config.target;
  this.CONSUMERS = config.consumers || "";
  this.INTERVAL = config.searchInterval || 300;
  this.CLEANUPINTERVAL = config.cleanupInterval || 30000;
  this.CACHEMAXAGE = config.cacheMaxAge || 60000;
  this.SHOW_LOAD_ANIMATION = true;
  this.LOAD_ANIM = config.loadingAnimation || this.manager.getGlobals().portalUrl+"/++resource++img/anim-loading.gif";
  this.INSTANCE_NAME = config.instanceName;
  this.EMPTYSHOWALL = config.emptyShowAll || false;
  
  this.MINSEARCHLENGTH = parseInt(this.FIELD.attr('ajax:minsearchlength'));
  this.TOOSHORTMSG = this.FIELD.attr('ajax:tooshortmsg');
  
  this.searchterm = "";
 
  if (this.FIELD.attr('title')) {
    this.emptyText = this.FIELD.attr('title');
    this.FIELD.val(this.emptyText);
  }

  this.cache = {};
  
  var self=this;
  
  this.cleanupInt = setInterval(function(){ self.cleanupCache(); },
                                this.CLEANUPINTERVAL);


  this.FIELD.bind('focus', function() { self.activate(); });
  this.FIELD.bind('blur', function() { self.deactivate(); });
 
  if (this['onInit']) {
  	this['onInit']();
  }
  
  this.FIELD.addClass("empty");
  
    
  // add defaults to config
  $.extend(config,
           {searchInterval: 300,
            cleanupInterval: 30000,
            cacheMaxAge: 60000});
};

LiveSearch.prototype.cleanupCache = function() {
  var now = new Date();
  for (var key in this.cache) {
    if ((now - this.cache[key].time) > this.CACHEMAXAGE) {
      delete this.cache[key];
    };
  }
};

LiveSearch.prototype.activate = function() {
  
  var self = this
  
  var field = this.FIELD;
  
  if (this['beforeSearch']) this['beforeSearch']();
  
  field.bind("keydown", function(event) {
    if(event.keyCode != 13) self.search($(this).attr("value"))
  });
  
  if (field.val()==this.emptyText) field.val("");
  field.addClass("filled");
  field.removeClass("empty");
  
  if (this['onActivate']) this['onActivate']();
};

LiveSearch.prototype.deactivate = function() {
  
  var field = this.FIELD;
  //LPM.tracker.search(this.searchterm);
  this.searchterm = "";
  field.unbind("keydown");
  
  if (field.val() == "" || field.val()==this.emptyText) {
      field.val(this.emptyText);
      field.addClass("empty");
      field.removeClass("filled");
  }
  
  if (this['onDeactivate']) this['onDeactivate']();
};

LiveSearch.prototype.search = function() {
  var self=this;
  clearInterval(this.searchInt);
  if (!this.isLoading) this.searchInt=setInterval(function(){self.loadResults()}, this.INTERVAL);
};

LiveSearch.prototype.loadResults = function() {
  
  clearInterval(this.searchInt);
  
  if(this.FIELD.attr("value")){
    var searchterm=this.FIELD.attr("value");
    }else{
        var searchterm="";
    } 
        var self=this;
  //only searach if we have more than minimum charachters
  if (searchterm.length < this.MINSEARCHLENGTH) {
    this.TARGET.empty().html('<div>'+this.TOOSHORTMSG+'</div>');
    return false;
  } 

  
  //only search if a searchterm is present
  if (searchterm==self.emptyText) searchterm="";

  if (searchterm || this.EMPTYSHOWALL) {
    var data = self.cache[searchterm];
    if (data != null) {
      if ((new Date() - data.time) < this.CACHEMAXAGE) {
        self._onResultsLoaded(data.data);
      }
    } else {
      
      this.isLoading = true;
      this.TARGET.empty();
      if (this.SHOW_LOAD_ANIMATION) this.showLoadAnimation()      
      $.get(
        this.getUrl(encodeURIComponent(searchterm)),
        function(data) {
          self.cache[searchterm] = {data: data, time: new Date()};
          self._onResultsLoaded(data);
        });
    }
  }
};

LiveSearch.prototype.showLoadAnimation = function() {
    this.TARGET.html('<img class="loading" src="'+this.LOAD_ANIM+'" alt="loading"" />');
};

LiveSearch.prototype.hideLoadAnimation = function() {};

LiveSearch.prototype.getUrl = function(term) {
  if (this.CONSUMERS) var consumers = "/"+this.CONSUMERS;
  else var consumers = "";
  
  //term = escape(term);
  var url = this.BASE_URL+consumers+"/search/"+this.cleanup(term)+"/"+this.VIEW_URL;
  return url;
};

LiveSearch.prototype.cleanup = function(term) {
    if(term.length > 0){ 
        term = term.split("?").join(" ");
        return term;
    }else{
        return term;
    }   
};

LiveSearch.prototype._onResultsLoaded = function (results) {
  this.isLoading = false;
  var searchedFor=$(results).attr("ajax:searchterm");
  this.searchterm = searchedFor;

  //display error and abort search if searchterm is not returned
  if (!searchedFor) {
    alert("check your search result template. 'ajax:searchterm' not provided.")
    this.isLoading=true;
    return;
  }
  
  if (searchedFor == this.cleanup(this.FIELD.attr("value"))) {
    this.hideLoadAnimation()
    this.TARGET.empty().append(results);
  } else {
    this.search();
  } 
  
  LPM.ajaxify();

  if (this['onResultsLoaded']) this['onResultsLoaded']();
};

/* mainsearch ------------------------------------------------------------- */

ToggleLiveSearch = function() {};

ToggleLiveSearch.prototype = new LiveSearch();

ToggleLiveSearch.prototype.onInit = function() {
  this.TARGET.hide();
  log("mainsearch.onInit()");
};

ToggleLiveSearch.prototype.onActivate = function() {
  
  var self=this;
  this.show();
  
  this.FIELD.bind("mouseout", function() {
    $('body').bind('click', function() {
      self.deactivate();
      $('body').unbind('click');
    });
  });
  this.FIELD.bind("mouseover", function() {
    $('body').unbind('click');
  });

  this.TARGET.bind("mouseout", function() {
    $('body').bind('click', function() {
      self.deactivate();
      $('body').unbind('click');
    });
  });
  
  this.TARGET.bind("mouseover", function() {
    $('body').unbind('click');
  });
};

ToggleLiveSearch.prototype.onResultsLoaded = function() {    
  var self=this;
};

ToggleLiveSearch.prototype.deactivate = function() {
  LiveSearch.prototype.deactivate.call(this);
//  this.hide();
};

ToggleLiveSearch.prototype.onDeactivate = function() {
    //override in subclass
};

ToggleLiveSearch.prototype.hide = function() {
  if (this.TARGET.css('display') != "none") this.TARGET.fadeOut("fast");
};
ToggleLiveSearch.prototype.show = function() {
  if (this.TARGET.css('display') == "none") this.TARGET.fadeIn("fast");
};

MainLiveSearch = function() {};
MainLiveSearch.prototype = new ToggleLiveSearch();

MainLiveSearch.prototype.init = function(manager, config) {
    ToggleLiveSearch.prototype.init.call(this, manager, config);
    this.lockResults = true;
};

MainLiveSearch.prototype.onActivate = function() {
    ToggleLiveSearch.prototype.onActivate.call(this);
    this.FIELD.parent().addClass("searched");
};

MainLiveSearch.prototype.onResultsLoaded = function() {    
  var self=this;
  $('a', this.TARGET).bind("mouseover", function(e) {self.locked=true;});
  $('a', this.TARGET).bind("mouseout", function(e) {self.locked=false;});
};

MainLiveSearch.prototype.deactivate = function() {
  if (!this.locked) {
      ToggleLiveSearch.prototype.deactivate.call(this);
      this.hide();
  }
};

MainLiveSearch.prototype.onDeactivate = function() {
    ToggleLiveSearch.prototype.onDeactivate.call(this);
    this.FIELD.parent().removeClass("searched");
};

/* addform searches */

FormSimilarPlacesSearch = function() {}
FormSimilarPlacesSearch.prototype = new LiveSearch();
FormSimilarPlacesSearch.prototype.onResultsLoaded = function() {
  var self=this;
  $('div.ts-description', this.TARGET.parent()).css('visibility', 'visible');
  $('div.shortsearchresult', this.TARGET).bind("click", function() {
    LHM.getCurrentHover().showExistingItemPreview(this, self);
  });
};

/* sliderlocationsearch */

SliderLocationSearch = function() {}
SliderLocationSearch.prototype = new ToggleLiveSearch();
SliderLocationSearch.prototype.onResultsLoaded = function() {
    var self = this;
    // $('li', this.TARGET).bind("mouseover", function(e) {self.lock();})
    // $('li', this.TARGET).bind("mouseout", function(e) {self.unlock();})
    $('li', this.TARGET).bind("click", function(event) {
        event.stopPropagation();
		var n = $(this);
        LPM.nav.onSearchResultChosen({
            street : $('span.street', n).html(),
            zip : $('span.zip', n).html(),
            district : $('span.district', n).html(),
            lat : n.attr("ajax:lat"),
            lon : n.attr("ajax:lon")
        });
		log("clicked");
        self.hide();
        self.FIELD.val($('span.street', n).html());        
    }).css("cursor", "pointer");
};

SliderLocationSearch.prototype.showLoadAnimation = function() {
    if(!$('img.loadanimation').length) {
      this.FIELD.after('<img class="loadanimation" src="'+this.LOAD_ANIM+'" alt="loading"" />');
    }
};

SliderLocationSearch.prototype.hideLoadAnimation = function() {
    $('img.loadanimation').remove()
};

SliderLocationSearch.prototype.onDeactivate = function() {
    ToggleLiveSearch.prototype.onDeactivate.call(this);
	this.TARGET.hide("slow");
};

FormAddressSearch = function() {}
FormAddressSearch.prototype = new ToggleLiveSearch();
FormAddressSearch.prototype.onResultsLoaded = function() {
  var self=this
  $('div.result', this.TARGET).bind("click", function(){
    LHM.getCurrentHover().updateAddressBySearchResult(this, self);
  });
};

UseTitleAsValueSearch = function() {}
UseTitleAsValueSearch.prototype = new ToggleLiveSearch();
UseTitleAsValueSearch.prototype.onResultsLoaded = function() {
  var self=this;
   $('.ajax_result', this.TARGET).bind("click", function(){
    self.FIELD.val($(this).attr('ajax:title'));
  });
};

/* listsearch ------------------------------------------------------------- */
LovelyListSearch = function() {}
LovelyListSearch.prototype = new LiveSearch();
var map; // Main Map Handle
var lat; // Main Map Parameter
var lon; // Main Map Parameter
var zoom; // Main Map Parameter
var logo; // global logo
var pinid=0;
var map_loaded=0;
var widget_type = "";	// for widget_map
var widget_lat;	// for widget_map
var widget_lon;	// for widget_map
var widget_zoom; // for widget_map
var widget_pin; // for widget_map
var widget_map; // for widget_map
var animator_status=0;
var mbRenderUrl = 'http://service.meinberlin.de/notes/';
var bubbleData;  // New Bubble-Dom
var bubbleActive=new Array(); // New Bubble-Dom
var mbReopenBubble = false;
var pinActive = []; // New Bubble-Dom
var pinRepos = []; // Holding Marker-Objects in an array
var pincheck = []; // Since we use a function to create pinmarker, we need a global hash-variable for stacking-check
var pinmarkerobject; // Global again to have always the current instance in case of switching between magazin to map.
var active; // Found in LPM Usage, dont know why :-)
var bubbleMap; // Yet another map-handle for small static-map in content-bubbles without picture
var mbDebug = false; // false: Debug only on localhost / true: Debug everywhere;
var mbHPLoaded = false;
var mbDrawRectangleArray = new Array();
var mbDrawRectangleType;
var operating = {
		resizingMap: 	false,
		getPrebubble: 	false,
		getPinCall:		false,
		zooming:		false
};

function mbGetBounds(map_object)
{

	map_object = map_object || map;

	if(map_object){
	var left_top_lon=map_object.getBounds().getSouthWest().lng();
	var right_bottom_lon=map_object.getBounds().getNorthEast().lng();
	var left_top_lat=map_object.getBounds().getNorthEast().lat();
	var right_bottom_lat=map_object.getBounds().getSouthWest().lat();
	}

	var ret=new Array(left_top_lat,left_top_lon,right_bottom_lat,right_bottom_lon);
	return ret;
}

// Main function to draw things, sync pins, ajax-calls etc.
function sync_pois(force, noEvent)
{
  
  info('in sync_pois');
  
	log("SYNC_POIS!!! - MapLoad-State: "+map_loaded+", LPM.mode: "+LPM.mode);
	if(map.getInfoWindow())map.closeInfoWindow();

    if(!document.getElementById("mbBigBubble")&&!mbReopenBubble)
	{
	var hash = mbGetHash();
	close_locator();

	if(map_loaded==1&&(LPM.mode=="map"||!LPM.mode))
		{

	var bounds=mbGetBounds(map);
    log("Got bounds :-) "+bounds[0]+" "	+bounds[1]+" "+bounds[2]+" "+bounds[3]+" in Mode: "+LPM.mode);

    log("Call JSON now!");

	//tile-based pinloading 
    LPM.map.loadPinsForArea(bounds[0],
                            bounds[1],
                            bounds[2],
                            bounds[3],
                            map.getZoom(),
                            LPM.getFilter(),
                            function(json) {
                              draw_pins(json);
							  if (zoom==19 && (map.getCenter().lat()==52.43676 && map.getCenter().lng()==13.64614)) markUnlocatedArea(); // show unlocated area
                            });
    	}else{
    		//log("Sync_Pois called but in wrong mode: "+LPM.mode);
    	}
	}else{
	
			if(document.getElementById("mbBigBubble"))log("sync_pois() stopped - there seems to be a bubble open");
   		
    		}

}

function fromLatLngToContainerPixel(the_map, the_container, gLatLng) {

    // first we translate into "DivPixel"
    var gPoint = the_map.fromLatLngToDivPixel(gLatLng);

    // locate the sliding "Div" div
    var div = document.getElementById(the_container).firstChild.firstChild;

    // adjust by the offset of "Div" and voila!
    gPoint.x += div.offsetLeft;
    gPoint.y += div.offsetTop;

    return gPoint;
}

// Draw the pins on the map
function draw_pins(json)
{

  info('in draw pins');
  
	mbClearOverlays();
	if(mbDrawRectangleArray.length>2){log("mbMakeLine: "+mbDrawRectangleArray.length); mbMakeLine(mbDrawRectangleArray,mbDrawRectangleType);}
	pincheck=new Array(); // Clear variable

	for(i=0;i<json.length;i++) // the cycle himself
	{
		mbCreatePin(json[i]['lat'],json[i]['lon'],json[i]['type'],json[i]['subType'],json[i]['id'],json[i]['title'],json[i])
	}

	map.checkResize();	// for compatibility-issues
}


function mbSinglePin(pinLat,pinLon,pinType,pinSubType,pinTitle,pinID)
{

	if(LPM.mode!="map"){
	pinActive['id']=pinID;
	pinActive['lat']=pinLat;
	pinActive['lon']=pinLon;
	pinActive['title']=pinTitle;
	pinActive['subtype']=pinSubType;
	pinActive['type']=pinType;

	log("Singlepin: "+LPM.mode+ "  "+pinTitle+"  LatLon: "+pinLat+" "+pinLon);
		
	mbClearOverlays();
	map.setCenter(new GLatLng(pinLat,pinLon),17);
	pincheck=new Array(); // Kill symbiotic cycle of stacking-function, which lifts Pins up more and more.
	mbCreatePin(pinLat,pinLon,pinType,pinSubType,pinID,pinTitle,false,false,true);
	}
	
}



function mbCreatePin(pinLat,pinLon,pinType,pinSubType,pinID,pinTitle,pinOptObject,opened,noclickevent)
{
	if(!pinTitle)pinTitle="Pin";
	if(opened){
	pincheck=new Array();
	log("OPEN: "+pinLat+" "+pinLon+" "+pinType+" "+pinSubType+" "+pinID+" "+pinTitle+" "+pinOptObject+" "+opened+" "+noclickevent);
	}
	if(noclickevent)("Single-Pin to draw: "+pinLat+" "+pinLon+" "+pinType+" "+pinSubType+" "+pinID+" "+pinTitle+" "+pinOptObject+" "+opened+" "+noclickevent);
		// Stapeln von Pins mit gleichen Koordinaten. This is mandatory for a clean view and not fpr notes
	if(pinType.toLowerCase()!='note'){
	var pointhash="ph"+pinLat+"x"+pinLon;
	var pinStack='';
	while(array_try(pincheck,pointhash)==1){
	pinLat=pinLat+((20-zoom)*0.00004); // Geographic stacking function..may be altered a bit
	// pinLon=pinLon+((20-zoom)*0.01); // Obsolete - Dont stack sideways
	var pointhash="ph"+pinLat+"x"+pinLon;
	pinStack='h';
	}

	pincheck[pointhash]=1;

	}
	if(LPM.mode!="map")pinStack="";

	
	pinLat=mbRound(pinLat,5);
	pinLon=mbRound(pinLon,5);



	var point=new GLatLng(pinLat,pinLon);

	if (pinType.toLowerCase() != 'note')
	{	if (pinType.toLowerCase() == 'homefolder') pinType = pinType + '-' + pinSubType;
		var Icon = new GIcon();
		Icon.image = LPM.getGlobals().portalUrl+'/@@/img/needles/' + pinStack + pinType.toLowerCase() + '-s.png';
		if (!($.browser.msie && $.browser.version < 7))Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-s.png';
		if ($.browser.msie && $.browser.version > 6)Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-s-ie.png';
		Icon.imageMap = [17,0,22,6,22,16,16,21,6,21,0,15,0,6,6,0];
		Icon.iconSize = new GSize(94, 70);
		Icon.iconAnchor = new GPoint(75, 64);
		Icon.infoWindowAnchor = new GPoint(16, 4);	
		Icon.shadowSize = new GSize(94, 70);
		Icon.shadow = LPM.getGlobals().portalUrl+'/@@/img/needles/schatten-s.png';
		
		if (zoom>=17)
		{
			Icon.image = mbRenderUrl +encodeURIComponent(pinTitle)+ '/' + pinStack + pinType.toLowerCase() + '/' +  pinID + '.png';
			if (!($.browser.msie && $.browser.version < 7))Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-long-needle.png';
			if($.browser.msie && $.browser.version > 6)Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-long-needle-ie.png';
			Icon.imageMap = [54,23,58,6,64,0,226,0,229,3,230,40,225,44,218,47,203,48,69,46,60,38,54,29,54,18];
			Icon.iconSize = new GSize(230, 72);
			Icon.shadowSize = new GSize(230, 72);	
			Icon.shadow = LPM.getGlobals().portalUrl+'/@@/img/needles/shadow-s_mit_detail.png';
			Icon.infoWindowAnchor = new GPoint(15, 6);
			Icon.iconAnchor = new GPoint(80, 64);			
		}
	}
	else
	{
		var Icon = new GIcon();
		Icon.image = mbRenderUrl+encodeURIComponent(pinTitle)+ '.png';
		/* Icon.image = LPM.getGlobals().portalUrl+'/@@/img/needles/post_it_auf_block.png'; */
		Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/note-transparent.png';
		Icon.imageMap = [4,4,39,2,42,24,12,28];
		Icon.iconSize = new GSize(44, 36);
		Icon.iconAnchor = new GPoint(25, 17);
		Icon.infoWindowAnchor = new GPoint(0, 0);
	}

	var options = {
	icon: Icon,
	draggable: false,
	title: pinTitle,
	dragCrossMove: false
	// id: "pin_"+pinID   // ID for hover-effect on stacks
	};

	pinmarker = new GMarker(point, options);

	pinmarker.id = pinID; // Giving an Unique ID to the image-map, so we can use JQuery to attach a ID to the image (needle) itself
	pinmarker.pintype=pinType;
	
	map.addOverlay(pinmarker);
	
	// Adding our marker to the repository. Needed for array-based "clearOverlays()" Function
	pinRepos.push(pinmarker);
	
		// Pinmarker 2.0 for bubble 2.0 START

	if(!noclickevent){
		

		GEvent.addListener(pinmarker, "click", function() {
			log("click - Have to open bubble #"+this.id);
			pinmarkerobject=this;
			mbOpenBubble(this);
	});
	
	}
		// Pinmarker 2.0 for bubble 2.0 END
	if (!($.browser.msie && $.browser.version < 7)) {
		// Every needle should have an Attribute
		if ($.browser.msie) {
			var transparent = $("#mtgt_" + pinID);
		}
		else {
			var transparent = $("#mtgt_" + pinID).parent().prev();
		}
		
		var top = parseInt(String(transparent.css("top")).substring(0, (String(transparent.css("top")).length - 2)));
		var left = parseInt(String(transparent.css("left")).substring(0, (String(transparent.css("left")).length - 2)));
		
		// moving image map a bit
		// transparent.attr("id","img_"+pinID);
		transparent.addClass("ico_" + pinType.toLowerCase());
		if (pinType.toLowerCase() != 'note') {
		
			if (zoom >= 17) {
				if ($.browser.msie) {
					transparent.css({
						width: "165px",
						height: "34px",
						top: (top + 10) + "px",
						left: (left + 54) + "px"
					});
				}
				else {
					transparent.css({
						width: "201px",
						height: "40px",
						top: (top + 10) + "px",
						left: (left + 14) + "px"
					});
				}
			}
			else {
				transparent.css({
					width: "22px",
					height: "22px",
					top: (top + 10) + "px",
					left: (left + 64) + "px"
				});
			}
			
		}
	}




		if(pinOptObject&&zoom>=17&&pinStack=='h'){  // Only if we hav an object
		GEvent.addListener(pinmarker, 'mouseover', function(){
 			var newZIndex=GOverlay.getZIndex(this.getPoint().lat()*-1);
			var subType = "";
			if (pinOptObject['subType']) subType = "-" + pinOptObject['subType'];
		   	var newImage=mbRenderUrl+encodeURIComponent(pinOptObject['title'])+'/'+pinOptObject['type'].toLowerCase()+subType+'/'+pinOptObject['id'] + '.png';
			this.setImage(newImage);
			$("img[src='"+newImage+"']").css({zIndex: newZIndex});
			log("Overpin: ",pinOptObject);
			});
		GEvent.addListener(pinmarker, 'mouseout', function(){

			var newZIndex=GOverlay.getZIndex(this.getPoint().lat()*1);
			var subType = "";
			if (pinOptObject['subType']) subType = "-" + pinOptObject['subType'];
			var newImage=mbRenderUrl+encodeURIComponent(pinOptObject['title'])+'/h'+pinOptObject['type'].toLowerCase()+subType+'/'+pinOptObject['id'] + '.png';
			this.setImage(newImage);
		 	$("img[src='"+newImage+"']").css({zIndex: newZIndex});
			log("Outpin: "+pinOptObject['type']);
			});

		}


		if(opened)
		{
		
		log("Active - Have to open bubble #"+pinID + " " + pinLat + " " + pinLon);
		// set trigger to click-event to open up the bubble. And dont miss the handling of map.clearOverlays, which will kick out every bubble :-)
		// GEvent.trigger(pinmarker,  "click");  // Hmmm :-)
		mbOpenBubble(pinmarker);
		
		}

}




// Initiale Funktion, wird vom Lovely Pagemanagaer aufgerufen

// function start_map(lat, lon, posz)
// {
//   var _mapstart = {
//       lat : lat,
//       lon : lon,
//       posz : posz
//   }
//   google.setOnLoadCallback(init_map);
// }

function start_map(lat, lon, posz) {
  //lat = _mapstart.lat; lon=_mapstart.lon; posz = _mapstart.posz; delete _mapstart;
    
  still_waiting=1;
  log("Started at "+lat+" "+lon+" "+posz);

	// wir passen den Startpunkt neu an
	var hash = mbGetHash();
	if (hash['lat'] && hash['lon'] && hash['zoom']) { lat = hash['lat']; lon = hash['lon']; posz = hash['zoom']; }

	zoom=posz;
	log("Hash ready");
   	// Map Instances - Here: Big Map w/ Events

        map = new GMap2(document.getElementById("karte")); // Create handler

		//LPM.trigger.initialize();
        log("Handler ready");

        map.setCenter(new GLatLng(lat,lon), zoom-0,G_HYBRID_MAP); // Show map center and choose style
        map_loaded=1;

  return{map:map}
}

function set_pos(posx,posy)
{
var posobject=new GLatLng(posx,posy);
if(LPM.mode=="map"){map.panTo(posobject);}
}

function set_zoom(posz)
{
zoom=posz;
map.setZoom(zoom);
sync_pois();
LPM.onMapZoomChange(zoom);
}

function set_pos_and_zoom(posx,posy,posz)
{
	zoom=posz; // zoom is global
	var posobject=new GLatLng(posx,posy);
	map.setCenter(posobject,Math.round(posz-0));
}

function get_center_and_zoom() {
		var red = new Object();
		red.lat = map.getCenter().lat();
		red.lon = map.getCenter().lng();
		red.zoom = zoom;

  return red;
}


function toggleMapmode()
{
	if(map.getCurrentMapType().getName()=="Hybrid")map.setCenter(map.getCenter(), zoom,G_NORMAL_MAP);
	if(map.getCurrentMapType().getName()=="Karte")map.setCenter(map.getCenter(), zoom,G_HYBRID_MAP);
}

function mbautoBound(plat,plon,pwidth,pheight)
{
	log("Starting Autobounder...");
	// coords
	var left = fromLatLngToContainerPixel(map,"karte",new GLatLng(plat,plon)).x;
	var top = fromLatLngToContainerPixel(map,"karte",new GLatLng(plat,plon)).y;
	var right = $('#karte').width()-260-left; // minus minimap
	var bottom = $('#karte').height()-top;
	// map-center
	var center = { x:($('#karte').width()/2), y:($('#karte').height()/2) };
	// new map-center
	if ((top - pheight) < 0)  center.y = center.y + top - pheight; // pan down
	if ((left - pwidth/2) < 0) center.x = center.x + left - pwidth/2; // pan right
	if ((right - pwidth/2) < 0) center.x = center.x - right + pwidth/2; // pan left
	// center the map
	map.panTo(map.fromContainerPixelToLatLng(new GPoint(center.x,center.y)));

}

function mbgetMapCenter()
{
	var center = { x:($('#karte').width()/2), y:($('#karte').height()/2) };
	return center;
}



//#######################################################
//###############  Bubble - Functions ###################
//#######################################################


function mbClearOverlays()
{
if(map.getInfoWindow())map.closeInfoWindow();
if(map.getExtInfoWindow())map.closeExtInfoWindow();

var pincount = pinRepos.length;
log("Called mbClearOverlays for "+pincount+" Pins"); 
for(i=0;i<pincount;i++)
	{
	map.removeOverlay(pinRepos[i]);	
	}
pinRepos = [];	
}	

// We´ll keep this function still compatible with generic bubbles, due to too many changes in our dev-history :-)
function mbOpenBubble(needle)
{
if(map.getInfoWindow())map.closeInfoWindow();
if(map.getExtInfoWindow())map.closeExtInfoWindow();
	if(needle)pinmarkerobject=needle;

if(pinmarkerobject){
		LPM.focus.setFocus(pinmarkerobject.id);


if ($.browser.msie)var offsetX=-199; else var offsetX=0;

if(pinmarkerobject.pintype!="Note"){
	var shadow=true; 
	var offsetY = -217;
	// var offsetX = offsetX;
	var paddingY = 300;
	var paddingX = 200;
	}else{
	var shadow=null;
	var offsetY = -70;
	var offsetX = offsetX + 90;
	var paddingY = 100;
	var paddingX = 100;
	}


	  	var url = LPM.getGlobals().portalUrl+ "/focus/" + pinmarkerobject.id + "/pin/content/resolvebubble";
    		pinmarkerobject.openExtInfoWindow(
              map,
              "mbBigBubble",
              "<div>Loading...</div>",
              {
                ajaxUrl: url, 
                offsetY: offsetY,
                offsetX: offsetX,
                paddingX: paddingX,
                paddingY: paddingY,
                paddingXR: 180,
                paddingXL: 0,
                shadow: shadow
               
              }); 

	}
	LPM.trigger.bubbleOpened();
}

function mbCloseBubble(norelease) {
	bubbleActive = new Array();
	if(!norelease && LPM.mode=="map")LPM.focus.releaseFocus();
	log("Closing bubble, releasing focus");
	if(map.getInfoWindow())map.closeInfoWindow();
	if(map.getExtInfoWindow())map.closeExtInfoWindow();
	sync_pois();
	LPM.trigger.addHistory();
}

function mbBubbleMap(mbBubbleLatLonObject)
{
		if(pinmarkerobject&&document.getElementById("contentbubble_map")){
		bubbleMap=new GMap2(document.getElementById("contentbubble_map"));
		GEvent.addListener(bubbleMap, 'load', function(){
			mbHideCopyright("contentbubble_map");
		});
		bubbleMap.setCenter(mbBubbleLatLonObject,19,G_HYBRID_MAP);
		bubbleMap.disableDragging();
	}
}

//###############  Bubble 2.0 by Flashi #################


function getPrebubble(type,koords)
{
	cancelPrebubble();
	if (!operating.getPrebubble)
	{
		window.scrollTo(0,0);
		operating.getPrebubble=true;
		if (!(LPM.getGlobals().loginStatus == "loggedIn" || type == "note"))
		{
			LPM.showHoverPage(LPM.getGlobals().portalUrl, "/pin/senden/pls_register/");
			operating.getPrebubble=false;
		}
		else
		{
			if(LPM.mode!="map")
			{
				mbEnlargeMap(type,koords);
			}
			else
			{
				addPrebubble(type,koords);
			}
			ivw.newPage(false, "funk");
		}	
	}
}

function addPrebubble(type,koords)
{
	var url = LPM.getGlobals().portalUrl+'/pin/'+type+'/create';
	cancelPrebubble();
	$.get(url, function(data){

		$('#karte').append(data);

		$('#prebubble').css({ left: (mbgetMapCenter().x-300), top: (mbgetMapCenter().y-150) });

		var prebubble = new GDraggableObject(document.getElementById("prebubble"), {
			draggingCursor: "move",
			draggableCursor: "pointer"
		});

		$('#pb_right').bind("click", function(){cancelPrebubble();})

		if (document.getElementById('pb_left'))	$('#pb_left').bind("click", function(){	submitPrebubble(type); });

    if (document.getElementById('pb_new_news')) $('#pb_new_news').bind("click", function(){ submitPrebubble("newsitem"); });
    if (document.getElementById('pb_new_event')) $('#pb_new_event').bind("click", function(){ submitPrebubble("event"); });
    if (document.getElementById('pb_new_place')) $('#pb_new_place').bind("click", function(){ submitPrebubble("place"); });

    LPM.ajaxify($('#prebubble'));

	});
}

function submitPrebubble(type)
{
	var pos = mbgetNotePosition("prebubble");

		if (type == 'note')
		{
			pos.x = pos.x + 100;
			pos.y = pos.y + 60;
		}
		else
		{
			pos.x = pos.x + 270;
			pos.y = pos.y + 156;
		}

	var endpos = map.fromContainerPixelToLatLng(new GPoint(pos.x,pos.y));
	cancelPrebubble();
	LPM.showAddForm(type.toLowerCase(),endpos.lat(),endpos.lng());
}

function cancelPrebubble()
{
	if (document.getElementById('prebubble'))
	{
		if(LPM.mode!="map") mbReduceMap();
		$('#prebubble').remove();
		operating.getPrebubble=false;
	}
}

function mbScreenLogo()
{
	map.addOverlay(logo);
}

function mbEnlargeMap(type,koords)
{
    var container=$('div#mapcontainer');
	var cz = get_center_and_zoom();
	var h = mbFixDOM.getHeight(); 
  	var speed = 2000;
	if($.browser.msie) speed = 5;
	operating.resizingMap = true;

    // doing the fast part
	container.animate({height: h+"px"}, speed, "swing", function(){
		if($.browser.msie) container.css({ minHeight: h+"px" });
		map.checkResize();
		map.setCenter(new GLatLng(cz.lat, cz.lon));
		if(type)
		{
			addPrebubble(type,koords);
		}
		else
		{
			LPM.mag.hideMagTabs();
			LPM.mag.hideHead();
		}
		mbFixDOM.resize(true);
		operating.resizingMap = false;
	});
}

function mbReduceMap(call)
{
	var container=$('div#mapcontainer');
    var cz = get_center_and_zoom();
	log("took Position: ", cz);
  	var speed = 2000;
	if(call=="init")speed = 2;
	if($.browser.msie) speed = 5;

    // doing the fast part
	operating.resizingMap = true;
	container.animate({height: "185px"}, speed, "swing", function(){
		if($.browser.msie) container.css({ minHeight: "185px" });
		map.checkResize();
		if(array_try(pinActive,"lat")>0)
		{
			cz.lat = pinActive['lat'];
			cz.lon = pinActive['lon'];
			log("took flashis array");
		}
		if(call)
		{
			cz.lat = LPM.getGlobals().mapStartUp.c_lat;
			cz.lon = LPM.getGlobals().mapStartUp.c_lon;
			log("took the global geos");
		}
		log(cz.lat +" + " + cz.lon);
		map.setCenter(new GLatLng(cz.lat, cz.lon));
		log("focus is "+LPM.focus.uid);
		log("HP is "+ mbHPLoaded);
		operating.resizingMap = false;
	});
}

// Now we show a small isle to all our invisibles
function markUnlocatedArea()
{

	var point=new GLatLng('52.43676','13.64614');
	var Icon = new GIcon();
	Icon.image = LPM.getGlobals().portalUrl+'/@@/img/ring_schild_1.png';
	Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-long-needle.png';
	Icon.iconSize = new GSize(414, 346);
	Icon.iconAnchor = new GPoint(200, 170);

	var options = {
	icon: Icon,
	draggable: false
	};

	marker = new GMarker(point, options);
	map.addOverlay(marker);

}

function hover_pin(pin_object)
{

	if (!$('#lneedle_'+pin_object['id']).attr("alt"))
	{
		log("Hovering Pin...",pin_object);
		$('#lneedle_'+pin_object['id']).attr({ src: mbRenderUrl+encodeURIComponent(pin_object['title'])+'/'+pin_object['type'].toLowerCase()+'/'+pin_object['id'] + '.png', alt: 		$('#lneedle_'+pin_object['id']).css("zIndex") });
		$('#lneedle_'+pin_object['id']).css({ zIndex: ($('#lneedle_'+pin_object['id']).css("zIndex")*-1) });
	}

}

function unhover_pin(pin_object)
{
	$('#lneedle_'+pin_object['id']).attr({ src: mbRenderUrl+encodeURIComponent(pin_object['title'])+'/'+pin_object['stapel']+pin_object['type'].toLowerCase()+'/'+pin_object['id'] + '.png' });
	$('#lneedle_'+pin_object['id']).css({ zIndex: $('#lneedle_'+pin_object['id']).attr("alt") });
	$('#lneedle_'+pin_object['id']).removeAttr("alt");
}

// Adress - Functions
function show_adress()
{
	// if (document.getElementById('locator')) $('#locator').remove();
	mbCloseBubble();
	$("#gm_map_repos_106").append("<div id=\"locator\" onclick=\"close_locator()\"></div>");
	var pos = { x:map.fromLatLngToDivPixel(map.getCenter()).x, y:map.fromLatLngToDivPixel(map.getCenter()).y };
	$('#locator').css({ top: (pos.y-($('#karte').height()/2))+"px", left: (pos.x-($('#karte').width()/2)-50)+"px", width: $('#karte').width()+"px", height: $('#karte').height()+"px" });
	window.setTimeout("fadeout_needles()", 1500);
	// dhtmlHistory.add('lat:'+mbRound(map.getCenter().y, 5)+'|lon:'+mbRound(map.getCenter().x, 5)+'|zoom:'+zoom, {message: 'changed zoom to' + zoom});
}

function fadeout_needles()
{
	$('#locator').fadeIn("slow");
	$('.long_needles').fadeTo("slow", 0.3);
}

function close_locator()
{
	$('#locator').fadeOut("slow", function(){
			$('#locator').remove();
			$('.long_needles').fadeTo("slow", 1);
		});
}


//############### END Bubble - Functions ###################


//#######################################################
//###############  Widget - Map Ding ####################
//#######################################################



function widget_set_zoom(wzoom)
{
	widget_zoom=wzoom;
	widget_map.setZoom(wzoom-0);
	widget_sync_pois();
}

function widget_draw_pins(wjson)
{
	log("widget_draw_pins "+wjson.length+" gestartet");
	widget_map.clearOverlays();
	var insert_html = "";
	var wpin_count=0;
	for(i=0;i<wjson.length;i++)
	{
    	var point=new GLatLng(wjson[i]['lat'],wjson[i]['lon']);
		var Icon = new GIcon();
		Icon.image = LPM.getGlobals().portalUrl+'/@@/img/needles/widgetmap/h' + wjson[i]['type'].toLowerCase() + '.png';
		// Icon.shadow = LPM.getGlobals().portalUrl+'/@@/img/needles/shadow.png';
		Icon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-s.png';
		Icon.imageMap = [0,0,31,0,31,31,0,31,0,0];
		Icon.iconSize = new GSize(40, 57);
		// Icon.shadowSize = new GSize(94, 70);
		Icon.iconAnchor = new GPoint(19, 65);
		Icon.infoWindowAnchor = new GPoint(15, 6);

		wpin_count++;

		var options =
		{
			icon: Icon,
			draggable: false,
			title: wjson[i]['title'],
			dragCrossMove: false,
			id: "pin_"+wjson[i]['id']
		};

		eval("wpin"+i+" = new GMarker(point, options);");
		eval("widget_map.addOverlay(wpin"+i+");");

		// Build dom

		insert_html = insert_html + '  <div id="wp'+i+'"  class="shortsearchresult" ajax:uid="'+wjson[i]['id']+'"ajax:pin="'+i+'" ajax:type="'+wjson[i]['type']+'" ajax:title="'+wjson[i]['title']+'" ajax:zip="10117" ajax:street="Pariser Pl. 7" ajax:district="Mitte" ajax:lon="'+wjson[i]['lon']+'" ajax:city="Berlin" ajax:lat="'+wjson[i]['lat']+'">  <div class="icon '+wjson[i]['type'].toLowerCase()+'"></div> <div class="title" onmouseover="wphover('+i+',\'over\',\''+wjson[i]['type']+'\');" onmouseout="wphover('+i+',\'out\',\''+wjson[i]['type']+'\');">'+wjson[i]['title']+'</div></div>';
	}

	LHM.getCurrentHover().showMapItemList(insert_html);

	widget_show_pin();

	for(i=0;i<wpin_count;i++)
	{
		eval("GEvent.addListener(wpin"+i+", 'mouseover', function(){$('#wp"+i+"').addClass('as-hover-remote');});");
		eval("GEvent.addListener(wpin"+i+", 'mouseout', function(){$('#wp"+i+"').removeClass('as-hover-remote');});");
	}
}

function wphover(a,b,c)
{
	eval("if(b==\"over\")wpin"+a+".setImage(LPM.getGlobals().portalUrl+'/@@/img/needles/widgetmap/' + c.toLowerCase() + '.png'); else wpin"+a+".setImage(LPM.getGlobals().portalUrl+'/@@/img/needles/widgetmap/h' + c.toLowerCase() + '.png');");
}

function widget_get_zoom()
{
	return widget_map.getZoom();
}

function widget_set_center(wlat,wlon,wzoom,type,fin)
{
	if(!type)type=widget_type; else widget_type=type;

    widget_map.setCenter(new GLatLng(wlat, wlon),wzoom-0,G_HYBRID_MAP);

        // Anzeige Mittelpin
 	widget_lat=wlat;
    widget_lon=wlon;

//    if(fin)widget_show_pin(1);

}

function widget_show_pin(fin)
{
	var Wicon = new GIcon();
	Wicon.image = LPM.getGlobals().portalUrl+'/@@/img/needles/' + widget_type.toLowerCase() + '.png';
		// Wicon.shadow = LPM.getGlobals().portalUrl+'/@@/img/needles/widget_map/' + widget_type.toLowerCase() + '.png';
	Wicon.transparent = LPM.getGlobals().portalUrl+'/@@/img/needles/transparent-s.png';
	Wicon.imageMap = [0,0,31,0,31,31,0,31,0,0];
	Wicon.iconSize = new GSize(40, 57);
	Wicon.iconAnchor = new GPoint(19, 65);
		// Wicon.shadowSize = new GSize(38, 70);
	Wicon.infoWindowAnchor = new GPoint(15, 6);

 	log("Zeige Widget-Mittelpin Typ "+widget_type+" at "+widget_map.getCenter().lat()+" "+widget_map.getCenter().lng());

    if(!fin)
	{
        var widget_pin = new GMarker(widget_map.getCenter(), {icon: Wicon, draggable:true,dragCrossMove:true});
        GEvent.addListener(widget_pin, 'dragend', function()
		{
			widget_lat=this.getPoint().lat();
			widget_lon=this.getPoint().lng();
			log("New Widget LatLng: "+widget_lat+" "+widget_lon);
			LHM.getCurrentHover().updateAddressByMapPosition(this.getPoint().lat(), this.getPoint().lng());
			widget_map.panTo(this.getPoint());
		});

	}
	else
	{
		var widget_pin = new GMarker(widget_map.getCenter(), {icon: Wicon, draggable:false,dragCrossMove:false});
	}

    widget_map.addOverlay(widget_pin);

}

function widget_sync_pois()
{
	widget_map.checkResize();
	var bounds=mbGetBounds(widget_map);

	log("Json Call mit Zoom " + widget_map.getZoom()+" bei "+bounds[0]+", "+bounds[1]+" zu "+bounds[2]+", "+bounds[3]+". Typ: "+widget_type + ". Kartengroesse: " + widget_map.getSize().width + "x" + widget_map.getSize().height + "px");

 	LPM.map.loadPinsForArea(bounds[0],
                            bounds[1],
                            bounds[2],
                            bounds[3],
                            widget_map.getZoom(),
                            widget_type,
                            function(json){
                              widget_draw_pins(json);
                            });
	widget_show_pin(1);
}

function widget_create(wdiv, wlat, wlon, wzoom, type, fin)
{
	widget_type = type;
	if(widget_map)widget_map=0;
	widget_map=new GMap2(document.getElementById(wdiv));
	if(fin)widget_map.disableDragging();
	log("Erstelle widget_map fin:"+fin+"map:"+widget_map);

	if(!fin)GEvent.addListener(widget_map, 'moveend', function(){
		LHM.getCurrentHover().updateAddressByMapPosition(widget_map.getCenter().lat(), widget_map.getCenter().lng());
		widget_sync_pois();
		
	});

	if(!fin)GEvent.addListener(widget_map, 'zoomend', function(oldLevel,newLevel){
		widget_zoom=newLevel;
		LHM.getCurrentHover().updateAddressByMapPosition(widget_map.getCenter().lat(), widget_map.getCenter().lng());
		widget_sync_pois();
		$('#as-zoomslider').slider("moveTo", newLevel);
		$('#as-zoomslider').css({
						backgroundPosition: '0 ' + (-220 + 16*(newLevel-7)) + 'px'
					});
	});

	widget_set_center(wlat,wlon,wzoom,type,fin);

	$('#'+wdiv).children('div').each(function(i){
   		if (i>0) this.style.display = "none";
 	});

// Sliderfunctions


  log("initialize widgetzoomslider");
  if (document.getElementById("as-zoomslider"))
  {
	
	$('#as-zoomslider').slider({
				stop: function(e,ui){widget_set_zoom(ui.value);},
				slide: function(e, ui){if (ui && ui.value) {
					$('#as-zoomslider').css({
						backgroundPosition: '0 ' + (-220 + 16*(ui.value-7)) + 'px'
					});
				}},
				min: 12,
				max: 19,
				steps: 7,
				axis: 'vertical'
				});			
		} else warn("nothing found to initialize!");
	
	$('#as-zoomslider').slider("moveTo", wzoom);
}

function widgetGetZoomLevel()
{
	error("called widgetGetZoomLevel");
}

function widgetSetZoomLevel()
{

	error("called widgetSetZoomLevel");

}


//#######################################################
//###############  Minimap - Functions ##################
//#######################################################

function slider()
{

	error("called slider");
}

function showSliderInfo(y)
{
	error("called showSliderInfo");

}

function mbgetZoomLevel()
{

		error("called mbgetZoomLevel");

}

//##############  END Minimap - Functions ###############
// #######################################################
// ########################  Mode-Switch  ################
// #######################################################
ViewModeManager = function(){
    this.container = $("#mapcontainer");
    this.map = $("#karte");
    this.modes = ["map", "magazine", "gossip"];
    this.modeClasses = {
        map: "mapmode",
        gossip: "gossipmode",
        magazine: "magazinemode"
    };
    this.magazineContainer = $("#magazine-container");
    this.containerHeight = {
        magazine: 145,
        map: 500,
        gossip: 115
    };
    this.minHeight = 685;
    //	this.loggedInMinHeight = 685;
    this.searchHeight = 112;
    this.borders = parseInt($("#mainframe").offset().top) * 2;
    this.mode = LPM.mode;
    this.speed = {
        tabs: "slow"
    };
    this.center = {};
    this.tabs = $('#magazine-header');
	this.button = {
		map: 		$("div#viewmode-map"),
		magazine:	$("div#viewmode-mag"),
		gossip:		$("div#viewmode-gossip")		
	};
};
ViewModeManager.prototype.init = function(){
    this.containerHeight.map = this.getMaxHeight();
	this.button.magazine.addClass("active");
};
ViewModeManager.prototype.getMaxHeight = function(){
    var height = parseInt($(window).height()) - this.borders - this.searchHeight + this.getBrowserOffset();
    if (height < this.minHeight) 
        height = this.minHeight;
    return height;
};
ViewModeManager.prototype.getSpeed = function(height){
    var newHeight = parseInt(height);
    var oldHeight = parseInt(this.container.height());
    var speed = Math.abs(newHeight - oldHeight) * 5;
    if (speed < 200) 
        speed = 700;
    return speed;
};
ViewModeManager.prototype.switchMode = function(mode){
    var height = 0;
    var speed = 0;
	for (var p in this.button)
		this.button[p].removeClass("active");
    this.center = LPM.map.getCenterAndZoom();
    LPM.map.clearMap();
    var self = this;
    if (this.getMode() != mode && $.inArray(mode, this.modes) > -1) {
        this.map.css({
            height: "100%"
        });
        LPM.setPageTitle(mode);
        
        switch (true) {
            case (mode == "map"):
                height = this.getMaxHeight();
                speed = this.getSpeed(height);
				this.button.map.addClass("active");
                var callback = function(){
                    log("map-level reached");
                    self.map.css({
                        height: height + "px"
                    });
                    self.setMode(mode);
                    LPM.map.checkResize();
                    self.hideMagazine();
                    self.hideGossip();
                    LPM.map.setCenterAndZoom(self.center.lat, self.center.lon, self.center.zoom);
                    LPM.enableFiltering();
                };
                break;
                
            case (mode == "magazine"):
                height = this.containerHeight.magazine;
                speed = this.getSpeed(height);
                this.showMagazine();
				this.button.magazine.addClass("active");
                var callback = function(){
                    log("mag-level reached");
                    self.map.css({
                        height: height + "px"
                    });
                    LPM.disableFiltering();
                    self.setMode(mode);
                    LPM.map.checkResize();
                    self.hideGossip();
                    LPM.map.setCenterAndZoom(self.center.lat, self.center.lon, self.center.zoom);
                };
                break;
                
            case (mode == "gossip"):
                height = this.containerHeight.gossip;
                speed = this.getSpeed(height);
                this.showMagazine();
				this.button.gossip.addClass("active");
                var callback = function(){
                    log("tratsch-level reached");
                    self.map.css({
                        height: height + "px"
                    });
                    self.setMode(mode);
                    LPM.disableFiltering();
                    LPM.map.checkResize();
                    self.showGossip();
                    LPM.map.setCenterAndZoom(self.center.lat, self.center.lon, self.center.zoom);
                };
                break;
                
            default:
                return false;
                break;
        }
        
        this.container.animate({
            height: height + "px",
            maxHeight: height + "px"
        }, speed, "swing", callback);
		
		LPM.tracking.track("modeChange");

    }
};
ViewModeManager.prototype.hideMagazine = function(){
    this.magazineContainer.addClass(this.modeClasses.map);
};
ViewModeManager.prototype.showMagazine = function(){
    this.magazineContainer.removeClass(this.modeClasses.map);
};
ViewModeManager.prototype.hideTabs = function(){
    this.tabs.hide(this.speed.tabs);
    this.tabs.addClass("passive");
};
ViewModeManager.prototype.showTabs = function(){
    this.tabs.removeClass("passive");
    this.tabs.show(this.speed.tabs);
};
ViewModeManager.prototype.hideGossip = function(){
    this.magazineContainer.removeClass(this.modeClasses.gossip);
    this.showTabs();
};
ViewModeManager.prototype.showGossip = function(){
    this.magazineContainer.addClass(this.modeClasses.gossip);
    this.hideTabs();
};
ViewModeManager.prototype.getMode = function(){
    return LPM.mode;
};
ViewModeManager.prototype.setMode = function(mode){
    if (mode) 
        LPM.setMode(mode);
};
ViewModeManager.prototype.getBrowserOffset = function(){
    switch (true) {
        case ($.browser.safari):
            return 30;
            break;
        default:
            return 0;
            break;
    }
};
// #######################################################
// ########################  History  ####################
// #######################################################
HistoryManager = function(){
    this.basket = [];
};
HistoryManager.prototype.init = function(man){
    this.manager = man;
    dhtmlHistory.initialize();
    dhtmlHistory.addListener(this.goBack);
};
HistoryManager.prototype.goBack = function(newLocation, historyData){
    if (!$.browser.safari) {
        var obj = LPM.history.getObjectFromBasket(newLocation)[0];
        switch(true) {
			case (obj && obj.mode == "magazine"):
				LPM.history.showPage(obj);
				break;
				
			case (obj && obj.mode == "map"):
				LPM.history.showZoom(obj);
				break;
			
			case (obj && obj.mode == "district"):
				LPM.history.showDistrict(obj);
				break;
				
			default:
				error("History without mode occured");
				// window.location.href = LPM.getGlobals().portalUrl; // need to be specified
				break;
		}    
    }
};

HistoryManager.prototype.showPage = function(page){
	if (page) {
		if (LPM.mode!="magazine") 
			LPM.toggleMode("magazine");
		if (page.hover) 
			LPM.showItemPage(page.id);// were in an item
		else {
			LHM.closeAll();
			LPM.map.setCenterAndZoom(page.lat,page.lon,page.zoom);
			LPM.showMagazinePage(page.id);// were in magazine
		}
	}
};
HistoryManager.prototype.showZoom = function(obj){
	if (obj) {
		LHM.closeAll();
		LPM.map.setCenterAndZoom(obj.lat,obj.lon,obj.zoom);
		if (LPM.mode!="map") 
			LPM.toggleMode("map");
	}
};
HistoryManager.prototype.showDistrict = function(obj){
	if (obj) {
		LHM.closeAll();
		LPM.map.setCenterAndZoom(obj.lat,obj.lon,obj.zoom);
		LPM.nav.onDistrictChosen({
                name : obj.district,
                lat : obj.lat,
                lon : obj.lon
            });
	}
};
HistoryManager.prototype.addPage = function(page){
	if (LPM.mode=="magazine" && page.id) {
		if(page.blurClass && page.blurClass=="black")
			return false;

		var obj = LPM.map.getCenterAndZoom();
		obj.mode = "magazine";
		if (page.container_id)
			obj.hover = true;
		obj.id = page.id;
		this.basket.push(obj);
	    this.add(obj.id);	
	}
};
HistoryManager.prototype.addZoom = function(){
	if (LPM.mode=="map") {
	    var obj = LPM.map.getCenterAndZoom();
		obj.mode = "map";
		obj.id = Math.round(Math.random()*100) + "." + obj.zoom;
		this.basket.push(obj);
	    this.add(obj.id);	
	}
};
HistoryManager.prototype.addDistrict = function(district){
	function _cleanUrl(str){
		str = str.replace(/ü/g, "ue").replace(/ä/g, "ae").replace(/ö/g, "oe");
		return str;
	}
	LPM.setPageTitle(district);
	var obj = LPM.map.getCenterAndZoom();
	obj.mode = "district";
	obj.district = district;
	obj.id = _cleanUrl(district);
	this.basket.push(obj);
    this.add(obj.id);	
};
HistoryManager.prototype.add = function(str){
    if (!$.browser.safari && str)
		dhtmlHistory.add(str, {
        	message: document.title
    	});
    this.scrollToTop();
};
HistoryManager.prototype.getObjectFromBasket = function(id){
    var obj = jQuery.grep(this.basket, function(n, i){
        return (n.id == id);
    });
    return obj;
};
HistoryManager.prototype.scrollToTop = function(){
    window.setTimeout("window.scrollTo(0,0)", 2);
};

//#######################################################
//#############  Mother's little Helper #################
//#######################################################

DOMManager = function(){
};
DOMManager.prototype.getHeight = function(){
    var topwrapper = {
        offset: parseInt($("#topwrapper").offset().top),
        height: parseInt($("#topwrapper").height())
    };
    var footer = {
        offset: parseInt($("#mainFooter").offset().top),
        height: parseInt($("#mainFooter").height())
    };
    var stage = parseInt($(window).height());
    
    switch (true) {
        case ($.browser.mozilla):
            var difference = 25;
            break;
        case ($.browser.safari):
            var difference = 31;
            break;
        case ($.browser.konqueror):
            var difference = 25;
            break;
        case ($.browser.msie && $.browser.version < 7):
            var difference = 8;
            break;
        case ($.browser.msie):
            var difference = 18;
            break;
        default:
            var difference = 25;
            break;
    }
    
    var wrapper = stage - (topwrapper.offset + topwrapper.height + footer.height + difference);
    if ($.browser.opera) 
        wrapper = stage - 149;
    return wrapper;
};
DOMManager.prototype.resize = function(force){
    if (force || !operating.resizingMap) {
        var wrapper = this.getHeight();
        var container = $('div#mapcontainer');
        var rest = parseInt($(document).height()) - parseInt($(window).height()); //Computimg the difference
        log("Rest: " + rest);
        if (LPM.mode == "map") {
        
            container.css({
                height: (wrapper) + "px"
            });
            if ($.browser.msie) {
                container.css({
                    minHeight: (wrapper) + "px"
                });
                $("body").css({
                    minHeight: (wrapper + 10) + "px"
                });
            }
            $("#wrapper").css({
                minHeight: (wrapper + 10) + "px"
            });
        }
        log("neuer Rest: " + (parseInt($(document).height()) - parseInt($(window).height())));
        map.checkResize();
    }
};

function mbLoadAnyScript(url) {
	var head = document.getElementsByTagName("head")[0];
	var script = document.createElement("script");
	script.src = url;
	head.appendChild(script);
	script.onload = function() {
		log("script: " + url + " successfully loaded");
		head.removeChild(script);
	}
}

function mbgetPosition(obj){
    var pos = {
        x: 0,
        y: 0
    };
    do {
        pos.x += obj.offsetLeft;
        pos.y += obj.offsetTop;
    }
    while (obj == obj.offsetParent);
    return pos;
}

function mbgetNotePosition(obj){
    var mousePos = mbgetPosition(document.getElementById(obj));
    var pos_karte = mbgetPosition(document.getElementById("karte"));
    
    var npos = {
        x: 0,
        y: 0
    };
    
    var width_karte = parseInt(document.getElementById("karte").offsetWidth);
    var height_karte = parseInt(document.getElementById("karte").offsetHeight);
    
    if ((mousePos.x > pos_karte.x) &&
    (mousePos.x < (pos_karte.x + width_karte)) &&
    (mousePos.y > pos_karte.y) &&
    (mousePos.y < (pos_karte.y + height_karte))) {
        npos.x = mousePos.x - pos_karte.x;
        npos.y = mousePos.y - pos_karte.y;
    }
    return npos;
}

function mbShorten(string, counts){
    var strArray = string.split(" ");
    if (strArray.length > counts) {
        strArray.splice(counts, strArray.length - counts);
        strArray.push("...");
    }
    return strArray.join(" ");
}

function mbMorphUrlString(string){
    var strArray = string.split("/").reverse();
    return strArray[1] + "." + strArray[0];
}

function mbMakeLine(koords, typ, color){
    color = color || '#ff0000';
    if (koords) 
        mbDrawRectangleArray = koords;
    if (typ == 'kill') 
        mbDrawRectangleArray = new Array();
    if (typ) 
        mbDrawRectangleType = typ;
    if (mbDrawRectangleArray.length > 2) {
        if (!mbDrawRectangleType) 
            mbDrawRectangleType = "rect";
        var pts = [];
        var ptc = 0;
        for (i = 0; i < mbDrawRectangleArray.length; i = i + 2) {
            pts[ptc] = new GLatLng(parseFloat(mbDrawRectangleArray[i]), parseFloat(mbDrawRectangleArray[i + 1]));
            ptc++;
        }
        if (mbDrawRectangleType == "rect") 
            map.addOverlay(new GPolygon(pts, color, 5, '0.2', "#ffff00", '0.2'));
        if (mbDrawRectangleType == "line") 
            map.addOverlay(new GPolyline(pts, color, 2, '0.8'));
    }
}

function mbExtractBubbleData(BId){
    var url = LPM.getGlobals().portalUrl + "/focus/" + BId + "/pin/content/resolvebubble";
    $("#historyform").append("<div id='temp_bubble'></div>");
    mbHPLoaded = true;
    $.get(url, function(data){
        $("#temp_bubble").append(data);
        var tempbubble = $("#d_bubble_" + BId);
        log($("#d_bubble_" + BId, data).attr("id"));
        var bubbleObject = {
            gender: false,
            type: tempbubble.attr("ajax:type"),
            lat: tempbubble.attr("ajax:lat"),
            lon: tempbubble.attr("ajax:lon"),
            title: tempbubble.attr("ajax:title"),
            id: tempbubble.attr("ajax:id")
        };
        if (bubbleObject.type == "homefolder") 
            bubbleObject.gender = tempbubble.attr("ajax:subtype");
        log("bubble: ", bubbleObject);
        $("#temp_bubble").remove();
        log("Deeplink-Found: " + bubbleObject.id + " " + bubbleObject.lat + " " + bubbleObject.lon + " " + bubbleObject.type + " " + bubbleObject.gender + " " + bubbleObject.title);
        mbCreatePin(bubbleObject.lat, bubbleObject.lon, bubbleObject.type, bubbleObject.gender, bubbleObject.id, bubbleObject.title, false, true, false);
    });
}

function mbHideCopyright(MInstance){
    $('#' + MInstance + ' > div:eq(1)').css({
        display: "none"
    });
}

function animate_wait(state){
    if (state == 1 && animator_status < 1) {
        animator_status = 1;
        log("Wait Animator (" + LPM.getGlobals().portalUrl + "/@@/img/anim-loading.gif) started...");
        $('#sync_animator').fadeTo('fast', 0.4);
        $('#sync_animator').css({
            cursor: 'progress'
        });
    }
    else {
        log("Wait Animator stopped...");
        animator_status = 0;
        $('#sync_animator').fadeOut('fast');
        $('#sync_animator').css({
            display: "none"
        });
    }
}

function mbDisableDebugging(){
    if (mbDebug) {
        if (mbDebug != "force" && window.location.hostname.toLowerCase() == "www.meinberlin.de") {
            mbDebug = false;
        }
    }
}

function array_try(arrayname, suchindex){
    try {
        return arrayname[suchindex];
    } 
    catch (e) {
        return 0;
    }
}

function mbGetHash(hashString){
    var hashwerte = new Array();
    hashwerte['pin'] = ""; // if itempage / bubble
    hashwerte['lat'] = "";
    hashwerte['lon'] = "";
    hashwerte['zoom'] = "";
    hashwerte['oldurl'] = "";
    
    hashwerte['map'] = "";
    hashwerte['page'] = "";
    hashwerte['home'] = "";
    hashwerte['init'] = "";
    
    if (window.location.href.indexOf("#") > -1) {
        if (hashString) {
            var hash = hashString;
        }
        else 
            if ($.browser.msie && parent['rshHistoryFrame'].mbDhtmlHash()) {
                var hash = parent['rshHistoryFrame'].mbDhtmlHash();
            }
            else {
                var hash = window.location.hash.substring(1, window.location.hash.length);
            }
        
        if (hash.length > 0) {
            var history_temp = hash.split("&");
            var history = new Array();
            for (var i = 0; i < history_temp.length; i++) {
                temp = history_temp[i].split("=");
                history[temp[0]] = temp[1];
            }
        }
        var empty = {};
        var settings = jQuery.extend(empty, hashwerte, history);
        return settings;
    }
    else {
        return false;
    }
    return hashwerte;
}

function mbRound(wert, laenge){
    return Math.round(parseFloat(wert) * (Math.pow(10, parseInt(laenge)))) / Math.pow(10, parseInt(laenge));
}

// Objekte Dumpen - Debugging only please
var MAX_DUMP_DEPTH = 10;
function dumpObj(obj){
    var name = "Objekt";
    var indent = "+++";
    var depth = 10;
    if (depth > MAX_DUMP_DEPTH) {
        return indent + name + ": <Maximum Depth Reached>\n";
    }
    if (typeof obj == "object") {
        var child = null;
        var output = indent + name + "\n";
        indent += "\t";
        for (var item in obj) {
            try {
                child = obj[item];
            } 
            catch (e) {
                child = "<Unable to Evaluate>";
            }
            if (typeof child == "object") {
                output += dumpObj(child, item, indent, depth + 1);
            }
            else {
                output += indent + item + ": " + child + "\n";
            }
        }
        return output;
    }
    else {
        return obj;
    }
}

/** The JSON class is copyright 2005 JSON.org. */
Array.prototype.______array = '______array';

var JSON = {
    org: 'http://www.JSON.org',
    copyright: '(c)2005 JSON.org',
    license: 'http://www.crockford.com/JSON/license.html',

    stringify: function (arg) {
        var c, i, l, s = '', v;

        switch (typeof arg) {
        case 'object':
            if (arg) {
                if (arg.______array == '______array') {
                    for (i = 0; i < arg.length; ++i) {
                        v = this.stringify(arg[i]);
                        if (s) {
                            s += ',';
                        }
                        s += v;
                    }
                    return '[' + s + ']';
                } else if (typeof arg.toString != 'undefined') {
                    for (i in arg) {
                        v = arg[i];
                        if (typeof v != 'undefined' && typeof v != 'function') {
                            v = this.stringify(v);
                            if (s) {
                                s += ',';
                            }
                            s += this.stringify(i) + ':' + v;
                        }
                    }
                    return '{' + s + '}';
                }
            }
            return 'null';
        case 'number':
            return isFinite(arg) ? String(arg) : 'null';
        case 'string':
            l = arg.length;
            s = '"';
            for (i = 0; i < l; i += 1) {
                c = arg.charAt(i);
                if (c >= ' ') {
                    if (c == '\\' || c == '"') {
                        s += '\\';
                    }
                    s += c;
                } else {
                    switch (c) {
                        case '\b':
                            s += '\\b';
                            break;
                        case '\f':
                            s += '\\f';
                            break;
                        case '\n':
                            s += '\\n';
                            break;
                        case '\r':
                            s += '\\r';
                            break;
                        case '\t':
                            s += '\\t';
                            break;
                        default:
                            c = c.charCodeAt();
                            s += '\\u00' + Math.floor(c / 16).toString(16) +
                                (c % 16).toString(16);
                    }
                }
            }
            return s + '"';
        case 'boolean':
            return String(arg);
        default:
            return 'null';
        }
    },
    parse: function (text) {
        var at = 0;
        var ch = ' ';

        function error(m) {
            throw {
                name: 'JSONError',
                message: m,
                at: at - 1,
                text: text
            };
        }

        function next() {
            ch = text.charAt(at);
            at += 1;
            return ch;
        }

        function white() {
            while (ch != '' && ch <= ' ') {
                next();
            }
        }

        function str() {
            var i, s = '', t, u;

            if (ch == '"') {
outer:          while (next()) {
                    if (ch == '"') {
                        next();
                        return s;
                    } else if (ch == '\\') {
                        switch (next()) {
                        case 'b':
                            s += '\b';
                            break;
                        case 'f':
                            s += '\f';
                            break;
                        case 'n':
                            s += '\n';
                            break;
                        case 'r':
                            s += '\r';
                            break;
                        case 't':
                            s += '\t';
                            break;
                        case 'u':
                            u = 0;
                            for (i = 0; i < 4; i += 1) {
                                t = parseInt(next(), 16);
                                if (!isFinite(t)) {
                                    break outer;
                                }
                                u = u * 16 + t;
                            }
                            s += String.fromCharCode(u);
                            break;
                        default:
                            s += ch;
                        }
                    } else {
                        s += ch;
                    }
                }
            }
            error("Bad string");
        }

        function arr() {
            var a = [];

            if (ch == '[') {
                next();
                white();
                if (ch == ']') {
                    next();
                    return a;
                }
                while (ch) {
                    a.push(val());
                    white();
                    if (ch == ']') {
                        next();
                        return a;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad array");
        }

        function obj() {
            var k, o = {};

            if (ch == '{') {
                next();
                white();
                if (ch == '}') {
                    next();
                    return o;
                }
                while (ch) {
                    k = str();
                    white();
                    if (ch != ':') {
                        break;
                    }
                    next();
                    o[k] = val();
                    white();
                    if (ch == '}') {
                        next();
                        return o;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad object");
        }

        function num() {
            var n = '', v;
            if (ch == '-') {
                n = '-';
                next();
            }
            while (ch >= '0' && ch <= '9') {
                n += ch;
                next();
            }
            if (ch == '.') {
                n += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    n += ch;
                }
            }
            if (ch == 'e' || ch == 'E') {
                n += 'e';
                next();
                if (ch == '-' || ch == '+') {
                    n += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    n += ch;
                    next();
                }
            }
            v = +n;
            if (!isFinite(v)) {
                error("Bad number");
            } else {
                return v;
            }
        }

        function word() {
            switch (ch) {
                case 't':
                    if (next() == 'r' && next() == 'u' && next() == 'e') {
                        next();
                        return true;
                    }
                    break;
                case 'f':
                    if (next() == 'a' && next() == 'l' && next() == 's' &&
                            next() == 'e') {
                        next();
                        return false;
                    }
                    break;
                case 'n':
                    if (next() == 'u' && next() == 'l' && next() == 'l') {
                        next();
                        return null;
                    }
                    break;
            }
            error("Syntax error");
        }

        function val() {
            white();
            switch (ch) {
                case '{':
                    return obj();
                case '[':
                    return arr();
                case '"':
                    return str();
                case '-':
                    return num();
                default:
                    return ch >= '0' && ch <= '9' ? num() : word();
            }
        }

        return val();
    }
};

/* jQuery Calendar v2.7
   Written by Marc Grabanski (m@marcgrabanski.com) and enhanced by Keith Wood (kbwood@iprimus.com.au).

   Date Range Picker mods provided by Filament Group, Inc
   ** NOTE! The portions of this script that are modified by Filament Group are not written for flexible reuse but rather for a specific implementation. 
   * We welcome any modification to package this in a more reusable plugin style.

   Copyright (c) 2007 Marc Grabanski (http://marcgrabanski.com/code/jquery-calendar)
   Dual licensed under the GPL (http://www.gnu.org/licenses/gpl-3.0.txt) and 
   CC (http://creativecommons.org/licenses/by/3.0/) licenses. "Share or Remix it but please Attribute the authors."
   Date: 09-03-2007  */

/* PopUp Calendar manager.
   Use the singleton instance of this class, popUpCal, to interact with the calendar.
   Settings for (groups of) calendars are maintained in an instance object
   (PopUpCalInstance), allowing multiple different settings on the same page. */
 
/*	Changed appearance and language by using default interfaces given by that script
 *	Date: 29.05.08 
 */

// ################################ Attention ! #####################################
// the following few lines need to be called by applicationmanager-script
// ##################################################################################






function PopUpCal() {
	this._nextId = 0; // Next ID for a calendar instance
	this._inst = []; // List of instances indexed by ID
	this._curInst = null; // The current instance in use
	this._disabledInputs = []; // List of calendar inputs that have been disabled
	this._popUpShowing = false; // True if the popup calendar is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		clearText: 'Löschen', // Display text for clear link
		closeText: 'Schließen', // Display text for close link
		prevText: '&lt;Prev', // Display text for previous month link
		nextText: 'Next&gt;', // Display text for next month link
		currentText: 'Heute', // Display text for current month link
		dayNames: ['So','Mo','Di','Mi','Do','Fr','Sa'], // Names of days starting at Sunday
		monthNames: ['Januar','Februar','März','April','Mai','Juni',
			'Juli','August','September','Oktober','November','Dezember'], // Names of months
		dateFormat: 'MDY/' // First three are day, month, year in the required order,
			// fourth (optional) is the separator, e.g. US would be 'MDY/', ISO would be 'YMD-'
	};
	this._defaults = { // Global defaults for all the calendar instances
		autoPopUp: 'focus', // 'focus' for popup on focus,
			// 'button' for trigger button, or 'both' for either
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		closeAtTop: false, // True to have the clear/close at the top,
			// false to have them at the bottom
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		changeMonth: true, // True if month can be selected directly, false if only prev/next
		changeYear: true, // True if year can be selected directly, false if only prev/next
		monthYearMenu: true, //True if a mixed month/year menu is desired
		yearRange: '-1:+1', // Range of years to display in drop-down,
			// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
		firstDay: 1, // The first day of the week, Sun = 0, Mon = 1, ...
		//changeFirstDay: true, // True to click on day name to change, false to remain as set
		showOtherMonths: true, // True to show dates in other months, false to leave blank
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		speed: 'fast', // Speed of display/closure
		customDate: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not,
			// [1] = custom CSS class name(s) or '', e.g. popUpCal.noWeekends
		fieldSettings: null, // Function that takes an input field and
			// returns a set of custom settings for the calendar
		onSelect: null, // Define a callback function when a date is selected
		dateRange: false
	};
	$.extend(this._defaults, this.regional['']);
	$(document).click(this._checkExternalClick);
}

$.extend(PopUpCal.prototype, {
	/* Class name added to elements to indicate already configured with a calendar. */
	markerClassName: 'hasCalendar',
	
	/* Register a new calendar instance - with custom settings. */
	_register: function(inst) {
		var id = this._nextId++;
		this._inst[id] = inst;
		this._calendarDiv = $('<div id="calendar_div_'+id+'" class="calendar_div"></div>');
		return id;
	},

	/* Retrieve a particular calendar instance based on its ID. */
	_getInst: function(id) {
		return this._inst[id] || id;
	},

	/* Override the default settings for all instances of the calendar. 
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return void */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
	},

	/* Handle keystrokes. */
	_doKeyDown: function(e) {
		var inst = popUpCal._getInst(this._calId);
		if (popUpCal._popUpShowing) {
			switch (e.keyCode) {
				case 9:  popUpCal.hideCalendar(inst, '');
						break; // hide on tab out
				case 13: popUpCal._selectDate(inst);
						break; // select the value on enter
				case 27: popUpCal.hideCalendar(inst, inst._get('speed'));
						break; // hide on escape
				case 33: popUpCal._adjustDate(inst, -1, (e.ctrlKey ? 'Y' : 'M'));
						break; // previous month/year on page up/+ ctrl
				case 34: popUpCal._adjustDate(inst, +1, (e.ctrlKey ? 'Y' : 'M'));
						break; // next month/year on page down/+ ctrl
				case 35: if (e.ctrlKey) popUpCal._clearDate(inst);
						break; // clear on ctrl+end
				case 36: if (e.ctrlKey) popUpCal._gotoToday(inst);
						break; // current on ctrl+home
				case 37: if (e.ctrlKey) popUpCal._adjustDate(inst, -1, 'D');
						break; // -1 day on ctrl+left
				case 38: if (e.ctrlKey) popUpCal._adjustDate(inst, -7, 'D');
						break; // -1 week on ctrl+up
				case 39: if (e.ctrlKey) popUpCal._adjustDate(inst, +1, 'D');
						break; // +1 day on ctrl+right
				case 40: if (e.ctrlKey) popUpCal._adjustDate(inst, +7, 'D');
						break; // +1 week on ctrl+down
			}
		}
		else if (e.keyCode == 36 && e.ctrlKey) { // display the calendar on ctrl+home
			popUpCal.showFor(this);
		}
	},

	/* Filter entered characters. */
	_doKeyPress: function(e) {
		var inst = popUpCal._getInst(this._calId);
		var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
		return (chr < ' ' || chr == inst._get('dateFormat').charAt(3) ||
			(chr >= '0' && chr <= '9')); // only allow numbers and separator
	},

	/* Attach the calendar to an input field. */
	_connectCalendar: function(target, inst) {
		var input = $(target);
		input.addClass('calendarInput');
		if (this._hasClass(input, this.markerClassName)) {
			return;
		}
		var appendText = inst._get('appendText');
		if (appendText) {
			input.after('<span class="calendar_append">' + appendText + '</span>');
		}
		

		
		input.after(inst._calendarDiv);
		
		var autoPopUp = inst._get('autoPopUp');
		if (autoPopUp == 'focus' || autoPopUp == 'both') { // pop-up calendar when in the marked field
			input.focus(this.showFor);
		}
		if (autoPopUp == 'button' || autoPopUp == 'both') { // pop-up calendar when button clicked
			var buttonText = inst._get('buttonText');
			var buttonImage = inst._get('buttonImage');
			var buttonImageOnly = inst._get('buttonImageOnly');
			var trigger = $(buttonImageOnly ? '<img class="calendar_trigger" src="' +
				buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
				'<button type="button" class="calendar_trigger">' + (buttonImage != '' ?
				'<img src="' + buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
				buttonText) + '</button>');
			input.wrap('<span class="calendar_wrap"></span>').after(trigger);
			trigger.click(this.showFor);
		}
		input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress);
		input[0]._calId = inst._id;
	},

	/* Attach an inline calendar to a div. */
	_inlineCalendar: function(target, inst) {
		var input = $(target);
		if (this._hasClass(input, this.markerClassName)) {
			return;
		}
		input.addClass(this.markerClassName).append(inst._calendarDiv);
		input[0]._calId = inst._id;
	},

	/* Does this element have a particular class? */
	_hasClass: function(element, className) {
		var classes = element.attr('class');
		return (classes && classes.indexOf(className) > -1);
	},

	/* Pop-up the calendar in a "dialog" box.
	   @param  dateText  string - the initial date to display (in the current format)
	   @param  onSelect  function - the function(dateText) to call when a date is selected
	   @param  settings  object - update the dialog calendar instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen
			leave empty for default (screen centre)
	   @return void */
	dialogCalendar: function(dateText, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			inst = this._dialogInst = new PopUpCalInstance({}, false);
			this._dialogInput = $('<input type="text" size="1" style="position: absolute; top: -100px;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			this._dialogInput[0]._calId = inst._id;
		}
		extendRemove(inst._settings, settings || {});
		this._dialogInput.val(dateText);
		
		/*	Cross Browser Positioning */
		if (self.innerHeight) { // all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		} 
		this._pos = pos || // should use actual width/height below
			[(windowWidth / 2) - 100, (windowHeight / 2) - 100];

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
		inst._settings.onSelect = onSelect;
		this._inDialog = true;
		this._calendarDiv.addClass('calendar_dialog');
		this.showFor(this._dialogInput[0]);
		if ($.blockUI) {
			$.blockUI(this._calendarDiv);
		}
	},

	/* Enable the input field(s) for entry.
	   @param  inputs  element/object - single input field or jQuery collection of input fields
	   @return void */
	enableFor: function(inputs) {
		inputs = (inputs.jquery ? inputs : $(inputs));
		inputs.each(function() {
			this.disabled = false;
			$('../button.calendar_trigger', this).each(function() { this.disabled = false; });
			$('../img.calendar_trigger', this).css({opacity:'1.0',cursor:''});
			var $this = this;
			popUpCal._disabledInputs = $.map(popUpCal._disabledInputs,
				function(value) { return (value == $this ? null : value); }); // delete entry
		});
	},

	/* Disable the input field(s) from entry.
	   @param  inputs  element/object - single input field or jQuery collection of input fields
	   @return void */
	disableFor: function(inputs) {
		inputs = (inputs.jquery ? inputs : $(inputs));
		inputs.each(function() {
			this.disabled = true;
			$('../button.calendar_trigger', this).each(function() { this.disabled = true; });
			$('../img.calendar_trigger', this).css({opacity:'0.5',cursor:'default'});
			var $this = this;
			popUpCal._disabledInputs = $.map(popUpCal._disabledInputs,
				function(value) { return (value == $this ? null : value); }); // delete entry
			popUpCal._disabledInputs[popUpCal._disabledInputs.length] = this;
		});
	},

	/* Update the settings for a calendar attached to an input field or division.
	   @param  control   element - the input field or div/span attached to the calendar or
	                     string - the ID or other jQuery selector of the input field
	   @param  settings  object - the new settings to update
	   @return void */
	reconfigureFor: function(control, settings) {
		control = (typeof control == 'string' ? $(control)[0] : control);
		var inst = this._getInst(control._calId);
		if (inst) {
			extendRemove(inst._settings, settings || {});
			this._updateCalendar(inst);
		}
	},

	/* Set the date for a calendar attached to an input field or division.
	   @param  control  element - the input field or div/span attached to the calendar
	   @param  date     Date - the new date
	   @return void */
	setDateFor: function(control, date) {
		var inst = this._getInst(control._calId);
		if (inst) {
			inst._setDate(date);
		}
	},

	/* Retrieve the date for a calendar attached to an input field or division.
	   @param  control  element - the input field or div/span attached to the calendar
	   @return Date - the current date */
	getDateFor: function(control) {
		var inst = this._getInst(control._calId);
		return (inst ? inst._getDate() : null);
	},

	/* Pop-up the calendar for a given input field.
	   @param  target  element - the input field attached to the calendar
	   @return void */
	showFor: function(target) {
		var input = (target.nodeName && target.nodeName.toLowerCase() == 'input' ? target : this);
		if (input.nodeName.toLowerCase() != 'input') { // find from button/image trigger
			input = $('input', input.parentNode)[0];
		}
		if (popUpCal._lastInput == input) { // already here
			return;
		}
		for (var i = 0; i < popUpCal._disabledInputs.length; i++) {  // check not disabled
			if (popUpCal._disabledInputs[i] == input) {
				return;
			}
		}
		var inst = popUpCal._getInst(input._calId);
		var fieldSettings = inst._get('fieldSettings');
		extendRemove(inst._settings, (fieldSettings ? fieldSettings(input) : {}));
		popUpCal.hideCalendar(inst, '');
		popUpCal._lastInput = input;
		inst._setDateFromField(input);
		if (popUpCal._inDialog) { // hide cursor
			input.value = '';
		}
		/*
		if (!popUpCal._pos) { // position below input
			popUpCal._pos = popUpCal._findPos(input);
			popUpCal._pos[1] += input.offsetHeight;
		}
		inst._calendarDiv.css('position', (popUpCal._inDialog && $.blockUI ? 'static' : 'absolute')).
			css('left', popUpCal._pos[0] + 'px').css('top', popUpCal._pos[1] + 'px');
			*/
		popUpCal._pos = null;
		popUpCal._showCalendar(inst);
	},

	/* Construct and display the calendar. */
	_showCalendar: function(id) {
		var inst = this._getInst(id);
		popUpCal._updateCalendar(inst);
		if (!inst._inline) {
			var speed = inst._get('speed');
			inst._calendarDiv.show(speed, function() {
				popUpCal._popUpShowing = true;
				popUpCal._afterShow(inst);
			});
			if (speed == '') {
				popUpCal._popUpShowing = true;
				popUpCal._afterShow(inst);
			}
			if (inst._input[0].type != 'hidden' && !$.browser.msie) {
				inst._input[0].focus();
			}
			this._curInst = inst;
		}
	},

	/* Generate the calendar content. */
	_updateCalendar: function(inst, visibility) {
		inst._calendarDiv.html(inst._generateCalendar());
		if (inst._input && inst._input[0].type != 'hidden' && visibility != 'hidden') {
			if (!$.browser.msie) inst._input[0].focus();
		}
	},

	/* Tidy up after displaying the calendar. */
	_afterShow: function(inst) {
		if ($.browser.msie) { // fix IE < 7 select problems
			$('#calendar_cover').css({width: inst._calendarDiv[0].offsetWidth + 4,
				height: inst._calendarDiv[0].offsetHeight + 4});
		}
		// re-position on screen if necessary
		var calDiv = inst._calendarDiv[0];
		var pos = popUpCal._findPos(inst._input[0]);
		// Get browser width and X value (IE6+, FF, Safari, Opera)
		if( typeof( window.innerWidth ) == 'number' ) {
			browserWidth = window.innerWidth;
		} else {
			browserWidth = document.documentElement.clientWidth;
		}
		if ( document.documentElement && (document.documentElement.scrollLeft)) {
			browserX = document.documentElement.scrollLeft;	
		} else {
			browserX = document.body.scrollLeft;
		}
		// Reposition calendar if outside the browser window.
		if ((calDiv.offsetLeft + calDiv.offsetWidth) >
				(browserWidth + browserX) ) {
			inst._calendarDiv.css('left', (pos[0] + inst._input[0].offsetWidth - calDiv.offsetWidth) + 'px');
		}
		// Get browser height and Y value (IE6+, FF, Safari, Opera)
		if( typeof( window.innerHeight ) == 'number' ) {
			browserHeight = window.innerHeight;
		} else {
			browserHeight = document.documentElement.clientHeight;
		}
		if ( document.documentElement && (document.documentElement.scrollTop)) {
			browserTopY = document.documentElement.scrollTop;
		} else {
			browserTopY = document.body.scrollTop;
		}
		// Reposition calendar if outside the browser window.
		if ((calDiv.offsetTop + calDiv.offsetHeight) >
				(browserTopY + browserHeight) ) {
			inst._calendarDiv.css('top', (pos[1] - calDiv.offsetHeight) + 'px');
		}
	},

	/* Hide the calendar from view.
	   @param  id     string/object - the ID of the current calendar instance,
			or the instance itself
	   @param  speed  string - the speed at which to close the calendar
	   @return void */
	hideCalendar: function(id, speed) {
		var inst = this._getInst(id);
		var dateRange = inst._get('dateRange');
		if(dateRange == false){
			var inst = this._getInst(id);
			if (popUpCal._popUpShowing) {
				speed = (speed != null ? speed : inst._get('speed'));
				inst._calendarDiv.hide(speed, function() {
					popUpCal._tidyDialog(inst);
				});
				if (speed == '') {
					popUpCal._tidyDialog(inst);
				}
				popUpCal._popUpShowing = false;
				popUpCal._lastInput = null;
				inst._settings.prompt = null;
				if (popUpCal._inDialog) {
					popUpCal._dialogInput.css('position', 'absolute').
						css('left', '0px').css('top', '-100px');
					if ($.blockUI) {
						$.unblockUI();
						$('body').append(this._calendarDiv);
					}
				}
				popUpCal._inDialog = false;
			}
			popUpCal._curInst = null;
		}
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst._calendarDiv.removeClass('calendar_dialog');
		$('.calendar_prompt', inst._calendarDiv).remove();
	},

	/* Close calendar if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!popUpCal._curInst) {
			return;
		}
		var target = $(event.target);
		if( (target.parents(".calendar_div").length == 0)
			&& (target.attr('class') != 'calendar_trigger')
			&& popUpCal._popUpShowing 
			&& !(popUpCal._inDialog && $.blockUI) )
		{
			popUpCal.hideCalendar(popUpCal._curInst, '');
		}
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var inst = this._getInst(id);
		inst._adjustDate(offset, period);
		this._updateCalendar(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var date = new Date();
		var inst = this._getInst(id);
		inst._selectedDay = date.getDate();
		inst._selectedMonth = date.getMonth();
		inst._selectedYear = date.getFullYear();
		this._adjustDate(inst);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var inst = this._getInst(id);
		inst._selectingMonthYear = false;
		if(period == 'MY'){
			inst['_selectedMonth'] = 	select.id.split('_')[0] - 0;
			inst['_selectedYear'] = 	select.id.split('_')[1] - 0;
			
		}
		else inst[period == 'M' ? '_selectedMonth' : '_selectedYear'] = select.options[select.selectedIndex].value - 0;
		this._adjustDate(inst);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var inst = this._getInst(id);
		if (inst._input && inst._selectingMonthYear && !$.browser.msie) {
			inst._input[0].focus();
		}
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for changing the first week day. */
	_changeFirstDay: function(id, a) {
		var inst = this._getInst(id);
		var dayNames = inst._get('dayNames');
		var value = a.firstChild.nodeValue;
		for (var i = 0; i < 7; i++) {
			if (dayNames[i] == value) {
				inst._settings.firstDay = i;
				break;
			}
		}
		this._updateCalendar(inst);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, td) {
		var inst = this._getInst(id);
		inst._selectedDay = $("a", td).html();
		this._selectDate(id);
	},

	/* Erase the input field and hide the calendar. */
	_clearDate: function(id) {
		this._selectDate(id, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var inst = this._getInst(id);
		dateStr = (dateStr != null ? dateStr : inst._formatDate());
		if (inst._input) {
			inst._input.val(dateStr);
		}
		var onSelect = inst._get('onSelect');
		if (onSelect) {
			onSelect(dateStr, inst);  // trigger custom callback
		}
		else {
			inst._input.trigger('change'); // fire the change event
		}
		if (inst._inline) {
			this._updateCalendar(inst);
		}
		else {
			this.hideCalendar(inst, inst._get('speed'));
		}
	},

	/* Set as customDate function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},

	/* Find an object's position on the screen. */
	_findPos: function(obj) {
		while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
			obj = obj.nextSibling;
		}
		var curleft = curtop = 0;
		if (obj && obj.offsetParent) {
			curleft = obj.offsetLeft;
			curtop = obj.offsetTop;
			while (obj = obj.offsetParent) {
				var origcurleft = curleft;
				curleft += obj.offsetLeft;
				if (curleft < 0) {
					curleft = origcurleft;
				}
				curtop += obj.offsetTop;
			}
		}
		return [curleft,curtop];
	}
});

/* Individualised settings for calendars applied to one or more related inputs.
   Instances are managed and manipulated through the PopUpCal manager. */
function PopUpCalInstance(settings, inline) {
	this._id = popUpCal._register(this);
	this._selectedDay = 0;
	this._selectedMonth = 0; // 0-11
	this._selectedYear = 0; // 4-digit year
	this._input = null; // The attached input field
	this._inline = inline; // True if showing inline, false if used in a popup
	this._calendarDiv = (!inline ? popUpCal._calendarDiv :
		$('<div id="calendar_div_' + this._id + '" class="calendar_inline"></div>'));
	// customise the calendar object - uses manager defaults if not overridden
	this._settings = extendRemove({}, settings || {}); // clone
	if (inline) {
		this._setDate(this._getDefaultDate());
	}
}

$.extend(PopUpCalInstance.prototype, {
	/* Get a setting value, defaulting if necessary. */
	_get: function(name) {
		return (this._settings[name] != null ? this._settings[name] : popUpCal._defaults[name]);
	},

	/* Parse existing date and initialise calendar. */
	_setDateFromField: function(input) {
		this._input = $(input);
		var dateFormat = this._get('dateFormat');
		var currentDate = this._input.val().split(dateFormat.charAt(3));
		if (currentDate.length == 3) {
			this._currentDay = parseInt(currentDate[dateFormat.indexOf('D')], 10);
			this._currentMonth = parseInt(currentDate[dateFormat.indexOf('M')], 10) - 1;
			this._currentYear = parseInt(currentDate[dateFormat.indexOf('Y')], 10);
		}
		else {
			var date = this._getDefaultDate();
			this._currentDay = date.getDate();
			this._currentMonth = date.getMonth();
			this._currentYear = date.getFullYear();
		}
		this._selectedDay = this._currentDay;
		this._selectedMonth = this._currentMonth;
		this._selectedYear = this._currentYear;
		this._adjustDate();
	},
	
	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function() {
		var offsetDate = function(offset) {
			var date = new Date();
			date.setDate(date.getDate() + offset);
			return date;
		};
		var defaultDate = this._get('defaultDate');
		return (defaultDate == null ? new Date() :
			(typeof defaultDate == 'number' ? offsetDate(defaultDate) : defaultDate));
	},

	/* Set the date directly. */
	_setDate: function(date) {
		this._selectedDay = this._currentDay = date.getDate();
		this._selectedMonth = this._currentMonth = date.getMonth();
		this._selectedYear = this._currentYear = date.getFullYear();
		this._adjustDate();
	},

	/* Retrieve the date directly. */
	_getDate: function() {
		return new Date(this._currentYear, this._currentMonth, this._currentDay);
	},

	/* Generate the HTML for the current state of the calendar. */
	_generateCalendar: function() {
		var today = new Date();
		today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time
		// build the calendar HTML
		var controls = '<div class="calendar_control">' +
			'<a class="calendar_clear" onclick="popUpCal._clearDate(' + this._id + ');">' +
			this._get('clearText') + '</a>' +
			'<a class="calendar_close" onclick="popUpCal.hideCalendar(' + this._id + ');">' +
			this._get('closeText') + '</a></div>';
		var prompt = this._get('prompt');
		var closeAtTop = this._get('closeAtTop');
		var hideIfNoPrevNext = this._get('hideIfNoPrevNext');
		// controls and links
		var html = (prompt ? '<div class="calendar_prompt">' + prompt + '</div>' : '') +
			(closeAtTop && !this._inline ? controls : '') + '<div class="calendar_header">' +
			(this._canAdjustMonth(-1) ? '<a class="calendar_prev" ' +
			'onclick="popUpCal._adjustDate(' + this._id + ', -1, \'M\');">' + this._get('prevText') + '</a>' :
			(hideIfNoPrevNext ? '' : '<label class="calendar_prev">' + this._get('prevText') + '</label>'));
			//(this._isInRange(today) ? '<a class="calendar_current" ' +
			//'onclick="popUpCal._gotoToday(' + this._id + ');">' + this._get('currentText') + '</a>' : '') +
			
		var minDate = this._get('minDate');
		var maxDate = this._get('maxDate');
		// month selection
		var monthNames = this._get('monthNames');
		//if 2 menus
		if(!this._get('monthYearMenu')){
			if (!this._get('changeMonth')) {
				html += monthNames[this._selectedMonth] + '&nbsp;';
			}
			else {
				var inMinYear = (minDate && minDate.getFullYear() == this._selectedYear);
				var inMaxYear = (maxDate && maxDate.getFullYear() == this._selectedYear);
				html += '<select class="calendar_newMonth" ' +
					'onchange="popUpCal._selectMonthYear(' + this._id + ', this, \'M\');" ' +
					'onclick="popUpCal._clickMonthYear(' + this._id + ');">';
				for (var month = 0; month < 12; month++) {
					if ((!inMinYear || month >= minDate.getMonth()) &&
							(!inMaxYear || month <= maxDate.getMonth())) {
						html += '<option value="' + month + '"' +
							(month == this._selectedMonth ? ' selected="selected"' : '') +
							'>' + monthNames[month] + '</option>';
					}
				}
				html += '</select>';
			}
			// year selection
			if (!this._get('changeYear')) {
				html += this._selectedYear;
			}
			else {
				// determine range of years to display
				var years = this._get('yearRange').split(':');
				var year = 0;
				var endYear = 0;
				if (years.length != 2) {
					year = this._selectedYear - 10;
					endYear = this._selectedYear + 10;
				}
				else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
					year = this._selectedYear + parseInt(years[0], 10);
					endYear = this._selectedYear + parseInt(years[1], 10);
				}
				else {
					year = parseInt(years[0], 10);
					endYear = parseInt(years[1], 10);
				}
				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
				html += '<select class="calendar_newYear" onchange="popUpCal._selectMonthYear(' +
					this._id + ', this, \'Y\');" ' + 'onclick="popUpCal._clickMonthYear(' +
					this._id + ');">';
				for (; year <= endYear; year++) {
					html += '<option value="' + year + '"' +
						(year == this._selectedYear ? ' selected="selected"' : '') +
						'>' + year + '</option>';
				}
				html += '</select>';
			}

		}
		//1 menu
		else {
			// determine range of years to display
				var years = this._get('yearRange').split(':');
				var year = 0;
				var endYear = 0;
				if (years.length != 2) {
					year = this._selectedYear - 10;
					endYear = this._selectedYear + 10;
				}
				else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
					year = this._selectedYear + parseInt(years[0], 10);
					endYear = this._selectedYear + parseInt(years[1], 10);
				}
				else {
					year = parseInt(years[0], 10);
					endYear = parseInt(years[1], 10);
				}
				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
				html += '<div class="monthYearContain" ><h2 onclick="$(this).parent().toggleClass(\'display\'); '+
				'$(this).parent().find(\'li\').each(function(i){'+
				'if($(this).is(\'#'+ this._selectedMonth+'_'+this._selectedYear +'\')) {'+
				'var scrollY = (i-4)*$(this).height(); this.parentNode.scrollTop = scrollY'+
				'} }); ">'+
				'<span>'+ monthNames[this._selectedMonth] +' '+ this._selectedYear +'</span></h2><div class="menu_contain"><div class="menu_pad"><ul class="calendar_monthYear" onclick="$(this).parent().parent().parent().removeClass(\'display\'); ">';

				for (; year <= endYear; year++) {
					var inMinYear = (minDate && minDate.getFullYear() == this._selectedYear);
					var inMaxYear = (maxDate && maxDate.getFullYear() == this._selectedYear);


					for (var month = 0; month < 12; month++) {
						if ((!inMinYear || month >= minDate.getMonth()) &&
								(!inMaxYear || month <= maxDate.getMonth())) {
							html += '<li id="' + month + '_'+ year + '"' +
								(month == this._selectedMonth && year == this._selectedYear ? ' class="selected"' : '') +
								'onclick="if($(this).parent().parent().parent().parent().is(\'.display\')) {popUpCal._selectMonthYear(' + this._id + ', this, \'MY\'); popUpCal._clickMonthYear(' + this._id + ');} $(document).click(function(){$(\'calendar_monthYear\').removeClass(\'display\');}); return false;">' + monthNames[month] + ' ' + year + '</li>';
						}
					}
				}


				
				html += '</ul></div></div></div>';
		}
		html += (this._canAdjustMonth(+1) ? '<a class="calendar_next" ' +
			'onclick="popUpCal._adjustDate(' + this._id + ', +1, \'M\');">' + this._get('nextText') + '</a>' :
			(hideIfNoPrevNext ? '' : '<label class="calendar_next">' + this._get('nextText') + '</label>'));
		



		
		html += '</div><table class="calendar" cellpadding="0" cellspacing="0"><thead>' +
			'<tr class="calendar_titleRow">';
		var firstDay = this._get('firstDay');
		var changeFirstDay = this._get('changeFirstDay');
		var dayNames = this._get('dayNames');
		for (var dow = 0; dow < 7; dow++) { // days of the week
			html += '<td>' + (!changeFirstDay ? '' : '<a onclick="popUpCal._changeFirstDay(' +
				this._id + ', this);">') + dayNames[(dow + firstDay) % 7] +
				(changeFirstDay ? '</a>' : '') + '</td>';
		}
		html += '</tr></thead><tbody>';
		var daysInMonth = this._getDaysInMonth(this._selectedYear, this._selectedMonth);
		this._selectedDay = Math.min(this._selectedDay, daysInMonth);
		var leadDays = (this._getFirstDayOfMonth(this._selectedYear, this._selectedMonth) - firstDay + 7) % 7;
		var currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay);
		var selectedDate = new Date(this._selectedYear, this._selectedMonth, this._selectedDay);
		var printDate = new Date(this._selectedYear, this._selectedMonth, 1 - leadDays);
		var numRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
		var customDate = this._get('customDate');
		var showOtherMonths = this._get('showOtherMonths');
		for (var row = 0; row < numRows; row++) { // create calendar rows
			html += '<tr class="calendar_daysRow">';
			for (var dow = 0; dow < 7; dow++) { // create calendar days
				var customSettings = (customDate ? customDate(printDate) : [true, '']);
				var otherMonth = (printDate.getMonth() != this._selectedMonth);
				var unselectable = otherMonth || !customSettings[0] ||
					(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
				html += '<td class="calendar_daysCell' +
					((dow + firstDay + 6) % 7 >= 5 ? ' calendar_weekEndCell' : '') + // highlight weekends
					(otherMonth ? ' calendar_otherMonth' : '') + // highlight days from other months
					(printDate.getTime() == selectedDate.getTime() ? ' ' : '') + // highlight selected day
					(unselectable ? ' calendar_unselectable' : '') +  // highlight unselectable days
					(otherMonth && !showOtherMonths ? '' : ' ' + customSettings[1] + // highlight custom dates
					(printDate.getTime() == currentDate.getTime() ? ' calendar_currentDay' : // highlight current day
					(printDate.getTime() == today.getTime() ? ' calendar_today currentSelection' : ''))) + '"' + // highlight today (if different)
					(unselectable ? '' : ' onmouseover="$(this).addClass(\'calendar_daysCellOver\');"' +
					' onmouseout="$(this).removeClass(\'calendar_daysCellOver\');"' +
					' onclick="popUpCal._selectDay(' + this._id + ', this); $(this).parents(\'table:eq(0)\').find(\'.currentSelection\').removeClass(\'currentSelection\');$(this).addClass(\'currentSelection\');"') + '>' + // actions
					(otherMonth ? (showOtherMonths ? printDate.getDate() : '&nbsp;') : // display for other months
					(unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
				printDate.setDate(printDate.getDate() + 1);
			}
			html += '</tr>';
		}
		html += '</tbody></table>' + (!closeAtTop && !this._inline ? controls : '') +
			'<div style="clear: both;"></div>' + (!$.browser.msie ? '' :
			'<!--[if lte IE 6.5]><iframe src="javascript:false;" class="calendar_cover"></iframe><![endif]-->');
		return html;
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(offset, period) {
		var date = new Date(this._selectedYear + (period == 'Y' ? offset : 0),
			this._selectedMonth + (period == 'M' ? offset : 0),
			this._selectedDay + (period == 'D' ? offset : 0));
		// ensure it is within the bounds set
		var minDate = this._get('minDate');
		var maxDate = this._get('maxDate');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		this._selectedDay = date.getDate();
		this._selectedMonth = date.getMonth();
		this._selectedYear = date.getFullYear();
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(offset) {
		var date = new Date(this._selectedYear, this._selectedMonth + offset, 1);
		if (offset < 0) {
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		}
		return this._isInRange(date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(date) {
		var minDate = this._get('minDate');
		var maxDate = this._get('maxDate');
		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
	},

	/* Format the given date for display. */
	_formatDate: function() {
		var day = this._currentDay = this._selectedDay;
		var month = this._currentMonth = this._selectedMonth;
		var year = this._currentYear = this._selectedYear;
		month++; // adjust javascript month
		var dateFormat = this._get('dateFormat');
		var dateString = '';
		for (var i = 0; i < 3; i++) {
			dateString += dateFormat.charAt(3) +
				(dateFormat.charAt(i) == 'D' ? (day < 10 ? '0' : '') + day :
				(dateFormat.charAt(i) == 'M' ? (month < 10 ? '0' : '') + month :
				(dateFormat.charAt(i) == 'Y' ? year : '?')));
		}
		return dateString.substring(dateFormat.charAt(3) ? 1 : 0);
	}
});



/* Attach the calendar to a jQuery selection.
   @param  settings  object - the new settings to use for this calendar instance (anonymous)
   @return jQuery object - for chaining further calls */
$.fn.calendar = function(settings) {
	return this.each(function() {
		// check for settings on the control itself - in namespace 'cal:'
		var inlineSettings = null;
		for (attrName in popUpCal._defaults) {
			var attrValue = this.getAttribute('cal:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				}
				catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = this.nodeName.toLowerCase();
		if (nodeName == 'input') {
			var instSettings = (inlineSettings ? $.extend($.extend({}, settings || {}),
				inlineSettings || {}) : settings); // clone and customise
			var inst = (inst && !inlineSettings ? inst :
				new PopUpCalInstance(instSettings, false));
			popUpCal._connectCalendar(this, inst);
		} 
		else if (nodeName == 'div' || nodeName == 'span') {
			var instSettings = $.extend($.extend({}, settings || {}),
				inlineSettings || {}); // clone and customise
			var inst = new PopUpCalInstance(instSettings, true);
			popUpCal._inlineCalendar(this, inst);
		}
	});
};

/* Initialise the calendar. */
$(document).ready(function() {
   popUpCal = new PopUpCal(); // singleton instance
   var earliest = new Date(2004, 10, 10);
   var latest = new Date(2014, 10, 10);
});



/**
 * --------------------------------------------------------------------
 * jQuery-Plugin to create interactive range picker with shortcut menu
 * by Scott Jehl, scott@filamentgroup.com
 * http://www.filamentgroup.com
 * reference article: http://www.filamentgroup.com/lab/jquery_interactive_date_range_picker_with_shortcuts
 * demo page: http://www.filamentgroup.com/examples/datepicker/
 * 
 * Copyright (c) 2008 Filament Group, Inc
 * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
 *
 * NOTE! This script is free to use and modify with proper attribution. 
 * However, it is not written for flexible reuse but rather for a specific implementation. 
 * We welcome any modification to package this in a more reusable plugin style.
 *
 * Version: 1.0, 31.05.2007
 * Changelog:
 * 	04.28.2008 initial Version 1.0
 * --------------------------------------------------------------------
 */







//DateRange Specific Extension
$.fn.dateRangePicker = function(options){
		var rangeElement = $(this).find('a.rangeDisplay');


		var presetMenu = {
				pastRange: '<div class="dateRange_contain dateRange_wide"><div class="dateRange"><ul class="dateRange_presets">'+
					'<li class="dateRange_last30"><a href="javascript://">letzte 30 Tage</a></li>'+
					'<li class="dateRange_lastYear"><a href="javascript://">letzte 12 Monante</a></li>'+
					'<li class="dateRange_yearToDate"><a href="javascript://">Heute</a></li>'+
					'<li class="dateRange_allDates"><a href="javascript://">alle Events</a></li>'+
					'<li class="dateRange_allBefore"><a href="javascript://">alle Events vor...</a></li>'+
					'<li class="dateRange_allAfter"><a href="javascript://">alle Events nach...</a></li>'+
					'<li class="dateRange_specificDate"><a href="javascript://">Datum...</a></li>'+
					'<li class="dateRange_dateRange"><a href="javascript://">Datumsbereich...</a></li>'+
					'</ul>'+
					'<a href="javascript://" class="dateRange_close">Fertig</a>'+
					'<h2 class="selectDate" style="display: none;"></h2>'+
					'<input type="text" name="range1" id="range1" class="range1" />'+
					'<input type="text" name="range2" id="range2" class="range2" /></div></div>',
				futureRange: '<div class="dateRange_contain dateRange_wide"><div class="dateRange"><ul class="dateRange_presets">'+
					'<li class="dateRange_today"><a href="javascript://">Heute</a></li>'+
					'<li class="dateRange_tomorrow"><a href="javascript://">Morgen</a></li>'+
					'<li class="dateRange_next7"><a href="javascript://">nächste 7 Tage</a></li>'+
					'<li class="dateRange_next30"><a href="javascript://">nächste 30 Tage</a></li>'+
					'<li class="dateRange_nextYear"><a href="javascript://">nächstes Jahr</a></li>'+
					'<li class="dateRange_allDates"><a href="javascript://">alle Events</a></li>'+
					'<li class="dateRange_specificDate"><a href="javascript://">Datum...</a></li>'+
					'<li class="dateRange_allBefore"><a href="javascript://">alle Events vor...</a></li>'+
					'<li class="dateRange_allAfter"><a href="javascript://">alle Events nach...</a></li>'+
					'<li class="dateRange_dateRange"><a href="javascript://">Datumsbereich...</a></li>'+
					'</ul>'+
					'<a href="javascript://" class="dateRange_close">Fertig</a>'+
					'<h2 class="selectDate" style="display: none;"></h2>'+
					'<input type="text" name="range1" id="range1" class="range1" />'+
					'<input type="text" name="range2" id="range2" class="range2" /></div></div>',
				singleUpcoming: '<div class="dateRange_contain"><div class="dateRange"><ul class="dateRange_presets">'+
					'<li class="dateRange_today"><a href="javascript://">Heute</a></li>'+
					'<li class="dateRange_tomorrow"><a href="javascript://">Morgen</a></li>'+
					'<li class="dateRange_beginningOfWeek"><a href="javascript://">Anfang der Woche</a></li>'+
					'<li class="dateRange_endOfWeek"><a href="javascript://">Ende der Woche</a></li>'+
					'<li class="dateRange_specificDate"><a href="javascript://">Datum...</a></li>'+
					'</ul>'+
					'<a href="javascript://" class="dateRange_close">Fertig</a>'+
					'<h2 class="selectDate" style="display: none;"></h2>'+
					'<input type="text" name="range1" id="range1" class="range1" />'+
					'<input type="text" name="range2" id="range2" class="range2" /></div></div>'	
		};


		
		//insert the preset menus and calendar holders
		if(typeof options.menuSet == 'undefined' || options.menuSet == 'pastRange'){
			var presetMenu = rangeElement.after(presetMenu.pastRange);
		}
		else if(options.menuSet == 'futureRange') {
			rangeElement.after(presetMenu.futureRange);
		}
		else if(options.menuSet == 'singleUpcoming') {
			rangeElement.after(presetMenu.singleUpcoming);
		}
		//height and widths of elements
		var startHeight = 270;//rangeElement.parent().find('ul.dateRange_presets').height();
		var startWidth = 198;//rangeElement.parent().find('ul.dateRange_presets').width()) +4;//+1 for the .4 padding on inner ul
		
		

		//height with pickers
		var expandedHeight = 242;//height needed for calendars
		if(startHeight> expandedHeight) {expandedHeight = startHeight;}

		//widths with pickers
		var width_onePicker_px = startWidth+215;
		var width_twoPickers_px = startWidth+407;


		//convert to ems
		startheight = startHeight/10+'em';
		expandedHeight = expandedHeight/10+'em';
		startWidth = startWidth/10+'em';
		width_onePicker = width_onePicker_px/10+'em';
		width_twoPickers = width_twoPickers_px/10+'em';


		
		
		var rangeType;		
		if(rangeElement.is('input')) rangeType = 'input';
		else rangeType = 'text';
		

		//create the 2 pickers and hide them
		
		var parentDiv = rangeElement.next();
		var range1 = parentDiv.find('[name=range1]');
		var range2 = parentDiv.find('[name=range2]');
		
		range1.calendar({dateRange: true}).focus().css({'position': 'absolute', 'left': '-999999px', 'top': '4.2em'});
		range2.calendar({dateRange: true}).focus().css({'position': 'absolute', 'left': '-999999px', 'top': '4.2em'});

		setTimeout(function(){parentDiv.children(0).hide();}, 100);

		var picker1 = parentDiv.find('.calendar_div:eq(0)');
		var picker2 = parentDiv.find('.calendar_div:eq(1)').addClass('position2');
				//hide pickers
		hidePickers();

		function hidePickers(intvl){
			if(!intvl) intvl=0;
			picker1.fadeOut(intvl);
			picker2.fadeOut(intvl);
			parentDiv.find('h2.selectDate, a.dateRange_close').fadeOut(intvl);
		}

		//show/hide menu from input actions
		$('body, .dateRange_close').click(function(){
			$('.dateRange_contain').children(0).hide(200);
			rangeElement.removeClass('rangeDisplay_on');
		});

		
		rangeElement.click(function(){
			if($(this).next().children(0).is(':visible')){ $(this).removeClass('rangeDisplay_on');}
			else {
				//collision detect
				var offset = $(this).offset();
				var winWidth = $(window).width();
				var rightSpace = winWidth - offset.left;
				if(rightSpace < width_twoPickers_px){
					parentDiv.find('div:eq(0)').css({'left': 'auto', 'right': 0, 'top': 0});
				}
				else {
					parentDiv.find('div:eq(0)').css({'left': 0, 'right': 'auto', 'top': 0});
				}
				$(this).addClass('rangeDisplay_on');
			}
			$(this).next().children(0).slideToggle(200);
			return false;
		});

		
		//cleanup hide
		rangeElement.one("click", function(){
			picker1.hide();
			picker2.hide();
			parentDiv.find('h2.selectDate, a.dateRange_close').hide();
		});
		$('.dateRange_contain').click(function(){
			return false;
		});


		var monthNames = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez']; // Names of months

		//loop to set the range input based on the 2 hidden inputs
		function setRangeVal (){
			setTimeout(function(){
				var val1 = range1.val();
				var val2 = range2.val();
				var str = '';
				if(val1 != ''){
					var splitter = ' bis '
					if(val1 == 'alle Events nach' || val1 == 'alle Events vor' || val1 == 'alle Events'  ||  val1 == 'Ende der Woche'  || val1 == 'Ende des Monats'  || val1 == 'Anfang der Woche'  || val1 == 'Anfang des Monats'  || val1 == '') splitter = ' ';
					else {
						val1 = val1.split('/');
						val1 = val1[1] + '. ' + monthNames[val1[0]-1]+' ' + val1[2].substring(2);
					}
					if(val2){
						val2 = val2.split('/');
						val2 = + val2[1] + '. ' + monthNames[val2[0]-1]+' ' + val2[2].substring(2);
					}

					
					if(val1 && val2 && val1 != val2) str = val1 + splitter + val2;
					else str = val1;
				}
				if(rangeType == 'input') rangeElement.val(str);
				else rangeElement.find('span').text(str);
				
				setRangeVal();
			}, 300);
		}
		setRangeVal();

		
		//input bg image
		if(rangeElement.is('input')) rangeElement.addClass('calendarInput');


		//next and prev buttons
		var btns_prevnext = $(this).find('.range_prev:eq(0), .range_next:eq(0)');

		$(btns_prevnext).click(function(){
			if(range1.val() == 'alle Events nach' || range1.val() == 'alle Events nach' || range1.val() == 'alle Events'){
				return false;
			}
			function returnDate(val){
				var dateFormat = 'DMY.';
				var currentDate = val.split(dateFormat.charAt(3));
				if (currentDate.length == 3) {
					var currentDay = parseInt(currentDate[dateFormat.indexOf('D')], 10);
					var currentMonth = parseInt(currentDate[dateFormat.indexOf('M')], 10) - 1;
					var currentYear = parseInt(currentDate[dateFormat.indexOf('Y')], 10);
				}
				return new Date(currentYear, currentMonth, currentDay);
			}

			//Get 1 day in milliseconds
			var one_day=1000*60*60*24

			//date from value
			var val1 = returnDate(range1.val());
			var val2 = returnDate(range2.val());
			var difference = Math.abs(Math.ceil((val1.getTime() - val2.getTime())));
			

			

			if(difference == 0) difference=one_day;//if same day, inc by 1

			if($(this).is('.range_prev')){
				difference *= -1;
			}


			var inst1 = popUpCal._inst[$(this).parent().find('.calendar_div:eq(0)').attr('id').split('_')[2]];
			var inst2 = popUpCal._inst[$(this).parent().find('.calendar_div:eq(1)').attr('id').split('_')[2]];


			/*cal 1*/
			//get current date
			var currDate1 = inst1._getDate().getTime();
			//make new temp dates for adding
			var newDate1 = new Date();
			newDate1.setTime(currDate1 + one_day);
			
			//update
			popUpCal._updateCalendar(inst1, 'hidden');
			//set current dates to new dates
			inst1._setDate(newDate1);
			//update
			popUpCal._updateCalendar(inst1, 'hidden');

			
			if(options.menuSet != 'singleUpcoming'){
				/*cal 2*/
				//get current date
				var currDate2 = inst2._getDate().getTime();
				//make new temp dates for adding
				var newDate2 = new Date();
				newDate2.setTime(currDate2 + difference);
				//update
				 popUpCal._updateCalendar(inst2, 'hidden');
				//set current dates to new dates
				inst2._setDate(newDate2);
				//update
				 popUpCal._updateCalendar(inst2, 'hidden');

				 $(this).parent().find('.calendar_currentDay:eq(1)').trigger("click");
			}

			//selected css
			$(this).parent().find('.calendar_currentDay:eq(0)').trigger("click");

			return false;
			
		});


		
		
		var dates = {
				minDate: function(){
					var date = new Date();
					return date.getMonth()+1+'/'+date.getDate()+'/'+(date.getFullYear()-10);
				},
				today: function(){
					var date = new Date();
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				yesterday: function(){
					var date = new Date();
					date.setDate(date.getDate()-1);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				tomorrow: function(){
					var date = new Date();
					date.setDate(date.getDate()+1);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				weekAgo: function(){
					var date = new Date();
					date.setDate(date.getDate()-7);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				nextWeek: function(){
					var date = new Date();
					date.setDate(date.getDate()+7);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				startOfWeek: function(){
					var date = new Date();
					var day = date.getDay();
					date.setDate(date.getDate() -day);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				endOfWeek: function(){
					var date = new Date();
					var day = date.getDay();
					var offset = 6 - day;
					date.setDate(date.getDate() + offset);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				monthAgo: function(){
					var date = new Date();
					date.setDate(date.getDate()-30);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				nextMonth: function(){
					var date = new Date();
					date.setDate(date.getDate()+30);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				startOfMonth: function(){
					var date = new Date();
					
					date.setMonth(date.getMonth()+1);
					date.setDate(1);
					date.setDate(date.getDate() - 1);
					date.setMonth(date.setMonth() - 1);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				endOfMonth: function(){
					var date = new Date();
					date.setDate(date.getDate()+30);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				yearAgo: function(){
					var date = new Date();
					date.setDate(date.getDate()-365);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				},
				ytdStart: function(){
					var date = new Date();
					return '1/1/'+(date.getFullYear());
				},
				nextYear: function(){
					var date = new Date();
					date.setDate(date.getDate()+365);
					return date.getMonth()+1+'/'+date.getDate()+'/'+date.getFullYear();
				}
			}

			//prefill hidden fields
			range1.val(dates.today());
			range2.val(dates.today());

		
			//menu animations
			var currTimeout = ''; //timeout var for hiding pickers
			$.fn.smallMenu = function(){
				$(this).parents('.dateRange:eq(0)').animate({width: startWidth}, 500,"swing");
				$(this).parents('.dateRange:eq(0)').find('ul:eq(0)').animate({height: startHeight}, 500,"swing");
				$(this).parents('.dateRange:eq(0)').slideUp(200);
				rangeElement.removeClass('rangeDisplay_on');
				currTimeout = setTimeout(function(){hidePickers(200);}, 500);
			}
			
			$.fn.showPickers = function(showPicker, pickerMsg){
				
				clearTimeout(currTimeout);
				picker1.css('top', '4.2em');
				picker2.css('top', '4.2em');
				rangeElement.addClass('rangeDisplay_on');
				$(this).addClass('dateRange_on');
				$(this).parents('.dateRange:eq(0)').find('ul:eq(0)').animate({height: expandedHeight}, 500,"swing");
				
					if(showPicker == 'picker1' || showPicker == 'picker2'){
						$(this).parents('.dateRange:eq(0)').animate({width: width_onePicker}, 500,"swing",function(){
							$(this).find('h2.selectDate').html(pickerMsg).fadeIn(100);
							$(this).find('a.dateRange_close').fadeIn(100);
						});
						if(showPicker == 'picker1') picker1.css('top', '4.2em').fadeIn(100);
						else picker2.removeClass('position2').fadeIn(100);
					}
					else {
						$(this).parents('.dateRange:eq(0)').animate({width: width_twoPickers}, 500,"swing",function(){
							$(this).find('h2.selectDate').html(pickerMsg).fadeIn(100);
								$(this).find('a.dateRange_close').fadeIn(100);
								picker1.fadeIn(100);
								picker2.addClass('position2').fadeIn(100);
						});
					}
			}


		parentDiv.find('li').click(function(){	
			$('.dateRange_on').removeClass('dateRange_on'); //kill onstate for LI
			hidePickers(200);//hide any range pickers present
			//figure out which preset is clicked
			if($(this).is('.dateRange_today')) {
				$(this).smallMenu();
				range1.val(dates.today());
				range2.val(dates.today());

			}
			if($(this).is('.dateRange_yesterday')) {
				$(this).smallMenu();
				range1.val(dates.yesterday());
				range2.val(dates.yesterday());

			}
			if($(this).is('.dateRange_tomorrow')) {
				$(this).smallMenu();
				range1.val(dates.tomorrow());
				range2.val(dates.tomorrow());

			}
			if($(this).is('.dateRange_beginningOfWeek')) {
				$(this).smallMenu();
				range1.val(dates.startOfWeek());
				range2.val('');
			}
			if($(this).is('.dateRange_endOfWeek')) {
				$(this).smallMenu();
				range1.val(dates.endOfWeek());
				range2.val('');
			}
			if($(this).is('.dateRange_beginningOfMonth')) {
				$(this).smallMenu();
				range1.val(dates.endOfMonth());
				range2.val('');
			}
			if($(this).is('.dateRange_endOfMonth')) {
				$(this).smallMenu();
				range1.val(dates.startOfMonth());
				range2.val('');
			}
			if($(this).is('.dateRange_last7')) {
				$(this).smallMenu();
				range1.val(dates.weekAgo());
				range2.val(dates.today());

			}
			if($(this).is('.dateRange_next7')) {
				$(this).smallMenu();
				range1.val(dates.today());
				range2.val(dates.nextWeek());

			}
			if($(this).is('.dateRange_last30')) {
				$(this).smallMenu();
				range1.val(dates.monthAgo());
				range2.val(dates.today());

			}
			if($(this).is('.dateRange_next30')) {
				$(this).smallMenu();
				range1.val(dates.today());
				range2.val(dates.nextMonth());

			}
			if($(this).is('.dateRange_lastYear')) {
				$(this).smallMenu();
				range1.val(dates.yearAgo());
				range2.val(dates.today());

			}
			if($(this).is('.dateRange_nextYear')) {
				$(this).smallMenu();
				range1.val(dates.today());
				range2.val(dates.nextYear());

			}
			if($(this).is('.dateRange_allDates')) {
				$(this).smallMenu();
				range1.val(dates.minDate());
				range2.val(dates.today());
				//console.log('all');
			}
			if($(this).is('.dateRange_yearToDate')) {
				$(this).smallMenu();
				range1.val(dates.ytdStart());
				range2.val(dates.today());
			}
			//items involving pickers
			if($(this).is('.dateRange_specificDate')) {
				range2.val('');
				$(this).showPickers('picker1', 'wähle ein Datum:');
			}
			
			if($(this).is('.dateRange_allBefore')) {
				range1.val('alle Events vor');
				$(this).showPickers('picker2', 'alle Events vor::');
			}
			
			if($(this).is('.dateRange_allAfter')) {
				range1.val('alle Events nach');
				$(this).showPickers('picker2', 'alle Events nach:');
			}
			
			if($(this).is('.dateRange_dateRange')) {
				$(this).showPickers('both', 'wähle einen Datumsbereich:');
			}

		});
		$('.dateRange_next30').trigger('click');
		if(parent) parent.scrollTo(0, 0); //
		return $(this);
	}


    /* jQuery extend now ignores nulls! */
    

     function extendRemove(target, props) {
    	$.extend(target, props);
    	for (var name in props) {
    		if (props[name] == null) {
    			target[name] = null;
    		}
    	}
    	return target;
    } 

function initDatePicker(){
    			$('.toggleRPpos').click(function(){
    				if($('div.rangePicker').css('float') == 'left') { 
    					$('div.rangePicker').css('float', 'right');
    					$('.toggleRPpos').html('Align date picker to the left');
    				}
    				else { 
    					$('div.rangePicker').css('float', 'left'); 
    					$('.toggleRPpos').html('Align date picker to the right');
    				}
    				return false;
    			});


    			// create date picker by replacing out the inputs
    		$('.rangePicker').html('<a href="#" class="rangeDisplay"><span>Pick a Date</span></a>').dateRangePicker({menuSet: 'futureRange'});


}


/*
Copyright (c) 2007 Brian Dillard and Brad Neuberg:
Brian Dillard | Project Lead | bdillard@pathf.com | http://blogs.pathf.com/agileajax/
Brad Neuberg | Original Project Creator | http://codinginparadise.org
   
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*
	dhtmlHistory: An object that provides history, history data, and bookmarking for DHTML and Ajax applications.
	
	dependencies:
		* the historyStorage object included in this file.

*/
window.dhtmlHistory = {
	
	/*Public: User-agent booleans*/
	isIE: false,
	isOpera: false,
	isSafari: false,
	isKonquerer: false,
	isGecko: false,
	isSupported: false,
	
	/*Public: Create the DHTML history infrastructure*/
	create: function(options) {
		
		/*
			options - object to store initialization parameters
			options.debugMode - boolean that causes hidden form fields to be shown for development purposes.
			options.toJSON - function to override default JSON stringifier
			options.fromJSON - function to override default JSON parser
		*/

		var that = this;

		/*set user-agent flags*/
		var UA = navigator.userAgent.toLowerCase();
		var platform = navigator.platform.toLowerCase();
		var vendor = navigator.vendor || "";
		if (vendor === "KDE") {
			this.isKonqueror = true;
			this.isSupported = false;
		} else if (typeof window.opera !== "undefined") {
			this.isOpera = true;
			this.isSupported = true;
		} else if (typeof document.all !== "undefined") {
			this.isIE = true;
			this.isSupported = true;
		} else if (vendor.indexOf("Apple Computer, Inc.") > -1) {
			this.isSafari = true;
			this.isSupported = (platform.indexOf("mac") > -1);
		} else if (UA.indexOf("gecko") != -1) {
			this.isGecko = true;
			this.isSupported = true;
		}

		/*Set up the historyStorage object; pass in init parameters*/
		window.historyStorage.setup(options);

		/*Execute browser-specific setup methods*/
		if (this.isSafari) {
			this.createSafari();
		} else if (this.isOpera) {
			this.createOpera();
		}
		
		/*Get our initial location*/
		var initialHash = this.getCurrentLocation();

		/*Save it as our current location*/
		this.currentLocation = initialHash;

		/*Now that we have a hash, create IE-specific code*/
		if (this.isIE) {
			this.createIE(initialHash);
		}

		/*Add an unload listener for the page; this is needed for FF 1.5+ because this browser caches all dynamic updates to the
		page, which can break some of our logic related to testing whether this is the first instance a page has loaded or whether
		it is being pulled from the cache*/

		var unloadHandler = function() {
			that.firstLoad = null;
		};
		
		this.addEventListener(window,'unload',unloadHandler);		

		/*Determine if this is our first page load; for IE, we do this in this.iframeLoaded(), which is fired on pageload. We do it
		there because we have no historyStorage at this point, which only exists after the page is finished loading in IE*/
		if (this.isIE) {
			/*The iframe will get loaded on page load, and we want to ignore this fact*/
			this.ignoreLocationChange = true;
		} else {
			if (!historyStorage.hasKey(this.PAGELOADEDSTRING)) {
				/*This is our first page load, so ignore the location change and add our special history entry*/
				this.ignoreLocationChange = true;
				this.firstLoad = true;
				historyStorage.put(this.PAGELOADEDSTRING, true);
			} else {
				/*This isn't our first page load, so indicate that we want to pay attention to this location change*/
				this.ignoreLocationChange = false;
				/*For browsers other than IE, fire a history change event; on IE, the event will be thrown automatically when its
				hidden iframe reloads on page load. Unfortunately, we don't have any listeners yet; indicate that we want to fire
				an event when a listener is added.*/
				this.fireOnNewListener = true;
			}
		}

		/*Other browsers can use a location handler that checks at regular intervals as their primary mechanism; we use it for IE as
		well to handle an important edge case; see checkLocation() for details*/
		var locationHandler = function() {
			that.checkLocation();
		};
		setInterval(locationHandler, 100);
	},	
	
	/*Public: Initialize our DHTML history. You must call this after the page is finished loading.*/
	initialize: function() {

		/*IE needs to be explicitly initialized. IE doesn't autofill form data until the page is finished loading, so we have to wait*/
		if (this.isIE) {
			/*If this is the first time this page has loaded*/
			if (!historyStorage.hasKey(this.PAGELOADEDSTRING)) {
				/*For IE, we do this in initialize(); for other browsers, we do it in create()*/
				this.fireOnNewListener = false;
				this.firstLoad = true;
				historyStorage.put(this.PAGELOADEDSTRING, true);
			}
			/*Else if this is a fake onload event*/
			else {
				this.fireOnNewListener = true;
				this.firstLoad = false;   
			}
		}
	},

	/*Public: Adds a history change listener. Note that only one listener is supported at this time.*/
	addListener: function(listener) {
		this.listener = listener;
		/*If the page was just loaded and we should not ignore it, fire an event to our new listener now*/
		if (this.fireOnNewListener) {
			this.fireHistoryEvent(this.currentLocation);
			this.fireOnNewListener = false;
		}
	},
	
	/*Public: Generic utility function for attaching events*/
	addEventListener: function(o,e,l) {
		if (o.addEventListener) {
			o.addEventListener(e,l,false);
		} else if (o.attachEvent) {
			o.attachEvent('on'+e,function() {
				l(window.event);
			});
		}
	},
	
	/*Public: Add a history point.*/
	add: function(newLocation, historyData) {
		
		if (this.isSafari) {
			
			/*Remove any leading hash symbols on newLocation*/
			newLocation = this.removeHash(newLocation);

			/*Store the history data into history storage*/
			historyStorage.put(newLocation, historyData);

			/*Save this as our current location*/
			this.currentLocation = newLocation;
	
			/*Change the browser location*/
			window.location.hash = newLocation;
		
			/*Save this to the Safari form field*/
			this.putSafariState(newLocation);

		} else {
			
			/*Most browsers require that we wait a certain amount of time before changing the location, such
			as 200 MS; rather than forcing external callers to use window.setTimeout to account for this,
			we internally handle it by putting requests in a queue.*/
			var that = this;
			var addImpl = function() {

				/*Indicate that the current wait time is now less*/
				if (that.currentWaitTime > 0) {
					that.currentWaitTime = that.currentWaitTime - that.waitTime;
				}
			
				/*Remove any leading hash symbols on newLocation*/
				newLocation = that.removeHash(newLocation);

				/*IE has a strange bug; if the newLocation is the same as _any_ preexisting id in the
				document, then the history action gets recorded twice; throw a programmer exception if
				there is an element with this ID*/
				if (document.getElementById(newLocation) && that.debugMode) {
					var e = "Exception: History locations can not have the same value as _any_ IDs that might be in the document,"
					+ " due to a bug in IE; please ask the developer to choose a history location that does not match any HTML"
					+ " IDs in this document. The following ID is already taken and cannot be a location: " + newLocation;
					throw new Error(e); 
				}

				/*Store the history data into history storage*/
				historyStorage.put(newLocation, historyData);

				/*Indicate to the browser to ignore this upcomming location change since we're making it programmatically*/
				that.ignoreLocationChange = true;

				/*Indicate to IE that this is an atomic location change block*/
				that.ieAtomicLocationChange = true;

				/*Save this as our current location*/
				that.currentLocation = newLocation;
		
				/*Change the browser location*/
				window.location.hash = newLocation;

				/*Change the hidden iframe's location if on IE*/
				if (that.isIE) {
					that.iframe.src = "++resource++blank.html?" + newLocation;
				}

				/*End of atomic location change block for IE*/
				that.ieAtomicLocationChange = false;
			};

			/*Now queue up this add request*/
			window.setTimeout(addImpl, this.currentWaitTime);

			/*Indicate that the next request will have to wait for awhile*/
			this.currentWaitTime = this.currentWaitTime + this.waitTime;
		}
	},

	/*Public*/
	isFirstLoad: function() {
		return this.firstLoad;
	},

	/*Public*/
	getVersion: function() {
		return "0.6";
	},

	/*Get browser's current hash location; for Safari, read value from a hidden form field*/

	/*Public*/
	getCurrentLocation: function() {
		var r = (this.isSafari
			? this.getSafariState()
			: this.getCurrentHash()
		);
		return r;
	},
	
	/*Public: Manually parse the current url for a hash; tip of the hat to YUI*/
    getCurrentHash: function() {
		var r = window.location.href;
		var i = r.indexOf("#");
		return (i >= 0
			? r.substr(i+1)
			: ""
		);
    },
	
	/*- - - - - - - - - - - -*/
	
	/*Private: Constant for our own internal history event called when the page is loaded*/
	PAGELOADEDSTRING: "DhtmlHistory_pageLoaded",
	
	/*Private: Our history change listener.*/
	listener: null,

	/*Private: MS to wait between add requests - will be reset for certain browsers*/
	waitTime: 200,
	
	/*Private: MS before an add request can execute*/
	currentWaitTime: 0,

	/*Private: Our current hash location, without the "#" symbol.*/
	currentLocation: null,

	/*Private: Hidden iframe used to IE to detect history changes*/
	iframe: null,

	/*Private: Flags and DOM references used only by Safari*/
	safariHistoryStartPoint: null,
	safariStack: null,
	safariLength: null,

	/*Private: Flag used to keep checkLocation() from doing anything when it discovers location changes we've made ourselves
	programmatically with the add() method. Basically, add() sets this to true. When checkLocation() discovers it's true,
	it refrains from firing our listener, then resets the flag to false for next cycle. That way, our listener only gets fired on
	history change events triggered by the user via back/forward buttons and manual hash changes. This flag also helps us set up
	IE's special iframe-based method of handling history changes.*/
	ignoreLocationChange: null,

	/*Private: A flag that indicates that we should fire a history change event when we are ready, i.e. after we are initialized and
	we have a history change listener. This is needed due to an edge case in browsers other than IE; if you leave a page entirely
	then return, we must fire this as a history change event. Unfortunately, we have lost all references to listeners from earlier,
	because JavaScript clears out.*/
	fireOnNewListener: null,

	/*Private: A variable that indicates whether this is the first time this page has been loaded. If you go to a web page, leave it
	for another one, and then return, the page's onload listener fires again. We need a way to differentiate between the first page
	load and subsequent ones. This variable works hand in hand with the pageLoaded variable we store into historyStorage.*/
	firstLoad: null,

	/*Private: A variable to handle an important edge case in IE. In IE, if a user manually types an address into their browser's
	location bar, we must intercept this by calling checkLocation() at regular intervals. However, if we are programmatically
	changing the location bar ourselves using the add() method, we need to ignore these changes in checkLocation(). Unfortunately,
	these changes take several lines of code to complete, so for the duration of those lines of code, we set this variable to true.
	That signals to checkLocation() to ignore the change-in-progress. Once we're done with our chunk of location-change code in
	add(), we set this back to false. We'll do the same thing when capturing user-entered address changes in checkLocation itself.*/
	ieAtomicLocationChange: null,
	
	/*Private: Create IE-specific DOM nodes and overrides*/
	createIE: function(initialHash) {
		/*write out a hidden iframe for IE and set the amount of time to wait between add() requests*/
		this.waitTime = 400;/*IE needs longer between history updates*/
		var styles = (historyStorage.debugMode
			? 'width: 800px;height:80px;border:1px solid black;'
			: historyStorage.hideStyles
		);
		var iframeID = "rshHistoryFrame";
		var iframeHTML = '<iframe frameborder="0" id="' + iframeID + '" style="' + styles + '" src="++resource++blank.html?' + initialHash + '"></iframe>';
		
		document.write(iframeHTML);
		this.iframe = document.getElementById(iframeID);
	},
	
	/*Private: Create Opera-specific DOM nodes and overrides*/
	createOpera: function() {
		this.waitTime = 400;/*Opera needs longer between history updates*/
		var imgHTML = '<img src="javascript:location.href=\'javascript:dhtmlHistory.checkLocation();\';" style="' + historyStorage.hideStyles + '" />';
		document.write(imgHTML);
	},
	
	/*Private: Create Safari-specific DOM nodes and overrides*/
	createSafari: function() {
		var formID = "rshSafariForm";
		var stackID = "rshSafariStack";
		var lengthID = "rshSafariLength";
		var formStyles = historyStorage.debugMode ? historyStorage.showStyles : historyStorage.hideStyles;
		var inputStyles = (historyStorage.debugMode
			? 'width:800px;height:20px;border:1px solid black;margin:0;padding:0;'
			: historyStorage.hideStyles
		);
		var safariHTML = '<form id="' + formID + '" style="' + formStyles + '">'
			+ '<input type="text" style="' + inputStyles + '" id="' + stackID + '" value="[]"/>'
			+ '<input type="text" style="' + inputStyles + '" id="' + lengthID + '" value=""/>'
		+ '</form>';
		document.write(safariHTML);
		this.safariStack = document.getElementById(stackID);
		this.safariLength = document.getElementById(lengthID);
		if (!historyStorage.hasKey(this.PAGELOADEDSTRING)) {
			this.safariHistoryStartPoint = history.length;
			this.safariLength.value = this.safariHistoryStartPoint;
		} else {
			this.safariHistoryStartPoint = this.safariLength.value;
		}
	},
	
	/*Private: Safari method to read the history stack from a hidden form field*/
	getSafariStack: function() {
		var r = this.safariStack.value;
		return historyStorage.fromJSON(r);
	},

	/*Private: Safari method to read from the history stack*/
	getSafariState: function() {
		var stack = this.getSafariStack();
		var state = stack[history.length - this.safariHistoryStartPoint - 1];
		return state;
	},			
	/*Private: Safari method to write the history stack to a hidden form field*/
	putSafariState: function(newLocation) {
	    var stack = this.getSafariStack();
	    stack[history.length - this.safariHistoryStartPoint] = newLocation;
	    this.safariStack.value = historyStorage.toJSON(stack);
	},

	/*Private: Notify the listener of new history changes.*/
	fireHistoryEvent: function(newHash) {
		/*extract the value from our history storage for this hash*/
		var historyData = historyStorage.get(newHash);
		/*call our listener*/
		this.listener.call(null, newHash, historyData);
	},
	
	/*Private: See if the browser has changed location. This is the primary history mechanism for Firefox. For IE, we use this to
	handle an important edge case: if a user manually types in a new hash value into their IE location bar and press enter, we want to
	to intercept this and notify any history listener.*/
	checkLocation: function() {
		
		/*Ignore any location changes that we made ourselves for browsers other than IE*/
		if (!this.isIE && this.ignoreLocationChange) {
			this.ignoreLocationChange = false;
			return;
		}

		/*If we are dealing with IE and we are in the middle of making a location change from an iframe, ignore it*/
		if (!this.isIE && this.ieAtomicLocationChange) {
			return;
		}
		
		/*Get hash location*/
		var hash = this.getCurrentLocation();

		/*Do nothing if there's been no change*/
		if (hash == this.currentLocation) {
			return;
		}

		/*In IE, users manually entering locations into the browser; we do this by comparing the browser's location against the
		iframe's location; if they differ, we are dealing with a manual event and need to place it inside our history, otherwise
		we can return*/
		this.ieAtomicLocationChange = true;

		if (this.isIE && this.getIframeHash() != hash) {
			this.iframe.src = "++resource++blank.html?" + hash;
		}
		else if (this.isIE) {
			/*the iframe is unchanged*/
			return;
		}

		/*Save this new location*/
		this.currentLocation = hash;

		this.ieAtomicLocationChange = false;

		/*Notify listeners of the change*/
		this.fireHistoryEvent(hash);
	},

	/*Private: Get the current location of IE's hidden iframe.*/
	getIframeHash: function() {
		var doc = this.iframe.contentWindow.document;
		var hash = String(doc.location.search);
		if (hash.length == 1 && hash.charAt(0) == "?") {
			hash = "";
		}
		else if (hash.length >= 2 && hash.charAt(0) == "?") {
			hash = hash.substring(1);
		}
		return hash;
	},

	/*Private: Remove any leading hash that might be on a location.*/
	removeHash: function(hashValue) {
		var r;
		if (hashValue === null || hashValue === undefined) {
			r = null;
		}
		else if (hashValue === "") {
			r = "";
		}
		else if (hashValue.length == 1 && hashValue.charAt(0) == "#") {
			r = "";
		}
		else if (hashValue.length > 1 && hashValue.charAt(0) == "#") {
			r = hashValue.substring(1);
		}
		else {
			r = hashValue;
		}
		return r;
	},

	/*Private: For IE, tell when the hidden iframe has finished loading.*/
	iframeLoaded: function(newLocation) {
		/*ignore any location changes that we made ourselves*/
		if (this.ignoreLocationChange) {
			this.ignoreLocationChange = false;
			return;
		}

		/*Get the new location*/
		var hash = String(newLocation.search);
		if (hash.length == 1 && hash.charAt(0) == "?") {
			hash = "";
		}
		else if (hash.length >= 2 && hash.charAt(0) == "?") {
			hash = hash.substring(1);
		}
		/*Keep the browser location bar in sync with the iframe hash*/
		window.location.hash = hash;

		/*Notify listeners of the change*/
		this.fireHistoryEvent(hash);
	}

};

/*
	historyStorage: An object that uses a hidden form to store history state across page loads. The mechanism for doing so relies on
	the fact that browsers save the text in form data for the life of the browser session, which means the text is still there when
	the user navigates back to the page. This object can be used independently of the dhtmlHistory object for caching of Ajax
	session information.
	
	dependencies: 
		* json2007.js (included in a separate file) or alternate JSON methods passed in through an options bundle.
*/
window.historyStorage = {
	
	/*Public: Set up our historyStorage object for use by dhtmlHistory or other objects*/
	setup: function(options) {
		
		/*
			options - object to store initialization parameters - passed in from dhtmlHistory or directly into historyStorage
			options.debugMode - boolean that causes hidden form fields to be shown for development purposes.
			options.toJSON - function to override default JSON stringifier
			options.fromJSON - function to override default JSON parser
		*/
		
		/*process init parameters*/
		if (typeof options !== "undefined") {
			if (options.debugMode) {
				this.debugMode = options.debugMode;
			}
			if (options.toJSON) {
				this.toJSON = options.toJSON;
			}
			if (options.fromJSON) {
				this.fromJSON = options.fromJSON;
			}
		}		
		
		/*write a hidden form and textarea into the page; we'll stow our history stack here*/
		var formID = "rshStorageForm";
		var textareaID = "rshStorageField";
		var formStyles = this.debugMode ? historyStorage.showStyles : historyStorage.hideStyles;
		var textareaStyles = (historyStorage.debugMode
			? 'width: 800px;height:80px;border:1px solid black;'
			: historyStorage.hideStyles
		);
		var textareaHTML = '<form id="' + formID + '" style="' + formStyles + '">'
			+ '<textarea id="' + textareaID + '" style="' + textareaStyles + '"></textarea>'
		+ '</form>';
		document.write(textareaHTML);
		this.storageField = document.getElementById(textareaID);
		if (typeof window.opera !== "undefined") {
			this.storageField.focus();/*Opera needs to focus this element before persisting values in it*/
		}
	},
	
	/*Public*/
	put: function(key, value) {
		this.assertValidKey(key);
		/*if we already have a value for this, remove the value before adding the new one*/
		if (this.hasKey(key)) {
			this.remove(key);
		}
		/*store this new key*/
		this.storageHash[key] = value;
		/*save and serialize the hashtable into the form*/
		this.saveHashTable();
	},

	/*Public*/
	get: function(key) {
		this.assertValidKey(key);
		/*make sure the hash table has been loaded from the form*/
		this.loadHashTable();
		var value = this.storageHash[key];
		if (value === undefined) {
			value = null;
		}
		return value;
	},

	/*Public*/
	remove: function(key) {
		this.assertValidKey(key);
		/*make sure the hash table has been loaded from the form*/
		this.loadHashTable();
		/*delete the value*/
		delete this.storageHash[key];
		/*serialize and save the hash table into the form*/
		this.saveHashTable();
	},

	/*Public: Clears out all saved data.*/
	reset: function() {
		this.storageField.value = "";
		this.storageHash = {};
	},

	/*Public*/
	hasKey: function(key) {
		this.assertValidKey(key);
		/*make sure the hash table has been loaded from the form*/
		this.loadHashTable();
		return (typeof this.storageHash[key] !== "undefined");
	},

	/*Public*/
	isValidKey: function(key) {
		return (typeof key === "string");
	},
	
	/*Public - CSS strings utilized by both objects to hide or show behind-the-scenes DOM elements*/
	showStyles: 'border:0;margin:0;padding:0;',
	hideStyles: 'left:-1000px;top:-1000px;width:1px;height:1px;border:0;position:absolute;',
	
	/*Public - debug mode flag*/
	debugMode: false,
	
	/*- - - - - - - - - - - -*/

	/*Private: Our hash of key name/values.*/
	storageHash: {},

	/*Private: If true, we have loaded our hash table out of the storage form.*/
	hashLoaded: false, 

	/*Private: DOM reference to our history field*/
	storageField: null,

	/*Private: Assert that a key is valid; throw an exception if it not.*/
	assertValidKey: function(key) {
		var isValid = this.isValidKey(key);
		if (!isValid && this.debugMode) {
			throw new Error("Please provide a valid key for window.historyStorage. Invalid key = " + key + ".");
		}
	},

	/*Private: Load the hash table up from the form.*/
	loadHashTable: function() {
		if (!this.hashLoaded) {	
			var serializedHashTable = this.storageField.value;
			if (serializedHashTable !== "" && serializedHashTable !== null) {
				this.storageHash = this.fromJSON(serializedHashTable);
				this.hashLoaded = true;
			}
		}
	},
	/*Private: Save the hash table into the form.*/
	saveHashTable: function() {
		this.loadHashTable();
		var serializedHashTable = this.toJSON(this.storageHash);
		this.storageField.value = serializedHashTable;
	},
	/*Private: Bridges for our JSON implementations - both rely on 2007 JSON.org library - can be overridden by options bundle*/
	toJSON: function(o) {
		return o.toJSONString();
	},
	fromJSON: function(s) {
		return s.parseJSON();
	}
};

window.dhtmlHistory.create({
        toJSON: function(o) {
                return JSON.stringify(o);
        }
        , fromJSON: function(s) {
                return JSON.parse(s);
        }
});

LovelyMagazineControl = function() {
  this.manager;
  var self=this;
  this.refreshableClass="ajax_refreshable";
  this.refreshing=true;
  this.ready=false;
  
  //a peristent sorter remains active after a location or itemchange
  this.peristentSorter;
}

LovelyMagazineControl.prototype.init=function(pm) {
  this.manager=pm;
}

LovelyMagazineControl.prototype.hasContent = function() {
  return $('div:first', this.manager.stage).length > 0;
}

LovelyMagazineControl.prototype.refresh=function(type, data) {
    
    var consumer;
    if (type=="city") {
        consumer = "";
    } else if (type=="district") {
        consumer = "district/"+encodeURIComponent(data.name);
    } else if (type=="street") {
        consumer = LPM.map.getMagazineCoordConsumerString();
    }

    this.currentConsumer = consumer; //store for pagechanges

    var self=this;
    LPM.refreshCssClass({
        cssClass : 'ajax_geosensitive',
        consumer : consumer,
        finishCallBack : function() {
            self.onRefreshed();
        }
    })
}

LovelyMagazineControl.prototype.setPersistentSorter = function(sorter) {
  this.persistentSorter = sorter;
}

LovelyMagazineControl.prototype.getPersistentSorter = function() {
  if (this.persistentSorter) return "/" + this.persistentSorter
  else return "";
}

/* called when the page has changed */
LovelyMagazineControl.prototype.onPageChanged = function(page) {
  this.setPersistentSorter(null);
}

LovelyMagazineControl.prototype.onRefreshed=function() {
  this.manager.ajaxify($('div#magazine'));
  this.refreshing = false;
  this.ready = true;
  this.initBatches();
  this.initRssFeed();
  
  //rehighlight the active tab
  if (this.manager.currentPage.tab) {
    this.manager.highlightActivePageLink(this.manager.pagesById[this.manager.currentPage.tab]);
  } else { 
    this.manager.highlightActivePageLink(this.manager.currentPage);
  }
}

LovelyMagazineControl.prototype.readyForProfiling = function() {
  if ((!this.refreshing) && (this.ready)) return true;
  else return false;
}

LovelyMagazineControl.prototype.refreshHead = function() {
  var coords = this.manager.map.getMagazineCoordConsumerString();
  var url = this.manager.getGlobals().portalUrl + "/" + coords + "/magazineHead";
  // this.getHead().load(url);
  $("div#ajax_head_container").load(url);
}

LovelyMagazineControl.prototype.initRssFeed = function(){
    var re = $('div.magazine', $("div#ajaxPageContainer")).parent();
    if (re.length) {
        var ab = re.attr("ajax:base");
        var feed = $('a#rss-feed');
        if(feed.length){
          var contenttype = feed.attr('ajax:contentType');
          contenttype = 'type/'+contenttype;
          ab = this.manager.getGlobals().portalUrl+ab+contenttype;
          ab = ab + '/rss2.xml';
          feed.attr('href',ab);  
          header = '<link rel="alternate" type="application/rss+xml" title="MyCity RSS'+contenttype+'" href="'+ab+'" />';
          $('head').append(header);
        };
    };
};

/* batchcontrol ------------------------------------------------------------- */

LISTSORTER_CLASS = 'ajax_listsorter';

Batch = function() {}
Batch.prototype.init = function(context) {
  this.manager=LPM;
  this.context=$(context, this.getSuperContext());
  this.id = this.manager.registerBatch(this);
  this.getContainer(context);
  this.consumers = {};
  this.scrollOnUpdate = true;
  
  this.base = this.context.attr("ajax:base");
  this.view = this.context.attr("ajax:view");

  //get the batchstart out of the baseurl TODO quite hacky
  PATTERN = /\/batch[0-9]*\/([0-9]*)/;
  if (this.base.match(PATTERN)) this.batchStart = parseInt(this.base.match(PATTERN)[1])
  else this.batchStart = 0;

  this.consumerButtons = $('.ajax_listFilter', this.context);
  this.initConsumerButtons();
  
  //find an optional listsorter and connect
  if ($('.'+LISTSORTER_CLASS).length) {
      this.sorter = new ListSorter();
      this.sorter.init($('.'+LISTSORTER_CLASS), this);
  }
}

Batch.prototype.getSuperContext = function() {
    //return the supercontext for the batch
    //in most cases this will be the document,
    //but in some cases the current hover
    //override in subclass
    return $('body');
}

Batch.prototype.getContainer = function() {

    info("batch.getContainer", this.context.parent());

    //recapture the context if it was lost (through dom manipulations)
    this.resetContext();
    
    if (this.context.length != 1) error('found wrong ammount of context for a single batch: ', this.context, this)
    if (this.context.parent().attr('class') != 'ajax_uc') {
      this.context.wrap($("<div class='ajax_uc'></div>"));
    }
    return this.context.parent();
}

Batch.prototype.initConsumerButtons = function() {
    var self=this;
    this.consumerButtons.each(function() {
      var addConsumer = $(this).attr("ajax:addconsumer");
      var removeConsumer = $(this).attr("ajax:removeconsumer");
      $(this).removeClass(this.consumerBtnClass);
      
      var action = "LPM.getBatch("+self.id+").applyConsumers('"+addConsumer+"', '"+removeConsumer+"')"      
      $(this).attr("href", 'javascript:'+action);
    });
}

Batch.prototype.update = function() {
  var self=this;
  //wrap a container if not present
  var url = self.buildUrl(this.base, this.view);
  this.getContainer().load(url, function() {
    self.onListUpdate();
  });            
}

Batch.prototype.onListUpdate = function() {
  this.initConsumerButtons();
  if (this.scrollOnUpdate) window.scrollTo(0,0);
  LPM.ajaxify();
}

Batch.prototype.applyConsumers = function(add, rem) {
    this.addConsumers(add);
    this.removeConsumers(rem);
    this.update();

    log(this.consumers);
  
}

Batch.prototype.resetContext = function() {
    this.context = LPM.getBatchContext(this.id);
}

Batch.prototype.addConsumers = function(add) {
  if (!add) return;
  var parts = add.split("/");
  var key=parts[0];
  if (parts.length > 1) {
    var args=parts.slice(1);
    this.consumers[key]=args;
  } else {
    this.consumers[key]=true;
  }
  log("addconsumer", this.consumers);
}

Batch.prototype.removeConsumers = function(rem) {
  if (!rem) return;
  var key = rem.split("/")[0];
  this.consumers[key] = false;

  //strip the consumer out of base and view
  log(this.base, rem);
  this.base = this.manager.stripOldConsumers(this.base, rem);
  log(this.base, rem);
  
  
  this.view = this.manager.stripOldConsumers(this.view,  rem);
}

Batch.prototype.buildUrl = function(base, view) {
  var cons = "";
  for (var p in this.consumers) {
    if (this.consumers[p]) {
      cons += p;
      if (typeof(this.consumers[p]) != "boolean") {
        cons += "/"+this.consumers[p].join("/");
      }
    }
  }

  if (cons) {
      base = this.manager.stripOldConsumers(this.base, cons);
      view = this.manager.stripOldConsumers(this.view, cons);
  } else {
      base = this.manager.stripAllConsumers(this.base, cons);
      view = this.manager.stripAllConsumers(this.view, cons);      
  }
  
  return base +"/"
         + cons+"/"
         + view;

}

BatchedBox = function(){}
BatchedBox.prototype = new Batch();
BatchedBox.prototype.init = function(context) {
    Batch.prototype.init.call(this, context);
    this.scrollOnUpdate=false;
    var self=this;
    $('a.ajax_enlargebox', this.context).unbind("click").bind("click", function() {
        self.enlarge();
    }).attr("href", "javascript:LPM.nothing();").removeClass('ajax_enlargebox');
    
    $('a.ajax_minimizebox', this.context).unbind("click").bind("click", function() {
        self.minimize();
    }).attr("href", "javascript:LPM.nothing();").removeClass('ajax_minimizebox');
    log("init batchbox: ", this.context, $('a.ajax_enlargebox', this.context), $('a.ajax_minimizebox', this.context))
}

BatchedBox.prototype.getSuperContext = function() {
    return LHM.getCurrentHover().getContainer();
}

BatchedBox.prototype.enlarge = function() {
    this.addConsumers('batch/0');
    this.update();
}

BatchedBox.prototype.minimize = function() {
    this.consumers={};
    this.update();
}

ListSorter = function() {}
ListSorter.prototype.init = function(node, batch) {
    this.batch = batch;
    this.context = node;
    this.initButtons();
}

ListSorter.prototype.initButtons = function() {
    var self=this;
    $('a', this.context).each(function() {
      var addConsumer = $(this).attr("ajax:addconsumer");
      var removeConsumer = $(this).attr("ajax:removeconsumer");      
      var action = "LPM.getBatch("+self.batch.id+").applyConsumers('"+addConsumer+"', '"+removeConsumer+"')"      
      $(this).attr("href", 'javascript:'+action);
    });
}
GossipControl = function() {}
GossipControl.prototype.init = function(pm) {
    this.manager=pm;
}
GossipControl.prototype.refresh = function(type, data) {

    var consumer = LPM.map.getMagazineCoordConsumerString();
    
    var self=this;
    LPM.refreshCssClass({
        cssClass : 'ajax_geosensitive',
        consumer : consumer,
        finishCallBack : function() {
            self.onRefreshed();
        }
    })
}

GossipControl.prototype.onRefreshed = function() {
    
}
/*
 * jQuery UI @VERSION
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 *
 * $Date: 2008-04-01 09:23:47 -0400 (Tue, 01 Apr 2008) $
 * $Rev: 5174 $
 */
;(function($) {

	//If the UI scope is not available, add it
	$.ui = $.ui || {};
	
	//Add methods that are vital for all mouse interaction stuff (plugin registering)
	$.extend($.ui, {
		plugin: {
			add: function(module, option, set) {
				var proto = $.ui[module].prototype;
				for(var i in set) {
					proto.plugins[i] = proto.plugins[i] || [];
					proto.plugins[i].push([option, set[i]]);
				}
			},
			call: function(instance, name, arguments) {
				var set = instance.plugins[name]; if(!set) return;
				for (var i = 0; i < set.length; i++) {
					if (instance.options[set[i][0]]) set[i][1].apply(instance.element, arguments);
				}
			}	
		},
		cssCache: {},
		css: function(name) {
			if ($.ui.cssCache[name]) return $.ui.cssCache[name];
			var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
			
			//if (!$.browser.safari)
				//tmp.appendTo('body'); 
			
			//Opera and Safari set width and height to 0px instead of auto
			//Safari returns rgba(0,0,0,0) when bgcolor is not set
			$.ui.cssCache[name] = !!(
				(!/auto|default/.test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
				!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
			);
			try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
			return $.ui.cssCache[name];
		},
		disableSelection: function(e) {
			e.unselectable = "on";
			e.onselectstart = function() {	return false; };
			if (e.style) e.style.MozUserSelect = "none";
		},
		enableSelection: function(e) {
			e.unselectable = "off";
			e.onselectstart = function() { return true; };
			if (e.style) e.style.MozUserSelect = "";
		},
		hasScroll: function(e, a) {
      		var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
      		if (e[scroll] > 0) return true; e[scroll] = 1;
      		has = e[scroll] > 0 ? true : false; e[scroll] = 0;
      		return has; 
    	}
	});

	/******* fn scope modifications ********/

	$.each( ['Left', 'Top'], function(i, name) {
		if(!$.fn['scroll'+name]) $.fn['scroll'+name] = function(v) {
			return v != undefined ?
				this.each(function() { this == window || this == document ? window.scrollTo(name == 'Left' ? v : $(window)['scrollLeft'](), name == 'Top'  ? v : $(window)['scrollTop']()) : this['scroll'+name] = v; }) :
				this[0] == window || this[0] == document ? self[(name == 'Left' ? 'pageXOffset' : 'pageYOffset')] || $.boxModel && document.documentElement['scroll'+name] || document.body['scroll'+name] : this[0][ 'scroll' + name ];
		};
	});

	var _remove = $.fn.remove;
	$.fn.extend({
		position: function() {
			var offset       = this.offset();
			var offsetParent = this.offsetParent();
			var parentOffset = offsetParent.offset();

			return {
				top:  offset.top - num(this[0], 'marginTop')  - parentOffset.top - num(offsetParent, 'borderTopWidth'),
				left: offset.left - num(this[0], 'marginLeft')  - parentOffset.left - num(offsetParent, 'borderLeftWidth')
			};
		},
		offsetParent: function() {
			var offsetParent = this[0].offsetParent;
			while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
				offsetParent = offsetParent.offsetParent;
			return $(offsetParent);
		},
		mouseInteraction: function(o) {
			return this.each(function() {
				new $.ui.mouseInteraction(this, o);
			});
		},
		removeMouseInteraction: function(o) {
			return this.each(function() {
				if($.data(this, "ui-mouse"))
					$.data(this, "ui-mouse").destroy();
			});
		},
		remove: function() {
			jQuery("*", this).add(this).trigger("remove");
			return _remove.apply(this, arguments );
		}
	});
	
	function num(el, prop) {
		return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
	};
	
	
	/********** Mouse Interaction Plugin *********/
	
	$.ui.mouseInteraction = function(element, options) {
	
		var self = this;
		this.element = element;

		$.data(this.element, "ui-mouse", this);
		this.options = $.extend({}, options);
		
		$(element).bind('mousedown.draggable', function() { return self.click.apply(self, arguments); });
		if($.browser.msie) $(element).attr('unselectable', 'on'); //Prevent text selection in IE
		
		// prevent draggable-options-delay bug #2553
		$(element).mouseup(function() {
			if(self.timer) clearInterval(self.timer);
		});
	};
	
	$.extend($.ui.mouseInteraction.prototype, {
		
		destroy: function() { $(this.element).unbind('mousedown.draggable'); },
		trigger: function() { return this.click.apply(this, arguments); },
		click: function(e) {
			
			if(
				   e.which != 1 //only left click starts dragging
				|| $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements
				|| (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition
			) return true;
				
			var self = this;
			var initialize = function() {
				self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position
				$(document).bind('mouseup.draggable', function() { return self.stop.apply(self, arguments); });
				$(document).bind('mousemove.draggable', function() { return self.drag.apply(self, arguments); });
				
				if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) {				
					if(self.options.start) self.options.start.call(self.options.executor || self, e, self.element);
					if(self.options.drag) self.options.drag.call(self.options.executor || self, e, this.element); //This is actually not correct, but expected
					self.initialized = true;
				}
			};

			if(this.options.delay) {
				if(this.timer) clearInterval(this.timer);
				this.timer = setTimeout(initialize, this.options.delay);
			} else {
				initialize();
			}
				
			return false;
			
		},
		stop: function(e) {			
			
			var o = this.options;
			if(!this.initialized) return $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');

			if(this.options.stop) this.options.stop.call(this.options.executor || this, e, this.element);
			$(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
			this.initialized = false;
			return false;
			
		},
		drag: function(e) {

			var o = this.options;
			if ($.browser.msie && !e.button) return this.stop.apply(this, [e]); // IE mouseup check
			
			if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) {				
				if(this.options.start) this.options.start.call(this.options.executor || this, e, this.element);
				this.initialized = true;
			} else {
				if(!this.initialized) return false;
			}

			if(o.drag) o.drag.call(this.options.executor || this, e, this.element);
			return false;
			
		}
	});
	
})(jQuery);
 
/*
 * jQuery UI Slider
 *
 * Copyright (c) 2008 Paul Bakaus
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * http://docs.jquery.com/UI/Slider
 *
 * Depends:
 *   ui.base.js
 *
 * Revision: $Id: ui.slider.js 5219 2008-04-09 20:16:05Z braeker $
 */
;(function($) {

	$.fn.extend({
		slider: function(options) {
			var args = Array.prototype.slice.call(arguments, 1);
			
			if ( options == "value" )
				return $.data(this[0], "slider").value(arguments[1]);
			
			return this.each(function() {
				if (typeof options == "string") {
					var slider = $.data(this, "slider");
					if (slider) slider[options].apply(slider, args);

				} else if(!$.data(this, "slider"))
					new $.ui.slider(this, options);
			});
		}
	});
	
	$.ui.slider = function(element, options) {

		//Initialize needed constants
		var self = this;
		this.element = $(element);
		$.data(element, "slider", this);
		this.element.addClass("ui-slider");
		
		//Prepare the passed options
		this.options = $.extend({}, $.ui.slider.defaults, options);
		var o = this.options;
		$.extend(o, {
			axis: o.axis || (element.offsetWidth < element.offsetHeight ? 'vertical' : 'horizontal'),
			max: !isNaN(parseInt(o.max,10)) ? { x: parseInt(o.max, 10), y: parseInt(o.max, 10)  } : ({ x: o.max && o.max.x || 100, y:  o.max && o.max.y || 100 }),
			min: !isNaN(parseInt(o.min,10)) ? { x: parseInt(o.min, 10), y: parseInt(o.min, 10)  } : ({ x: o.min && o.min.x || 0, y:  o.min && o.min.y || 0 })
		});
	
		//Prepare the real maxValue
		o.realMax = {
			x: o.max.x - o.min.x,
			y: o.max.y - o.min.y
		};
		
		//Calculate stepping based on steps
		o.stepping = {
			x: o.stepping && o.stepping.x || parseInt(o.stepping, 10) || (o.steps && o.steps.x ? o.realMax.x/o.steps.x : 0),
			y: o.stepping && o.stepping.y || parseInt(o.stepping, 10) || (o.steps && o.steps.y ? o.realMax.y/o.steps.y : 0)
		};
		
		$(element).bind("setData.slider", function(event, key, value){
			self.options[key] = value;
		}).bind("getData.slider", function(event, key){
			return self.options[key];
		});

		//Initialize mouse and key events for interaction
		this.handle = $(o.handle, element);
		if (!this.handle.length) {
			self.handle = self.generated = $(o.handles || [0]).map(function() {
				var handle = $("<div/>").addClass("ui-slider-handle").appendTo(element);
				if (this.id)
					handle.attr("id", this.id);
				return handle[0];
			});
		}
		$(this.handle)
			.mouseInteraction({
				executor: this,
				delay: o.delay,
				distance: o.distance != undefined ? o.distance : 1,
				dragPrevention: o.prevention ? o.prevention.toLowerCase().split(',') : ['input','textarea','button','select','option'],
				start: this.start,
				stop: this.stop,
				drag: this.drag,
				condition: function(e, handle) {
					if(!this.disabled) {
						if(this.currentHandle) this.blur(this.currentHandle);
						this.focus(handle,1);
						return !this.disabled;
					}
				}
			})
			.wrap('<a href="javascript:void(0)" style="cursor:default;"></a>')
			.parent()
				.bind('focus', function(e) { self.focus(this.firstChild); })
				.bind('blur', function(e) { self.blur(this.firstChild); })
				.bind('keydown', function(e) {
					if(/(37|38|39|40)/.test(e.keyCode)) {
						self.moveTo({
							x: /(37|39)/.test(e.keyCode) ? (e.keyCode == 37 ? '-' : '+') + '=' + self.oneStep(1) : null,
							y: /(38|40)/.test(e.keyCode) ? (e.keyCode == 38 ? '-' : '+') + '=' + self.oneStep(2) : null
						}, this.firstChild);
					}
				})
		;
		
		//Prepare dynamic properties for later use
		this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() };
		
		//Bind the click to the slider itself
		this.element.bind('mousedown.slider', function(e) {
			self.click.apply(self, [e]);
			self.currentHandle.data("ui-mouse").trigger(e);
			self.firstValue = self.firstValue + 1; //This is for always triggering the change event
		});
		
		//Move the first handle to the startValue
		$.each(o.handles || [], function(index, handle) {
			self.moveTo(handle.start, index, true);
		});
		if (!isNaN(o.startValue))
			this.moveTo(o.startValue, 0, true);
		
		//If we only have one handle, set the previous handle to this one to allow clicking before selecting the handle
		if(this.handle.length == 1) this.previousHandle = this.handle;
		if(this.handle.length == 2 && o.range) this.createRange();
	
	};
	
	$.extend($.ui.slider.prototype, {
		plugins: {},
		createRange: function() {
			this.rangeElement = $('<div></div>')
				.addClass('ui-slider-range')
				.css({ position: 'absolute' })
				.appendTo(this.element);
			this.updateRange();
		},
		updateRange: function() {
				var prop = this.options.axis == "vertical" ? "top" : "left";
				var size = this.options.axis == "vertical" ? "height" : "width";
				this.rangeElement.css(prop, parseInt($(this.handle[0]).css(prop),10) + this.handleSize(0, this.options.axis == "vertical" ? 2 : 1)/2);
				this.rangeElement.css(size, parseInt($(this.handle[1]).css(prop),10) - parseInt($(this.handle[0]).css(prop),10));
		},
		getRange: function() {
			return this.rangeElement ? this.convertValue(parseInt(this.rangeElement.css(this.options.axis == "vertical" ? "height" : "width"),10)) : null;
		},
		ui: function(e) {
			return {
				instance: this,
				options: this.options,
				handle: this.currentHandle,
				value: this.options.axis != "both" || !this.options.axis ? Math.round(this.value(null,this.options.axis == "vertical" ? 2 : 1)) : {
					x: Math.round(this.value(null,1)),
					y: Math.round(this.value(null,2))
				},
				range: this.getRange()
			};
		},
		propagate: function(n,e) {
			$.ui.plugin.call(this, n, [e, this.ui()]);
			this.element.triggerHandler(n == "slide" ? n : "slide"+n, [e, this.ui()], this.options[n]);
		},
		destroy: function() {
			this.element
				.removeClass("ui-slider ui-slider-disabled")
				.removeData("slider")
				.unbind(".slider");
			this.handle.removeMouseInteraction();
			this.generated && this.generated.remove();
		},
		enable: function() {
			this.element.removeClass("ui-slider-disabled");
			this.disabled = false;
		},
		disable: function() {
			this.element.addClass("ui-slider-disabled");
			this.disabled = true;
		},
		focus: function(handle,hard) {
			this.currentHandle = $(handle).addClass('ui-slider-handle-active');
			if(hard) this.currentHandle.parent()[0].focus();
		},
		blur: function(handle) {
			$(handle).removeClass('ui-slider-handle-active');
			if(this.currentHandle && this.currentHandle[0] == handle) { this.previousHandle = this.currentHandle; this.currentHandle = null; };
		},
		value: function(handle, axis) {
			if(this.handle.length == 1) this.currentHandle = this.handle;
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			
			var value = ((parseInt($(handle != undefined && handle !== null ? this.handle[handle] || handle : this.currentHandle).css(axis == 1 ? "left" : "top"),10) / (this.actualSize[axis == 1 ? "width" : "height"] - this.handleSize(null,axis))) * this.options.realMax[axis == 1 ? "x" : "y"]) + this.options.min[axis == 1 ? "x" : "y"];
			
			var o = this.options;
			if (o.stepping[axis == 1 ? "x" : "y"]) {
			    value = Math.round(value / o.stepping[axis == 1 ? "x" : "y"]) * o.stepping[axis == 1 ? "x" : "y"];
			}
			return value;
		},
		convertValue: function(value,axis) {
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			return this.options.min[axis == 1 ? "x" : "y"] + (value / (this.actualSize[axis == 1 ? "width" : "height"] - this.handleSize(null,axis))) * this.options.realMax[axis == 1 ? "x" : "y"];
		},
		translateValue: function(value,axis) {
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			return ((value - this.options.min[axis == 1 ? "x" : "y"]) / this.options.realMax[axis == 1 ? "x" : "y"]) * (this.actualSize[axis == 1 ? "width" : "height"] - this.handleSize(null,axis));
		},
		handleSize: function(handle,axis) {
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			return $(handle != undefined && handle !== null ? this.handle[handle] : this.currentHandle)[axis == 1 ? "outerWidth" : "outerHeight"]();	
		},
		click: function(e) {
		
			// This method is only used if:
			// - The user didn't click a handle
			// - The Slider is not disabled
			// - There is a current, or previous selected handle (otherwise we wouldn't know which one to move)
			var pointer = [e.pageX,e.pageY];
			var clickedHandle = false; this.handle.each(function() { if(this == e.target) clickedHandle = true;  });
			if(clickedHandle || this.disabled || !(this.currentHandle || this.previousHandle)) return;

			//If a previous handle was focussed, focus it again
			if(this.previousHandle) this.focus(this.previousHandle, 1);
			
			//Move focussed handle to the clicked position
			this.offset = this.element.offset();
			this.moveTo({
				y: this.convertValue(e.pageY - this.offset.top - this.currentHandle.outerHeight()/2),
				x: this.convertValue(e.pageX - this.offset.left - this.currentHandle.outerWidth()/2)
			}, null, true);
		},
		start: function(e, handle) {
		
			var o = this.options;
			if(!this.currentHandle) this.focus(this.previousHandle, true); //This is a especially ugly fix for strange blur events happening on mousemove events

			this.offset = this.element.offset();
			this.handleOffset = this.currentHandle.offset();
			this.clickOffset = { top: e.pageY - this.handleOffset.top, left: e.pageX - this.handleOffset.left };
			this.firstValue = this.value();
			
			this.propagate('start', e);
			return false;
						
		},
		stop: function(e) {
			this.propagate('stop', e);
			if (this.firstValue != this.value())
				this.propagate('change', e);
			this.focus(this.currentHandle, true); //This is a especially ugly fix for strange blur events happening on mousemove events
			return false;
		},

		oneStep: function(axis) {
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			return this.options.stepping[axis == 1 ? "x" : "y"] ? this.options.stepping[axis == 1 ? "x" : "y"] : (this.options.realMax[axis == 1 ? "x" : "y"] / this.actualSize[axis == 1 ? "width" : "height"]) * 5;
		},
		
		translateRange: function(value,axis) {
			if (this.rangeElement) {
				if (this.currentHandle[0] == this.handle[0] && value >= this.translateValue(this.value(1),axis))
					value = this.translateValue(this.value(1,axis) - this.oneStep(axis), axis);
				if (this.currentHandle[0] == this.handle[1] && value <= this.translateValue(this.value(0),axis))
					value = this.translateValue(this.value(0,axis) + this.oneStep(axis));
			}
			if (this.options.handles) {
				var handle = this.options.handles[this.handleIndex()];
				if (value < this.translateValue(handle.min,axis)) {
					value = this.translateValue(handle.min,axis);
				} else if (value > this.translateValue(handle.max,axis)) {
					value = this.translateValue(handle.max,axis);
				}
			}
			return value;
		},
		
		handleIndex: function() {
			return this.handle.index(this.currentHandle[0])
		},
		
		translateLimits: function(value,axis) {
			if(!axis) axis = this.options.axis == "vertical" ? 2 : 1;
			if (value >= this.actualSize[axis == 1 ? "width" : "height"] - this.handleSize(null,axis))
				value = this.actualSize[axis == 1 ? "width" : "height"] - this.handleSize(null,axis);
			if (value <= 0)
				value = 0;
			return value;
		},
		
		drag: function(e, handle) {

			var o = this.options;
			var position = { top: e.pageY - this.offset.top - this.clickOffset.top, left: e.pageX - this.offset.left - this.clickOffset.left};
			if(!this.currentHandle) this.focus(this.previousHandle, true); //This is a especially ugly fix for strange blur events happening on mousemove events

			position.left = this.translateLimits(position.left,1);
			position.top = this.translateLimits(position.top,2);
			
			if (o.stepping.x) {
				var value = this.convertValue(position.left,1);
				value = Math.round(value / o.stepping.x) * o.stepping.x;
				position.left = this.translateValue(value, 1);	
			}
			if (o.stepping.y) {
				var value = this.convertValue(position.top,2);
				value = Math.round(value / o.stepping.y) * o.stepping.y;
				position.top = this.translateValue(value, 2);	
			}
			
			position.left = this.translateRange(position.left, 1);
			position.top = this.translateRange(position.top, 2);

			if(o.axis != "vertical") this.currentHandle.css({ left: position.left });
			if(o.axis != "horizontal") this.currentHandle.css({ top: position.top });
			
			if (this.rangeElement)
				this.updateRange();
			this.propagate('slide', e);
			return false;
		},
		
		moveTo: function(value, handle, noPropagation) {
			var o = this.options;
			if (handle == undefined && !this.currentHandle && this.handle.length != 1)
				return false; //If no handle has been passed, no current handle is available and we have multiple handles, return false
			if (handle == undefined && !this.currentHandle)
				handle = 0; //If only one handle is available, use it
			if (handle != undefined)
				this.currentHandle = this.previousHandle = $(this.handle[handle] || handle);



			if(value.x !== undefined && value.y !== undefined) {
				var x = value.x;
				var y = value.y;
			} else {
				var x = value, y = value;
			}

			if(x && x.constructor != Number) {
				var me = /^\-\=/.test(x), pe = /^\+\=/.test(x);
				if (me) {
					x = this.value(null,1) - parseInt(x.replace('-=', ''), 10);
				} else if (pe) {
					x = this.value(null,1) + parseInt(x.replace('+=', ''), 10);
				}
			}
			
			if(y && y.constructor != Number) {
				var me = /^\-\=/.test(y), pe = /^\+\=/.test(y);
				if (me) {
					y = this.value(null,2) - parseInt(y.replace('-=', ''), 10);
				} else if (pe) {
					y = this.value(null,2) + parseInt(y.replace('+=', ''), 10);
				}
			}

			if(o.axis != "vertical" && x) {
				if(o.stepping.x) x = Math.round(x / o.stepping.x) * o.stepping.x;
				x = this.translateValue(x, 1);
				x = this.translateLimits(x, 1);
				x = this.translateRange(x, 1);
				this.currentHandle.css({ left: x });
			}

			if(o.axis != "horizontal" && y) {
				if(o.stepping.y) y = Math.round(y / o.stepping.y) * o.stepping.y;
				y = this.translateValue(y, 2);
				y = this.translateLimits(y, 2);
				y = this.translateRange(y, 2);
				this.currentHandle.css({ top: y });
			}
			
			if (this.rangeElement)
				this.updateRange();
			
			if (!noPropagation) {
				this.propagate('start', null);
				this.propagate('stop', null);
				this.propagate('change', null);
				this.propagate("slide", null);
			}
		}
	});
	
	$.ui.slider.defaults = {
		handle: ".ui-slider-handle"
	};

})(jQuery);

// superclass for hovering pages

LovelyHoverPage = function() {
  this.container_id;
  this.url;
  this.blurClass="black";
}

LovelyHoverPage.prototype.toString = function() {
    return "["+this.controller+" "+this.url+"]"
}

LovelyHoverPage.prototype.load = function (url) {
  
  this.manager = LPM;
  this.url = url ? url : this.url;
  if (!this.url) {
      error('no url for hoverpage found:', this);
      return;
  }
  
  var len = this.url.split("/").length;
  this.baseUrl = this.url.split("/", len-1).join('/');
  this.viewUrl = this.url.split("/")[len-1]

  LHM.loadHover(this);
}

LovelyHoverPage.prototype.generateUrl = function() {
  return this.baseUrl + "/" + this.viewUrl;
}

LovelyHoverPage.prototype.___onHidden = function (abort) {
  this.__onHidden(abort);
  this._onHidden();
  this.onHidden();
}

LovelyHoverPage.prototype.___onShown = function () {
  this._beforeShown();
  this.__onShown();
  this._onShown();
  this.onShown();
}

LovelyHoverPage.prototype.__onHidden = function (abort){
  if (!abort && this.refreshOnClose || this.forceRefresh) {
      //refresh all set classes if not aborted
      var refreshes = this.refreshOnClose.split(' ');
      for (var i=0; i<refreshes.length;i++) {
          this.manager.refreshCssClass({
            cssClass : refreshes[i]
          });
      }
  }
}

LovelyHoverPage.prototype.hide = function(abort) {
    LHM.hideHover(this, abort);
}

LovelyHoverPage.prototype.show = function() {
    LHM.showHover(this);
}

LovelyHoverPage.prototype.__onShown = function (){

  var self=this;

  this.manager.ajaxify($(this.container_id))
  
  $('.ajax_closehover', $(this.container_id)).
    css('cursor', 'pointer').
    removeClass(".ajax_closehover").
    bind("click", function(e) {
        e.preventDefault();
        self.hide(true);
    });

  $('.ajax_closeallhovers', $(this.container_id)).
    css('cursor', 'pointer').
    removeClass(".ajax_closehover").
    bind("click", function() {
        LHM.closeAll(true);
    });
  
  window.scrollTo(0,0);
//  LPM.trigger.hoverPageReady();
}

LovelyHoverPage.prototype.getContainer = function() {
  return $(this.container_id);
}

LovelyHoverPage.prototype.hoverIsVisible = function() {
  return $(this.hover_id).css("display") != "none";
}

LovelyHoverPage.prototype._beforeShown = function () {
  //override in subclass
}

LovelyHoverPage.prototype._onShown = function () {
  //override in subclass
}
LovelyHoverPage.prototype._onHidden = function () {
  //override in subclass
}
LovelyHoverPage.prototype.onShown = function () {
  //override in subclass
}
LovelyHoverPage.prototype.onHidden = function () {
  //override in subclass
}

/* hover depth manager */
LovelyHoverManager=function() {}

LovelyHoverManager.prototype.init = function() {
  this.CONTAINER = $("div#hover-container");
  this.BLUR = $("div#hover-filter");
  this.pages = [];
  this.pagesById = {};
}
LovelyHoverManager.prototype.loadHover = function(page) {

  warn("loadhover: ", page.id, page);
  if (this.pagesById[page.id]) {
       this.showHover(this.pagesById[page.id]);
  } else {
      //clear the container if no hoverpage is present
      if (!this.pages.length) this.CONTAINER.empty();
 
      this.pagesById[page.id] = page;
      this.pages.push(page);
      var index = this.pages.length;
      var cid = "hover"+index;

      if (!$('div#'+cid, this.CONTAINER).length) {
        this.CONTAINER.append('<div id="'+cid+'"></div>');
      }
  
      page.container_id = 'div#'+cid;
      
      var self=this;
      page.getContainer().load(
          page.generateUrl(),
          function(data) {
            self.showHover(page);
      });
  }
}

LovelyHoverManager.prototype.showsDashboard = function() {
  if (this.getCurrentHover()) {
    return this.getCurrentHover().viewUrl.indexOf("dashboard") != -1
  } else return false;
}

LovelyHoverManager.prototype.getHoverURl = function() {
  if (this.getCurrentHover()) {
    return this.getCurrentHover().viewUrl;
  } else return false;
}

LovelyHoverManager.prototype.showHover = function(page) {
  
  //consider the page's blurcolor
  this.blurClass=page.blurClass

  //show all other page
  for (var p in this.pagesById) {
      this.pagesById[p].getContainer().hide();
  }

  page.getContainer().show();

  this.CONTAINER.addClass("active");
  this.BLUR.removeClass("black").removeClass("active");
  this.BLUR.addClass(this.blurClass);
  
  this.createEscapes();  
  page.___onShown();
  LPM.onHoverShown(page);
}

LovelyHoverManager.prototype.closeAll = function() {
  this.CONTAINER.removeClass("active");
  this.BLUR.removeClass(this.blurClass);
  this.cleanup();
  LPM.setPageTitle("Magazine");
}

LovelyHoverManager.prototype.cleanup = function() {
  this.CONTAINER.empty();
  this.pages = [];
  this.pagesById = {};
}

LovelyHoverManager.prototype.hideHover = function(page, abort) {
  
 page.getContainer().remove();
  
 for (var i=0; i<this.pages.length;i++) {
   if (this.pages[i] == page) {
     this.pages.splice(i, 1);
    }
 }
 
 delete this.pagesById[page.id];
  
  if (this.pages.length == 0) {
    //close hover if no page is left
    this.closeAll();
  } else {
    //show the previous page otherwise
    this.showHover(this.pages[this.pages.length-1]);
  }
  
  page.___onHidden(abort);
}

LovelyHoverManager.prototype.getCurrentHover = function() {
  return this.pages[this.pages.length-1];
}

LovelyHoverManager.prototype.destroyCurrentHover = function() {
  this.hideHover(this.getCurrentHover());
}

LovelyHoverManager.prototype.destroyHoverByUrl = function(url) {
    var page = this.getHoverByUrl(url);
    log(page);
    this.hideHover(page);
}

LovelyHoverManager.prototype.getHoverByUrl = function(url) {
    var url = url.replace('.html', '.ajax');
    log(this.pages, this.pagesByUrl);
    
    for (var i=0; i<this.pages.length;i++) {
        log(i, this.pages, this.pages[i], this.pages[i].url, url);
        if (this.pages[i].url==url) {
            return this.pages[i];
        }
    }
    
    /*
    for (var p in this.pagesById) {
        if (this.pagesById[p].url == url) {
            log(p, this.pagesById[p]);
            return this.pagesById[p];
        }
    }*/
    
    return null;
}

LovelyHoverManager.prototype.blockScrolling = function() {
  if($.browser.msie) $('html').css('overflow', 'hidden');
  else $('body').css('overflow', 'hidden');
  
  $('body').width('100%');
  
}
LovelyHoverManager.prototype.enableScrolling = function() {
  if($.browser.msie) $('html').css('overflow', 'auto');
  else $('body').css('overflow', 'auto');
  
  $('body').width('auto');
  
}

LovelyHoverManager.prototype.createEscapes = function() {
  //create escape possibiliies
  //click on the hover-area
/*
  var self=this;
  $(this.container_id).bind("mouseout", function(){
    $(self.hover_id).bind("click", function() {
      self.hide();
    })
  })
  $(this.container_id).bind("mouseover", function(){
    $(self.hover_id).unbind("click");
  })
*/  
  //press the escape-key
/*
  var self=this;
  $('body').bind('keydown', function(e) {
  'keyup')
  })
*/
}

LovelyInlineForm = function() {}
LovelyInlineForm.prototype.init = function(mgr, config) {
  
  this.manager=mgr;
  this.form = config.form;
  this.target = config.target;

  this.loadingAnimation = "/++resource++img/anim-loading.gif";

  this.isIFrameBased = config.iframebased;

  if (this.isIFrameBased) this.iFrameHijack();
  else this.ajaxHijack();
};

LovelyInlineForm.prototype.ajaxHijack = function() {
  
  var self=this;
  var options = {
    success: function(data) {
      self.handleResponse(data);
    },
    beforeSubmit: function(){
      self.beforeSubmit();
    }
  };
  this.form.ajaxForm(options);
  this.onHijacked();
}

LovelyInlineForm.prototype.iFrameHijack = function() {
  
  /* if you want to set a form iframebased, you have to wrap your form
     into a <div id="formenvelope"> and return the formid generated here as
     an attribute 'ajax:formid' on the formenvelope-node:
     <div id="formenvelope" ajax:formid="xyz">
     also include a script-tag at the end of the form template (see addform_macro.pt)
  */

  var id=new Date().getTime();
  //register at the pagemanager to handle iframe-responses
  this.manager.registerIFrameForm(id, this);
  
  //insert the formid as input field, so we can recoginze responses
  this.form.append("<input name='formId' type='hidden' value='"+id+"' />");

  //set the iframe as the target
  this.form.attr("target", "formsubmitframe");

  var self=this;
  this.form.bind("submit", function() {
    return self.beforeSubmit();
  })

  this.onHijacked();
}

LovelyInlineForm.prototype.beforeSubmit = function() {
  var img = $('<img alt="loading" />')
  img.attr("src", this.loadingAnimation);
  $('input[type=submit]', this.form).hide().after(img);
}


LovelyInlineForm.prototype.handleIFrameResponse = function(form) {
  this.handleResponse(form.html());
}

LovelyInlineForm.prototype.handleResponse = function(data) {
  
  if (!this.target.length) error("inline form target not found:", data);
  
  this.target.empty().html(data);
  this.manager.ajaxify(this.target);
}

LovelyInlineForm.prototype.onHijacked = function(){
  //overwrite in possible subclass
  this.initComplimentTypeChooser();
}

LovelyInlineForm.prototype.initComplimentTypeChooser = function(){
  var self=this;
  $('div.complimenttypes div', this.form).bind('click', function(){
    
    var type=$(this).attr('ajax:name');
    var text=$(this).attr('ajax:defaulttext');
    
    $('input[@id=form.type]', self.form).val(type);
    $('textarea[@id=form.text]', self.form).val(text);
    
    self.highlightComplimentCategory(type);
  });
}

LovelyInlineForm.prototype.highlightComplimentCategory = function(type) {
  $('div.complimenttypes div', this.form).each(function (){
      if ($(this).attr('ajax:name')==type) {
        $(this).addClass('active');
      } else {
        $(this).removeClass('active');
      }
  });
}


// --------------------------------------------- superclass for hovering form //

LovelyHoverForm = function(manager) {
  this.isForm=true;
  this.manager=manager;
  this.loadingAnimation = "/++resource++img/anim-loading.gif";

  this.context;
  this.formId;
  this.form;
  
  this.updateAfterClose = true;
  this.showResponse = true;

  this.validateSteps = false;
  this.validators=[];
  
  this.existingEnabled = true;
  this.isIFrameBased = false;
}

LovelyHoverForm.prototype = new LovelyHoverPage();

LovelyHoverForm.prototype._onHidden = function() {
  if (this.updateAfterClose) {
  var self = this;
    
    /* refresh css class after close */
    
    if (this.getEnvelope().attr("ajax:refreshafterclose")) {
      var refresh = this.getEnvelope().attr("ajax:refreshafterclose");
      this.manager.refreshCssClass({cssClass : refresh,
                                    finishCallback : function() {
                                      LPM.ajaxify(self.getEnvelope());
                                    }});
    }
  }
}

LovelyHoverForm.prototype.getEnvelope = function() {
  return $('div#formenvelope', this.context);
}

LovelyHoverForm.prototype._beforeShown = function() {
  this.context=$(this.container_id);

  //check a possible responsesuccess and close emediatly
  if (this.getEnvelope().attr("ajax:success")=="True") {
      this.hide();
  }
  
  //set existings enabled if present as attributes
  var ee = this.getEnvelope().attr('ajax:existingenabled')

  if (ee=="true") this.existingEnabled=true;
  else if (ee=="false") this.existingEnabled=false;
  
  if ($('fieldset', this.context).length) this.setupSteps();

}

LovelyHoverForm.prototype._onShown = function() {
  this.form=$('form:first', $(this.container_id));
  
  this.enablePreview();
  //this.manager.ajaxify()
  
  if (this.validateSteps) this.enableValidation();
  
  this.initStreetCheck();
  
  if (this.isIFrameBased) {
    this.iFrameHijack();
  } else {
    this.ajaxHijack();
  }
  this.blockEnterKeySubmit();
   
  //hide titlesearch caption
  //var desc = $('div.ts-description', this.form);
  //if (desc.length) desc[0].css('visibility', 'hidden');

  allInputs= $(":input",this.form);
  if(allInputs.length > 0) allInputs[0].focus();
}

LovelyHoverForm.prototype.ajaxHijack = function() {
  
  var self=this;
  var options = {
    success: function(data) {
      self.handleResponse(data);
    },
    beforeSubmit:function(data, form, options) {
      return self.beforeSubmit();
    }
  };
  this.form.ajaxForm(options);
  this.onHijacked();
}

LovelyHoverForm.prototype.iFrameHijack = function() {
  
  var id=new Date().getTime();
  var self=this;
  //register at the pagemanager to handle iframe-responses
  this.manager.registerIFrameForm(id, this);
  
  //insert the formid as input field, so we can recoginze responses
  this.form.append("<input name='formId' type='hidden' value='"+id+"' />");

  //set the iframe as the target
  this.form.attr("target", "formsubmitframe");
  
  this.form.bind("submit", function() {
    return self.beforeSubmit();
  })
  
  this.onHijacked();
}

LovelyHoverForm.prototype.onHijacked = function() {}

LovelyHoverForm.prototype.beforeSubmit = function() {
  
  var img = $('<img alt="loading" />')
  img.attr("src", this.loadingAnimation);
  img.css("float", "right");
  
  $('input[type=submit]', this.form).hide().after(img);
}

LovelyHoverForm.prototype.setupSteps = function() {
  var self=this;
  
  //attach the clickactions to the stepbuttons
  $(".ajax_nextstep", this.context).bind("click", function() {
    //abort if not valid
    cont=true;
    if (self.validateSteps) {
      self.validateStep(self.currentStep);
      self.showValidationProgress(); 
    } else {
      self.currentStep++;
      self.gotoStep(self.currentStep);
    }
  });
  
  $(".ajax_prevstep", this.context).bind("click", function() {
    self.currentStep--;
    self.gotoStep(self.currentStep);
  })
  
  //attach actions to the existbuttons
  $(".ajax_reject").bind("click", function(){
    self.rejectExistingItem();
  })
  $(".ajax_confirm").bind("click", function(){
    self.confirmExistingItem();
  })
  
  this.currentStep=0;
  this.currentBlock=$("fieldset", this.context).eq(0);
  
  this.setupLatLonWidget(this.currentBlock);
  
  //hide all other steps
  $("fieldset", this.context).slice(1).hide();
}

LovelyHoverForm.prototype.showValidationProgress = function() {
  var img = $('<img class="ajax_validprogress" alt="validating" />')
  img.attr("src", this.loadingAnimation);
  img.css("float", "right");
  
  var fieldset = $('fieldset', this.context).slice(this.currentStep, this.currentStep+1);
  $('.ajax_nextstep', fieldset).hide().after(img);
}

LovelyHoverForm.prototype.hideValidationProgress = function(fs) {
  $('img.ajax_validprogress', this.context).remove();
  $('.ajax_nextstep', this.context).show();
}

LovelyHoverForm.prototype.gotoStep = function(nr) {
  log("gotoStep: ",nr);
  this.currentBlock.hide();
  this.currentBlock=$("fieldset", this.context).eq(nr);
  this.currentBlock.show();
  
  this.onStepChanged(this.currentBlock);
}

LovelyHoverForm.prototype.setupLatLonWidget = function (con) {
  
  var context = con || $('body');
  
  if (!$("div#as-mapcontainer", context).length) return;
  
  //extract startup position or use global mapstartup
  var lat = $('input[@id=form.lat]', this.form).val() || this.manager.getGlobals().mapStartUp.c_lat;
  var lon = $('input[@id=form.lon]', this.form).val() || this.manager.getGlobals().mapStartUp.c_lon;
  var zoom = $('input[@id=form.lat]', this.form).val() ? 17 : 12;
  
  var type = this.getEnvelope().attr("ajax:mapfilter");
  
  widget_create('as-mapcontainer', lat, lon, zoom, type, 0);
  
  this.currentAddress = {
    lat : $('input[@id=form.lat]', this.context).val(),
    lon : $('input[@id=form.lon]', this.context).val(),
    street : $('input[@id=form.street]', this.context).val(),
    city : $('input[@id=form.city]', this.context).val(),
    zip : $('input[@id=form.zip]', this.context).val(),
    district : $('input[@id=form.district]', this.context).val()
  }
}

LovelyHoverForm.prototype.validateStep = function(step) {
  //overwrite this in subclass
  return true;
}

LovelyHoverForm.prototype.onStepValidated = function(step, success) {
  
  log("step was validated: ",step,": ",success);

  this.hideValidationProgress();
  
  if (success) {
    this.currentStep=step+1;
    this.gotoStep(this.currentStep);
  }
}

LovelyHoverForm.prototype.enablePreview = function () {
  var self=this;
  
  //update at first
  $('input[@type="text"], textarea', this.context).each(function(i) {
    var val = $(this).val();
    var name = $(this).attr("name");
    self.updatePreview(name, val);
  })
  
  
  //bind events
  $('input[@type="text"], textarea', this.context).bind("change", function() {
    var val = $(this).val();
    var name = $(this).attr("name");
    self.updatePreview(name, val);
  });
}

LovelyHoverForm.prototype.updatePreview = function(field, val) {
  
  log("updateing preview: ",field,", ",val)
  
  var pb = $('dl.preview', this.form);
  
  //$('dd[@ajax:field='+field+']', pb).html(val);
  
  $('dd', pb).each(function() {
    if ($(this).attr('ajax:field') == field) {
      $(this).text(val);
    }
  });
}

//triggered by the locationwidget, when a now location was selected
LovelyHoverForm.prototype.onLocationChange = function(data) {
  this.updatePreview('form.street', data.street+" " + data.number+", " + data.district);
  //remove the error class as a location is set now
  
  var lwblock = $('div.inputblock.locationwidget',  this.context);
  lwblock.removeClass("error");
  lwblock.children(".info").html("Perfekt!");
}

//triggered by the genderselector
LovelyHoverForm.prototype.onGenderChange = function(val) {
  
  var german = val == "female" ? "weiblich" : "männlich";
  
  this.updatePreview('form.gender', german);
  //remove the error class as a gender is set now
  var gblock = $('div.inputblock.gender',  this.context);
  gblock.removeClass("error");
  gblock.children(".info").html("Perfekt!");
}

LovelyHoverForm.prototype.handleIFrameResponse = function(envelope, doc) {
  this.handleResponse(envelope);
}

LovelyHoverForm.prototype.handleResponse = function(response) {

  var envelope = $(response);

  var con = this.onResponse(response);
  if (con == false) return;
  
  //check the responsesuccess
  if (envelope.attr("ajax:success")=="True") {
      this.hide();
  }
  
  //check for form redirects and abort in case
  var cont = this.manager.handleFormRedirects(envelope); 
  if (cont == false) return;

  if (this.isIFrameBased) if ($.browser.msie || $.browser.safari) response = response.html();

  $(this.container_id).empty().append(response);
  this._beforeShown();
  this.__onShown();
  this._onShown();
  this.onShown();
}

//return false here if you don't want to work with the response
LovelyHoverForm.prototype.onResponse = function(response) {
   //destroy the current hover if a item was deleted
   if ($(response).attr('ajax:deletedobject')) {
        //if an item was deleted we close its hover
        eval("var deleted=" + $(response).attr('ajax:deletedobject'));
        LHM.destroyHoverByUrl(deleted.url);
    }
  return true;
}

LovelyHoverForm.prototype.blockEnterKeySubmit = function (){
  
  //prevent submit by return-key
  //this.form.attr("onsubmit", 'javascript:return false');
  
  this.form.bind("keydown", function(e) {
    if (e.keyCode == 13) $(this).attr("onsubmit", 'javascript:return false');
  })
  this.form.bind("keyup", function(e) {
    if (e.keyCode == 13) $(this).removeAttr("onsubmit");
  });
  
}

LovelyHoverForm.prototype.lockPosition = function() {
  //this.manager.locationWidget.disable();
}

LovelyHoverForm.prototype.enableValidation = function() {
  
  if (!this.validationService) {
    error("no validationService defined. abort form validation");
    return;
  };
  
  var self = this;
  this.validateSteps = true;
  this.validators=[];
  
  this.validatorsByName={};
  
  //bind the validation to each field with class ajax_validate
  var self=this;
  $('fieldset', this.context).each(function(i){
    var fieldset=this;
    var fieldsetindex=i;
    $('.ajax_validate', $(fieldset)).each(function(){
    
      if ($(this).attr("ajax:valfield")) {
        var field=$("*[@id="+$(this).attr("ajax:valfield")+"]");
        if (!field) {
          error("ValidationField could not be found: " + $(this).attr("ajax:valfield"));
          return;
        }
      } else {
        var field = $('input, textarea', $(this));
      }
      
      if ($(this).attr("ajax:valtype")=="multiple") {
        var type = 'multiple';
        
        var addfields = $(this).attr("ajax:valfields");
        var addfield_array=[];
        if (addfields) {
          f = addfields.split(";");
          for (var i=0; i < f.length; i++) {
            addfield_array.push($('input[@id='+f[i]+']', $(fieldset)));
          }
        }
         
        
      } else {
        var type ="single";
      }
      
      //create a validator for the field
      var validator = new LovelyFieldValidator();
      
      var basicinit = self.configFieldValidator($(this));
      
      var init = {
        event : 'blur',
        field : field,
        form : self.form,
        serviceurl : self.validationService,
        type : type,
        additionalfields : addfield_array
      };
      
      //add all basic properties
      for (var p in basicinit) init[p] = basicinit[p];
      
      validator.init(init);
      
      self.validatorsByName[field.attr("name")]=validator;
      
      //organize the validators in groups for step validation
      if (!self.validators[fieldsetindex]) self.validators[fieldsetindex] = [];
      self.validators[fieldsetindex].push(validator);
    });
  });
}

LovelyHoverForm.prototype.configFieldValidator = function(markedElement) {
    return {
        errorhandler : markedElement.parent(),
        msghandler : markedElement.parent().children('.info'),
        errorClass : 'error'
    }
}

LovelyHoverForm.prototype.getValidatorByFieldName = function(name) {
  return this.validatorsByName[name];
}


LovelyHoverForm.prototype.updateAddressBySearchResult = function(node, search) {
  
  this.chosenAddress = {
    district : $(node).attr("ajax:district"),
    lat : $(node).attr("ajax:lat"),
    lon : $(node).attr("ajax:lon"),
    street : $(node).attr("ajax:street"),
    number : $(node).attr("ajax:number"),
    zip : $(node).attr("ajax:zip"),
    city : $(node).attr("ajax:city")
  };
  
  this.writeAddressValues(this.chosenAddress);
  search.hide();
  //widget_set_center(this.chosenAddress.lat, this.chosenAddress.lon, 17);
}

LovelyHoverForm.prototype.updateAddressByMapPosition = function(lat, lon) {
  
  //ignore the update if its the default lat and lon
  //otherwise, there always will be a preselected position visible for the user
  var clat = this.manager.getGlobals().mapStartUp.c_lat;
  var clon = this.manager.getGlobals().mapStartUp.c_lon;
  if ((lat==clat) && (lon==clon)) return;
    
  var self=this;
  var searchlat = lat;
  var searchlon = lon;
  $.getJSON('revlocation',
            {lat:lat,
             lon:lon},
             function(data) {
               self.onAddressResolved(data, searchlat, searchlon);
             });
  log("update address by map position: ",lat,", ",lon);
}

LovelyHoverForm.prototype.onAddressResolved = function(data, searchlat, searchlon) {
  this.chosenAddress = {
    district : data.district,
    lat : searchlat,
    lon : searchlon,
    street : data.street,
    number : data.number,
    zip : data.zip,
    city : data.city
  };
  
  var self=this;
  
  //check the distance between map and current location
  //if > 100, we also update the entered address
  
  if (this.currentAddress.lat && this.currentAddress.lon) {
      LPM.map.resolvePointDistance({lat:this.currentAddress.lat,
                                    lon:this.currentAddress.lon},
                                   {lat:this.chosenAddress.lat,
                                    lon:this.chosenAddress.lon},
                                   function(distance){
                                     if (distance < 100) self.writeAddressValues(self.chosenAddress, true, true)
                                     else self.writeAddressValues(self.chosenAddress, true)
                                   })
  } else {
      this.writeAddressValues(this.chosenAddress, true)
  }
}

LovelyHoverForm.prototype.writeAddressValues = function (obj, noupdate, leaveValues) {


  $('input[@id=form.lat]', this.context).val(obj.lat);
  $('input[@id=form.lon]', this.context).val(obj.lon);
  
  if (!leaveValues) {
    $('input[@id=form.street]', this.context).val(obj.street + " " + obj.number);
    $('input[@id=form.city]', this.context).val(obj.city);
    $('input[@id=form.zip]', this.context).val(obj.zip);
    $('input[@id=form.district]', this.context).val(obj.district);
    this.currentAddress = obj;
  }

  //update the map
  if (!noupdate) widget_set_center(obj.lat, obj.lon, 17);

  //after write, the validation should match TODO: find a nicer way
  $('input[@id=form.street]', this.context).parent().parent().removeClass('error');
  $('input[@id=form.street]', this.context).parent().parent().children('.info').html("Perfekt");

  //and preview should be updated
  this.updatePreview('form.street', $('input[@id=form.street]', this.context).val());
}

LovelyHoverForm.prototype.initStreetCheck = function() {
  var self = this;
  $('input[@name=form.street]').bind('blur', function(){
    self.checkStreetValue($(this).val());
  });
}

LovelyHoverForm.prototype.checkStreetValue = function(value) {
  var self=this;
  $.getJSON(this.manager.getGlobals().portalUrl+"/@@geolocation",
            {address:value},
            function(response) {
              self.onStreetValueChecked(response);
            });
}

LovelyHoverForm.prototype.onStreetValueChecked = function(response) {
  var self=this;
  if (response) {
    if (response.length==1) {
      self.writeAddressValues(response[0]);
      self.getValidatorByFieldName("form.street").validate();
    }
  }
}

LovelyHoverForm.prototype.showExistingItemPreview = function(node, form) {
  
  //abort if no existings enabled
  if (!this.existingEnabled) return;
  
  var preview = $('fieldset.existingpreview', this.context);
  
  $("div.title", preview).html($(node).attr('ajax:title'));
  $("div.street", preview).html($(node).attr('ajax:street'));
  $("div.city", preview).html($(node).attr('ajax:zip') + " " + $(node).attr('ajax:city') + ", " + $(node).attr("ajax:district"));
  
  var lat = $(node).attr('ajax:lat');
  var lon = $(node).attr('ajax:lon');
  var uid = $(node).attr('ajax:uid');
  var type = $('#formenvelope').attr("ajax:mapfilter");
  
  //store the existing item uid which is used in the zope formaction
  if (!$('input[@id=form.existingId]').length) {
    this.form.append("<input type='hidden' id='form.existingId' name='form.existingId' />");
  }
  $('input[@id=form.existingId]').val(uid);
  
  this.currentBlock.hide();
  preview.show();

  widget_create('co-mapcontainer', lat, lon, 17, type, 1);
}
LovelyHoverForm.prototype.rejectExistingItem = function() {
  this.currentBlock.show();
  $('fieldset.existingpreview', this.context).hide();  
  
  //delete the existing form value set in showExistingItemPreview
  $('input[@id=form.existingId]').val('');
}

LovelyHoverForm.prototype.onStepChanged = function(step) {
  this.setupLatLonWidget(step);
}

LovelyHoverForm.prototype.showMapItemList = function(html) {
  $('div#as-discovered', this.form).empty().append(html);
  
  if (this.existingEnabled) {
    var self=this;
    $('div.shortsearchresult', this.form).bind("click", function() {
      self.showExistingItemPreview(this, self);
    });
  } else {
    //disable active styles for searchresult
    $('div.shortsearchresult', this.form).css('margin-bottom', '5px');
  }
}

// LovelyAddForm Class -------------------------------------------------------------------

LovelyAddForm = function(manager, type, lat, lon) {
  
  this.manager=manager;
  this.type=type; //add or addandcollect
  this.startup_lat=lat;
  this.startup_lon=lon;
  this.showResponse = false;

  this.isIFrameBased = true;
  
  this.validateSteps = true;
  this.validationService = "addformvalidate";

  //disable existing for editforms
  if (type=='edit') this.existingEnabled = false;
}

LovelyAddForm.prototype = new LovelyHoverForm();

LovelyAddForm.prototype.generateUrl = function() {
  var url;
  
  if (this.type == "add") {
    url = this.baseUrl + "/latlon/"+this.startup_lat+"/"+this.startup_lon+"/@@"+this.viewUrl;
  } else if (this.type == "addandcollect") {
    url = this.baseUrl + "/latlon/"+this.startup_lat+"/"+this.startup_lon+"/fa/collectunique/"+this.collection+"/@@"+this.viewUrl;
  } else {
    url = this.baseUrl + "/" + this.viewUrl;
  }

  log("generate addform url: ",url);
  return url;
}

LovelyAddForm.prototype.validateStep = function(step) {
  if (this.validators[step]) {
    this.groupvalidator = new LovelyGroupValidator();
    this.groupvalidator.init(this.validators[step], step);
    this.groupvalidator.validate(this, "onStepValidated");
  } else {
    this.onStepValidated(step, true);
  }
}

LovelyAddForm.prototype.onResponse = function(response) {
    
    if ($(response).attr('ajax:createdobject')) {
        //if an item was created, we show its page
        eval('var created='+$(response).attr('ajax:createdobject'));
        log("onresponse", created, $(response), $(response).attr('ajax:createdcreatedect'));
        var url = created.url.replace(".html", ".ajax");
        var page = new LovelyAjaxPage();

        page.url = url;
        page.itemId = created.id;
        page.target = $(AjaxCommands.hoverItemContainer);
        var id = LPM.registerAjaxPage(page);
        LPM.showItemPage(id);
        return false;
    }
}


/*
  set the collection name, if the created item should be
  collected after creation
*/
LovelyAddForm.prototype.setCollection = function(col) {
  this.collection=col;
}



LovelyEditForm = function(manager) {
  this.type="edit"
}
LovelyEditForm.prototype = new LovelyAddForm();


//Lovely complimentform ------------------------------------------------------


LovelyComplimentForm = function(manager, recipient) {
  this.manager=manager;
  this.recipient=recipient;
  this.isIFrameBased = false;
}

LovelyComplimentForm.prototype = new LovelyHoverForm();

LovelyComplimentForm.prototype.onHijacked = function () {
    this.initCategories();
}
  
LovelyComplimentForm.prototype.initCategories = function () {
  var self=this;
  
  $('div.complimenttypes div', this.form).bind("click", function() {
    var type=$(this).attr("ajax:name");
    var text=$(this).attr('ajax:defaulttext');
    
    $('input[@name="form.type"]', this.form).val(type);
    $('textarea[@name="form.text"]', this.form).val(text);
        
    self.highlightCategory(type);
  });
}

LovelyComplimentForm.prototype.highlightCategory = function(type) {
  $('div.complimenttypes div', this.form).each(function (){
      if ($(this).attr('ajax:type')==type) {
        $(this).addClass('active');
      } else {
        $(this).removeClass('active');
      }
  });
}

/* lovely registration form ----------------------------------------- */

LovelyRegistrationForm = function(manager) {
  this.manager = manager;
  this.updateAfterClose = false;
  
  //validator handling
  this.validateSteps = true;
  this.validationService = "regvalidate";
  this.existingEnabled = false;
  this.isIFrameBased = true;
}

LovelyRegistrationForm.prototype = new LovelyHoverForm();

LovelyRegistrationForm.prototype.validateStep = function(step) {
  
  if (step == 3) {
    var agb=$("input[@id=form.agb]").fieldValue()[0] == "on";    
    if (agb) {
      this.onStepValidated(step, true);
    } else {    
      alert("Akzeptiere die AGB um fortzufahren.");
      this.onStepValidated(step, false);
    }
  } else {
    if (this.validators[step]) {
      //do the stepvalidation if validateable fields are in the step
      this.groupvalidator = new LovelyGroupValidator();
      this.groupvalidator.init(this.validators[step], step);
      this.groupvalidator.validate(this, "onStepValidated");
      return false;
    } else {
      //no validateable field present just return true
      this.onStepValidated(step, true);
    }
  }
}

LovelyLeaveTrailForm = function(manager) {
  this.manager = manager;
}

LovelyLeaveTrailForm.prototype = new LovelyHoverForm();

LovelyLeaveTrailForm.prototype.onHijacked = function() {
  //init the preview
  var self=this;

  $('textarea[@id=form.description]', this.form).bind("keyup", function() {
    $('span.ajax_updatetrail', self.form).html($(this).val());
  });
  
  val = $('textarea[@id=form.description]', this.form).val();
  if (val) $('span.ajax_updatetrail', this.form).html(val);
}


LovelyLoginForm = function(manager, loginmanager) {
  this.manager = manager;
  this.loginmanager = loginmanager;
}
LovelyLoginForm.prototype = new LovelyHoverForm();
LovelyLoginForm.prototype.onResponse = function(response) {
  var status = $(response).attr("ajax:formstatus");
  var response = this.loginmanager.handleStatus(status);
  return response;
}

/* lost password form */

LovelyLostPasswordForm = function(manager) {
  this.manager = manager;
}
LovelyLostPasswordForm.prototype = new LovelyHoverForm();
LovelyLostPasswordForm.prototype.onHijacked = function() {
  //set the value of jsenabled to true
  $('input[id=form.jsenabled]').val('true');
}

/* chnagepasswordform */

LovelyChangePasswordForm = function(manager) {
  this.manager = manager;
}
LovelyChangePasswordForm.prototype = new LovelyHoverForm();
LovelyChangePasswordForm.prototype.onHidden = function() {
  self.location.href = this.manager.getGlobals().portalUrl;
}

LovelyPageManager = function() {

  this.MODE_MAGAZINE = "magazine";
  this.MODE_MAP = "map";
  this.MODE_GOSSIP = "gossip";

  this.CONSUMERPATTERNS = ['\/?area\/[0-9.]*,[0-9.]*\/[0-9.]*,[0-9.]*\/[0-9]{1,2}\/[a-zA-Z0-9%üöäÜÖÄ]+',
                           '\/?coord\/[0-9.]*\/[0-9.]*\/[0-9]{1,2}',
                           '\/?district\/[a-zA-Z0-9%üöäÜÖÄ]+',
                           '\/?liked\/[a-zA-Z0-9_]*',
                           '\/?tracked\/[a-zA-Z0-9_]*',
                           '\/?batch[0-9]*\/[0-9]*',
                           '\/?current',
                           '\/?recent'];
  this.AREAPAT = this.CONSUMERPATTERNS[0];
  
  this.pageTitleSuffix = " - meinberlin.de";

  this.pages = {};
  this.hovers = {};
  this.modePages = {};
  this.formsById = {};
  this.filters = {};
  this.batches = [];
  this.currentPage;

  this.filters = {
      'HomeFolder' : false,
      'Event' : false,
      'News' : false,
      'Place' : false,
      'all' : false
  };

  this.addFormViews = {
    newsitem : "addNewsItem.ajax",
    news : "addNewsItem.ajax",
    event : "addEvent.ajax",
    place : "addPlace.ajax",
    note : "addNote.ajax"
  };

  this.attachFormViews = {
    newsitem : "attachNewsItem.form",
    news : "attachNewsItem.form",
    event : "attachEvent.form"
  };

  this.mode = this.MODE_MAGAZINE;
  this.title = false;
  this.log = false; // Enable logging on www
};

LovelyPageManager.prototype.init = function() {
  var globs = this.getGlobals();
	this.checkDebugging();
    this.map = new LovelyMapControl();
    this.mag = new LovelyMagazineControl();
    this.gossip = new GossipControl();

    this.map.init(this, this.getGlobals().mapStartUp);
    this.mag.init(this);
    this.gossip.init(this);

    this.login = new LovelyLoginManager();
    this.login.init(this);

    LHM = new LovelyHoverManager();
    LHM.init();

    this.transitions = new TransitionManager();

    this.modeSwitch = new ViewModeManager();
    this.modeSwitch.init(this);
	
	this.history = new HistoryManager();
	this.history.init(this);
	
	this.tracking = new TrackingManager();
	this.tracking.init();
	
};

LovelyPageManager.prototype.toString = function() {
    return "[LovelyPageManager object]";
};

/*
  get the globals, which can change over time and therefor are fetched
  every time needed
*/

LovelyPageManager.prototype.getGlobals = function() {

  var glob = $('span#ajax_globals');
  var ms= $('span#ajax_mapstart');

  if (glob.attr("ajax:startup")) eval("var startup = "+glob.attr('ajax:startup'));
  else var startup=false;

  var ret = {
    node : glob,
    portalUrl : glob.attr('ajax:portalUrl'),
    loginStatus : glob.attr('ajax:loginStatus'),
    loggedInUserHome : glob.attr('ajax:loggedInUserHome'),
    loggedInUserId : glob.attr('ajax:loggedInUserId'),
    startup : startup,
    mapStartUp : {
      c_lat : ms.attr('ajax:lat'),
      c_lon : ms.attr('ajax:lon'),
      zoom : ms.attr('ajax:zoom')
    }
  };

  return ret;
};

LovelyPageManager.prototype.checkDebugging = function() {
	if (this.getGlobals().portalUrl.indexOf("www")==-1)
		mbDebug = true;
};

LovelyPageManager.prototype.getUrlParam = function(name) {
  var PAT = name+"=[a-zA-z0-9/]*";
  var pair = self.location.href.match(PAT);

  if (pair) return pair[0].split("=")[1];
  else return null;

};

LovelyPageManager.prototype.pageExists = function(id) {
  if (this.pages[id]) return true;
  else return false;
};

LovelyPageManager.prototype.showSubPage = function(id) {
  var page=this.pages[id];
  var self=this;

  var fade=new LovelyFadeTransition({
    target : page.target,
    url : page.url,
    between : function() {
      self.ajaxify(page.target);
      self.highlightActivePageLink(page)
    }
  });
  this.transitions.start(fade);
};

LovelyPageManager.prototype.handleStartupParams = function(startup) {
  //if not startupparam is set we use oldurl to compose the parameters
  if (!startup) {
    var oldurl = this.getUrlParam("oldurl");
    if (oldurl) {
      if (oldurl.match('/startup/')) {
        var parts = oldurl.split("/");
        var startup = {};
        startup[parts[2]]=parts[3];
      } else {
        return false;
      }
    } else {
      return false;
    }
  }

  if (startup.firstTime) this.onFirstTime();
  else if (startup.rpk) this.onRPK();
  else if (startup.message) this.gotoMessageBox(startup);
  else return false;

  return true;
};

LovelyPageManager.prototype.onFirstTime = function() {
  var globs = this.getGlobals();
  this.showHover('LovelyHoverPage', globs.loggedInUserHome, "startup/firstTime/true/dashboard.ajax");
};

LovelyPageManager.prototype.onRPK = function() {
  var rpk = this.getGlobals().startup.rpk;
  if (rpk) this.showHover('LovelyChangePasswordForm',
                          this.getGlobals().portalUrl,
                          "++validation++"+rpk);
};

LovelyPageManager.prototype.gotoMessageBox = function(param) {

  if (this.getGlobals().loginStatus=="loggedIn") {
    var base = this.getGlobals().loggedInUserHome
              + "/section/"
              + param.message
    var view = "/dashboard.ajax";

    this.showHover('LovelyHoverPage', base, view);
  } else {
    this.login.showForm(null, param);
  }
};

LovelyPageManager.prototype.toggleFilter = function (filter, visible) {
    var value = false;
    if (['Event', 'HomeFolder', 'News', 'Place'].contains(filter)) {
        this.filters[filter] = visible;
        value = true;
    } else if (filter=="all" && visible)
        this.clearFilter();

    if(this.mode==this.MODE_MAP)
        LPM.map.syncPois();

    return value;
};

LovelyPageManager.prototype.getFilter = function() {

    var all=true;
    var filtered=[];
    for (var p in this.filters) {
      if (this.filters[p]) {
        filtered.push(p)
        all=false;
      }
    }
    if (all)
        return "all";
    else
        return filtered.join(',');
};

LovelyPageManager.prototype.enableFiltering = function(){
    this.clearFilter();
	$("#magazine-header .users").show("slow");
    var that = this;
    for (var p in this.filters) {
        $("#tab-" + p).bind("click", {p:p}, function(event){
            var value = true;
            if(that.filters[event.data.p])
                value = false;
            that.toggleFilter(event.data.p, value);
            that.showFiltered();
            return false;
        });
    }
    this.showFiltered();
};

LovelyPageManager.prototype.disableFiltering = function(){
    $("#magazine-header .users").hide("slow");
	for (var p in this.filters)
        $("#tab-" + p).unbind("click");
    this.clearFilter();
};

LovelyPageManager.prototype.clearFilter = function(){
    for (var p in this.filters)
        LPM.filters[p] = false;
};

LovelyPageManager.prototype.showFiltered = function(){
    var filter = this.getFilter().split(",");
    for (var p in this.filters)
        $("#tab-" + p).parent().removeClass("active");
    for (i=0; i<filter.length; i++)
        $("#tab-" + filter[i]).parent().addClass("active");
};

LovelyPageManager.prototype.registerIFrameForm = function(id, form) {
  this.formsById[id] = form;
};

LovelyPageManager.prototype.setMode = function(mode) {
    this.mode=mode;
    LPM.showModePage(mode);
};
LovelyPageManager.prototype.toggleMode = function(mode) {
    this.modeSwitch.switchMode(mode);
};

LovelyPageManager.prototype.gotoHood = function(lat, lon) {
    this.map.setCenterAndZoom(lat, lon, 18);
    this.onPositionChanged("street");
    if (LHM.getCurrentHover()) LHM.closeAll();
};

LovelyPageManager.prototype.onPositionChanged = function(type, data) {

    if (this.mode==this.MODE_GOSSIP) {
        this.gossip.refresh(type, data);
    } else {
        this.mag.refresh(type, data);
    }
};

LovelyPageManager.prototype.showMagazinePage = function(id) {
    var self=this;

    var consumers='';
    if (this.mode==this.MODE_MAGAZINE) var consumers = this.mag.currentConsumer;
    else if (this.mode==this.MODE_GOSSIP) var consumers = this.map.getMagazineCoordConsumerString();


    if (this.pageExists(id)) {
        var page = this.pages[id];
        var fade=new LovelyFadeTransition({target : page.target,
                                           between : function() {
                                               self.onPageShown(page);
                                           }});

        if (consumers) fade.setUrl(page.getConsumedUrl(consumers));
        else fade.setUrl(page.getUrl());

        this.transitions.start(fade);

    } else {
        error("page was not found: " + id);
    }
};

LovelyPageManager.prototype.refreshCurrentMagPage = function() {
    this.showMagazinePage(this.currentPage.id);
};

LovelyPageManager.prototype.showItemPage = function(id) {
    var self=this;
    if (this.pageExists(id)) {
        var page = this.pages[id];

        var hover = new LovelyHoverPage()
        hover.url = page.url.replace(/@@/g, '');
        hover.blurClass = "active";

        id = this.registerHover(hover);
        this.showHover(id);

        log("showItemPage", id, page, hover);

    } else {
        error("itempage was not found: " + id);
    }
};

LovelyPageManager.prototype.registerHover = function(hover) {
    var id = this.generatePageId(hover.url);
    this.hovers[id] = hover;
    this.hovers[id].id = id;
    return id;
}

LovelyPageManager.prototype.showHover = function(id) {
  var hover = this.hovers[id];
  if (!hover) error("hover was not found: ", id, this.hovers);
  else hover.load();
};

// LovelyPageManager.prototype.addPageToHistory = function (page) {
//
//   re = new RegExp(this.AREAPAT);
//   var url = page.url.replace(re, "");
//
//   if (page.getItemId()) {
//     mbH.history.page = "item"+page.getItemId();
//   } else {
//       //remove the portal url
//     url = url.replace(this.getGlobals().portalUrl+"/","");
//     url = url.replace("@@","");
//     url = url.split(".ajax")[0];
//     mbH.history.page = url;
//   }
//   //set history point
// };
//
// LovelyPageManager.prototype.showPageFromHistory = function(data) {
//   //store the data if the page was not completely initialized before
//
//   warn("show page from history: ", data);
//
//   var self=this;
//
//   if (this.pageExists(data.page))
//     this.showPage(data.page);
//   else {
//     if (data.oldurl.length > 2) {
//       this.addAjaxPage(data.page, data.oldurl + ".ajax");
//       this.showPage(data.page);
//       log("using oldurl");
//     }
//     else
//       if (data.page.indexOf("item") > -1) {
//         this.showPage(data.page); //we should use resolvepage....
//         }
//         else {
//           var url = this.getGlobals().portalUrl + "/" + data.page + ".ajax";
//           this.addAjaxPage(data.page, url);
//           this.showPage(data.page);
//           log("using vars");
//         }
//     }
// };

LovelyPageManager.prototype.onPageShown = function(page) {

  this.currentPage = page;
  this.ajaxify();

  this.handlePageEnvelope($('div#pageenvelope'));
 
  if (this.mode==this.MODE_MAGAZINE)
    this.mag.onPageChanged(page);

  this.highlightActivePageLink(page);
  
  if (this.mode==this.MODE_MAP) this.showFiltered();
  /* uncommend, if datepicker is available
  if(page.url.indexOf("events.")>-1)
  	initDatePicker();
  */
  this.setPageTitle("Magazin");
  
  this.history.addPage(page);
  
  this.tracking.track("pageReady");
  
};

LovelyPageManager.prototype.handlePageEnvelope = function(envelope) {
   //set the class of the content-div, which controls the grid-measures
  //the cssClass is retreived via the pageenvelope
  var cssClass = envelope.attr('ajax:cssClass');
  $('div#content').attr('class', cssClass);

}

LovelyPageManager.prototype.onHoverShown = function(page) {
	if (page && page.url) if (page.url.match(/index\.ajax/))
	{
		var self = this;
		var url = page.url.replace(/index.ajax/, "contentmetaview");
		$.getJSON(url, function(data){
			self.setPageTitle(data.title)			
		});
	}
	this.history.addPage(page);
	
	if (page.blurClass=="black")
		this.tracking.track("hover");
	else
		this.tracking.track("pageReady");
};

LovelyPageManager.prototype.setPageTitle = function(title) {
	document.title = title + this.pageTitleSuffix;
	this.title = title;
};

LovelyPageManager.prototype.onMapZoomChange = function() {
	error("onMapZoomChange");
};

LovelyPageManager.prototype.ajaxify = function(target) {

  var target = target || $('body');
  AjaxCommands.init(target);

};

LovelyPageManager.prototype.highlightActivePageLink = function(page) {

    function removeTrailingAts(string) {
        if(string)
            return string.replace(/@@/,"");
        else
            return string;
    }

    $('a').each(function() {
        if ($(this).attr("ajax:highlight") == "true") {
            var url = $(this).attr('ajax:url');
            var url = removeTrailingAts($(this).attr('ajax:url'));
            if (url == removeTrailingAts(page.url)) {
                $(this).addClass("active");
                $(this).parent().addClass("active");
            } else {
                $(this).removeClass("active");
                $(this).parent().removeClass("active");
            }
        }
    });
};

LovelyPageManager.prototype.nothing = function() {};

LovelyPageManager.prototype.showDistrict = function (lat, lon, name) {
  var zoom = this.map.showDistrict(lat, lon, name);
};

LovelyPageManager.prototype.setZoomLevel = function(name, lat, lon) {
  var zoom = this.map.setZoomType(name, lat, lon);
};

LovelyPageManager.prototype.handleIFrameFormResponse = function (doc) {
  
  var envelope = $('div#formenvelope', $(doc));

  var formid = envelope.attr("ajax:formid");
  var form = this.formsById[formid];
  if (form) {
    form.handleIFrameResponse(envelope, doc);
  }
};


/* called from the forms to handle redirects */
LovelyPageManager.prototype.handleFormRedirects = function(envelope) {

  //search for form redirections
  var redirect = envelope.attr("ajax:redirect");
  var redirectJS = envelope.attr("ajax:redirectJS");

  if (redirect) {
    switch (redirectJS) {

      case "showHoverForm":
        var parts = redirect.split("/");
        var base = parts.slice(0, parts.length-1).join("/");
        var view = parts[parts.length-1];
        LHM.destroyCurrentHover();
        this[redirectJS](base, view);
        return false;

      case "showPage":
        this.showPage(redirect, null, true);
        return true;

      default:
        error("Unknown javascript control for hoverform redirections: ", envelope);
        return true;
    }
  }
};

LovelyPageManager.prototype.refreshCssClass = function(options) {
    var self=this;
    var cls = options.cssClass;
        if( typeof cls  != 'string'){
            warn("no refresh class: ", self, cls, finishCallback);
        }
    var scope  = options.scope ? options.scope : $(document);
    var finishCallback = options.finishCallback;
    var eachCallback = options.eachCallback;
    var consumer = options.consumer;
    var loadAnimation = options.loadAnimation;
    var loadHtml = options.loadHtml;
    var removeConsumers = options.removeConsumers;

    var batch = new LovelyBatchLoader();

    $('.'+cls, scope).each(function(i) {
      var base=$(this).attr('ajax:base');
      var view=$(this).attr('ajax:view');
      var group=$(this).attr('ajax:group');

      var refreshUrl;

      base = self.stripOldConsumers(base, consumer);
      view = self.stripOldConsumers(view, consumer);

      if (removeConsumers) {
            base = self.stripOldConsumers(base, removeConsumers);
            view = self.stripOldConsumers(view, removeConsumers);
      }

      if (consumer) refreshUrl = base+"/"+consumer+"/"+view;
      else refreshUrl = base + "/" + view;

      //wrap the refreshable into a div if not present
      //to prevent nesting
      if ($(this).parent().attr('class') != "ajax_refreshwrapper") {
        var rw = $("<div class='ajax_refreshwrapper'></div>");
        $(this).wrap(rw);
      }

      if ((base != undefined) && (view != undefined)){
          batch.addItem($(this).parent(), refreshUrl, function() {
                LPM.ajaxify(scope); //turn normal links into ajax links after load
                if (eachCallback) eachCallback.call(this);
            });


          //show loadanimation for group mainmaglists TODO: find a generic way
          if (group=="mainmaglists") $(this).empty().append('<div style="text-align:center;width:100%;padding-top:100px"><img src="/@@/img/anim-loading-big.gif" alt="loading" /></div>');
          else if (loadAnimation) $(this).empty().append('<img src="'+loadAnimation+'" alt="loading" />');
      }
    });
    batch.load(finishCallback);
};

/*
LovelyPageManager.prototype.registerConsumer = function(group, consumer) {
    
    if (!this.consumerGroups[group]) this.consumerGroups[group] = [];
    
    var list = this.consumerGroups[group]
    var key = consumer.split('/')[0];

    //overwrite if already present
    for (var i=0; i<list.length; i++) {
        if (list[i].indexOf(key)==0) {
            this.consumerGroups[group][i]=consumer;
            return;
        }
    }
    this.consumerGroups[group].push(consumer);
}

LovelyPageManager.prototype.removeConsumer = function(group, consumer) {
    alert("implement removeConsumer");
}

LovelyPageManager.prototype.getConsumers = function(group) {
    return this.consumerGroups[group].join('/');
}
*/
LovelyPageManager.prototype.replaceOldConsumers = function(url, consumers, option) {

  //check for consumers already present in the url and replace them
  //in the consumersstring if present

  for (var i=0;i<this.CONSUMERPATTERNS.length;i++) {
      re = new RegExp(this.CONSUMERPATTERNS[i]);
      if (re.test(consumers) && re.test(url)) {
        if (option=="strip") url = url.replace(re, "");
        else url = url.replace(re, consumers.match(re)[0]);
      }
  }

  //check if only slashes TODO: solve the problem
  if (url)
  {
    for (var i=0;i<url.length;i++) {
    if (url.charAt(i) != ('/')) return url;
    }
  }
  return "";

};

LovelyPageManager.prototype.stripOldConsumers = function(url, consumers) {
  var url = this.replaceOldConsumers(url, consumers, 'strip');
  return url;
};

LovelyPageManager.prototype.stripAllConsumers = function(url) {

  for (var i=0;i<this.CONSUMERPATTERNS.length;i++) {
      re = new RegExp(this.CONSUMERPATTERNS[i]);
      if (re.test(url)) url = url.replace(re, "");
  }

  //check if only slashes TODO: solve the problem
  if (url)
  {
    for (var i=0;i<url.length;i++) {
    if (url.charAt(i) != ('/')) return url;
    }
  }
  return "";
}

/* periodic refresh */
LovelyPageManager.prototype.startPeriodicRefresh = function() {
  clearInterval(this.pri);
  this.periodicRefresh();
  this.pri = setInterval("LPM.periodicRefresh()", 60000);
};

LovelyPageManager.prototype.stopPeriodicRefresh = function() {
  clearInterval(this.pri);
};

LovelyPageManager.prototype.periodicRefresh = function() {
  this.updateNewMessageAmount();
  //this.refreshCssClass({cssClass:'ajax_periodicrefresh'});
};


LovelyPageManager.prototype.resolveByUid = function(uid, cb) {
  var self=this;
  var callback = cb;

  //consider privacy
  if (this.getGlobals().loggedInUserId == uid) pc="?cache=false";
  else pc = "";

  $.getJSON(this.getGlobals().portalUrl+"/focus/"+uid+"/@@resolve"+pc, {}, function(data){
    callback.call(this, data);
  });
};

LovelyPageManager.prototype.locationByLatLon = function(lat,lon, cb){
    var self = this;
    var callback = cb;
    var url = this.getGlobals().portalUrl+"/revlocation?lat="+lat+"&lon="+lon;
    LCM.ajaxGet(url, {max_age:1000}, {}, function(response){
      eval("var data=" + response);
      callback.call(this, data);
   });
};

LovelyPageManager.prototype.uidByUrl=function(url, cb) {
  var self = this;
  var callback = cb;
  $.get(this.getGlobals().portalUrl+"/"+url+"/@@uid", {}, function(data){
    callback.call(this, parseInt(data));
  });
};

LovelyPageManager.prototype.updateNewMessageAmount = function() {
};

LovelyPageManager.prototype.trimLength = function(target) {
  //Trim Text/Username to the ajax:trimLength
    var target = target;
    var self = this;

    $('.ajax_trim').each(function(){
       var toTrim = $(this).html();
       var orgLength = toTrim.length;

       if($(this).parent('span').length){
            var trimIndex = $(this).parent('span').attr('ajax:trimlength')
            if(orgLength > trimIndex){
                var trimmed = toTrim.substr(0,trimIndex-3);
                trimmed = trimmed+'...';
            };
            $(this).html(trimmed);
       };
    });
};

LovelyPageManager.prototype.deNormalize = function(target){

    if ($(".ajax_denormalize",target).length) {
        var self = this;
        var infos = this.map.getCenterAndZoom();
        log('Denormalization:', target);
        this.locationByLatLon(infos.lat,infos.lon,function(r){
            $(".ajax_denormalize").each(function(){
                var level = $(this).attr("ajax:denormalize");
                if (level =="city"){
                    $(this).html(r.city);
                } else if (level =="district"){
                    $(this).html(r.district);
                } else if(level =="street"){
                    $(this).html(r.street);
                } else {
                  //use the current zoomlevel if the denormalization level
                  //is not explicitly defined
                  $(this).html(r[self.map.getZoom()])
                };
            });
        });
    };
};

LovelyPageManager.prototype.initMouseOverHelp = function(target) {
    var self = this;
    LPM.getHelp(function(helptext){

            $('.ajax_help',target).each(function(){
                var id = $(this).attr('ajax:help');
                var text = helptext[id];
                var identify = $("div#"+id);
                TTM.createTip($(this),id,text);

              $(this).bind('mouseover',function(pos){
                 $('.tooltip').hide();
                 TTM.showTip(identify, pos);
                });
             $(this).bind('mouseout',function(){
                 TTM.hideTip(identify);
                 TTM.purgeTimeout();
                });
             });
     });
};

LovelyPageManager.prototype.getHelp = function(cb){
    var self = this;
    var callback = cb;
    var url = this.getGlobals().portalUrl+"/mouseoverhelp";
    LCM.ajaxGet(url,{max_age:1000}, {}, function(response){
            eval("var data=" +response);
            callback.call(this,data);
    });
};

LovelyPageManager.prototype.registerAjaxPage = function(page) {
    var id = this.generatePageId(page.url);
    this.pages[id] = page;
    this.pages[id].id = id;
    return id;
};

LovelyPageManager.prototype.registerModePage = function(mode, page) {
    this.modePages[mode]=page;
};

LovelyPageManager.prototype.showModePage = function(mode) {
    this.showMagazinePage(this.modePages[mode].id);
};

LovelyPageManager.prototype.generatePageId = function(url) {
    url = url.replace(this.getGlobals().portalUrl+"/", "");
    url = url.split("/").join(".");
    url = url.split("@@").join("");
    return url;
};

LovelyPageManager.prototype.registerBatch = function(batch) {
    this.batches.push(batch);
    var id = this.batches.length-1;
    
    batch.context.addClass('ajax_registeredBatch'+id);
    
    return id;
}
LovelyPageManager.prototype.getBatch = function(id) {
    return this.batches[id]
}
LovelyPageManager.prototype.getBatchContext = function(id) {
    return $('.ajax_registeredBatch'+id);
}

// LovelyAjaxPage Class -------------------------------------------------------------------

LovelyAjaxPage = function () {
  this.manager=LPM;
  this.url;
  this.id;
  this.itemId;
  this.target;
};

LovelyAjaxPage.prototype.toString = function() {
  return "[LovelyAjaxPage "+this.url+"]";
};

LovelyAjaxPage.prototype.getUrl = function() {
  return this.url;
};

LovelyAjaxPage.prototype.getViewUrl = function() {
  var parts = this.url.split("/");
  return parts[parts.length-1];
};

LovelyAjaxPage.prototype.getBaseUrl = function() {
  var parts = this.url.split("/");
  return parts.slice(0, parts.length-1).join("/");
};

LovelyAjaxPage.prototype.getConsumedUrl = function (consumers) {
  var url =  this.getBaseUrl() + "/" + consumers + "/" + this.getViewUrl();
  return url;
};

LovelyAjaxPage.prototype.getItemId = function() {
  return this.itemId;
};

LovelyAjaxPage.prototype.getTarget = function() {
    return this.target;
}

//LovelyLoginManager -----------------------------------------------------------

LovelyLoginManager = function() {
  this.parent_id;
  this.container_id;
};

LovelyLoginManager.prototype.init = function(manager) {
  this.manager = manager;
};


LovelyLoginManager.prototype.showForm = function(url, startup) {
  this.form = new LovelyLoginForm(this.manager, this);
  this.form.controller = "LovelyLoginForm";
  this.form.url = url ? url : this.manager.getGlobals().portalUrl+"/login.ajax";
  this.form.load();
  //save the startup-params and use them after login
  this.startup=startup;
};

LovelyLoginManager.prototype.hideForm = function() {
  this.form.hide();
};

LovelyLoginManager.prototype.handleStatus = function(status) {

  if (status == "login") {
    this.onLoggedIn();
    return false;
  } if (status == "logout") {
    this.onLoggedOut();
    return false;
  } if (status == "invalid") {
    return true;
  } else {
    error('Unknown state for LoginForm: ', status);
    return true;
  }
};

LovelyLoginManager.prototype.onLoggedIn = function() {

  var self = this;
  this.manager.refreshCssClass({cssClass:'ajax_loginsensitive',
                                  finishCallback:function(){
                                    self.repeatStartup();
                                  },
                                  cameFrom : "onLoggedIn"
                                 });

  this.hideForm();
  this.manager.startPeriodicRefresh();
  //LPM.trigger.logging();
  LPM.tracking.ivw.logging();
};

LovelyLoginManager.prototype.repeatStartup = function() {
  if (this.startup) {
    this.manager.handleStartupParams(this.startup);
    this.startup=null;
  }
};

LovelyLoginManager.prototype.onLoggedOut = function () {

  this.manager.refreshCssClass({cssClass:'ajax_loginsensitive'});
  this.manager.stopPeriodicRefresh();
  this.hideForm();
  LPM.tracking.ivw.logging();
};


//LovelySlideShow -----------------------------------------------------------------

LovelySlideShow = function(){};
LovelySlideShow.prototype.initSlideShow = function(node){
  context = $(node);
  slideShowSize = $('div.thumbholder', context).children().length;
  buttonLeft = $('a#goBack', context);
  buttonRight = $('a#goForward', context);
  slideStrip = $('div.thumbholder',context);
  thumbWidth = 86;      // --->> image-width
  imgPerPage = 2;       // --->> images shown per page
  this.currentPage = 0;
  
  var self=this;
  
  buttonLeft.bind('click', function(event) {
    self.goOneStep(event);
  });
  buttonRight.bind('click', function(event) {
    self.goOneStep(event);
  });
    
  if(slideShowSize <= imgPerPage){
    buttonLeft.addClass('disabled');
    buttonRight.addClass('disabled');
  };
  
  $('a', slideStrip).bind('click', function(event){
    self.showBig(event);
  });
  
  this.showNumbers();
};

LovelySlideShow.prototype.goOneStep = function(event){
  var self=this;
  var currentStat = parseFloat(slideStrip.css('left'), 10);
  this.pageAmount = Math.ceil(slideShowSize/imgPerPage)
    
  if(event.target.className != 'disabled'){
    if(event.target.id == "goForward"){
      currentStat -= thumbWidth*imgPerPage;
    }
    else {
      currentStat += thumbWidth*imgPerPage;
    }
  }
  
  this.currentPage = Math.abs(currentStat/(thumbWidth*imgPerPage));
  
  buttonLeft.removeClass('disabled');
  buttonRight.removeClass('disabled');
  
  if(this.currentPage == 0){
    buttonLeft.addClass('disabled');
  }

  if(this.currentPage == this.pageAmount-1){
    buttonRight.addClass('disabled');
  }
  
  slideStrip.animate({left:currentStat},'slow');
  
  this.showNumbers();
};

LovelySlideShow.prototype.showNumbers = function(){  
  var rightNum = slideShowSize-((this.currentPage +1)*imgPerPage);
  var leftNum = slideShowSize - imgPerPage - rightNum;
  
  if(rightNum < 0){
    rightNum = 0;
  }
  
  if(leftNum < 0){
    leftNum = 0;
  }
  
  buttonLeft.html('('+ leftNum +')');
  buttonRight.html('('+ rightNum +')');
  
};

LovelySlideShow.prototype.showBig = function(event){
  var self=this;
  this.url = $(event.target).attr('src');
  this.urlAr = $(event.target).attr('src').split('/');
  this.lastDir = this.urlAr[this.urlAr.length-1];
  this.lastPos = this.url.indexOf(this.lastDir);
  this.newUrl = this.url.substring(0,this.lastPos) + 'large';
  this.picBig = $('div.picBig > img');
  
  if(this.picBig.attr('src') != this.newUrl) {
    this.picBig.attr('src', this.newUrl);
  }; 
};

//LovelyNavigationControl -----------------------------------------------------------
NavigationControl = function(){};
NavigationControl.prototype.init = function(context) {
    var self=this;
    this.context = context;
    this.districtoverlay = $('div#district_overlay', context);
    
    this.DISTRICT_LABEL = $('div#nav-middle', context);
    this.STREET_FIELD = $('input[name=street]', context);
    
    this.CITY_ZOOM = 12;
    this.DISTRICT_ZOOM = 15;
    this.STREET_ZOOM = 19;
    
    this.defaultDistrictLabel = this.DISTRICT_LABEL.html()
    
    $('li', this.districtoverlay).each(function() {
        var li = $(this);
        var a = li.children('a');
        li.attr("ajax:url", a.attr("href"));
        li.unbind('click').bind("click", function() {
            var district = li.children('a').html();
            self.onDistrictChosen({
                name : district,
                lat : li.attr("ajax:lat"),
                lon : li.attr("ajax:lon")
            });
			// LPM.history.addDistrict(district);
        });
        a.attr("href", "javascript:LPM.nothing();");
    });
    
    this.districtButton = $('div#nav-middle', this.context);
    this.districtButton.bind("click", function() {
        self.toggleDistrictOverlay();
    }).css("cursor", "pointer");
    
    $('a.ajax_wholecity').bind("click", function(){
        self.onCityChosen({
            name : $(this).attr('ajax:name'),
            lat : $(this).attr('ajax:lat'),
            lon : $(this).attr('ajax:lon')
        })
    }).attr("href", "javascript:LPM.nothing();");

    this.initSlider();
};

NavigationControl.prototype.toggleDistrictOverlay = function() {
	var dov = this.districtoverlay;
    dov.toggle();
    var self=this;
    if (dov.css('display')!='none') {
		var offset = this.getBoundaries(dov);
      	dov.bind("mouseout", function(event) {
	  		event.stopPropagation();
       		if(event.pageX<offset.left || event.pageX>offset.right || event.pageY<offset.top || event.pageY>offset.bottom)
				dov.hide();
      	});
    }
};

NavigationControl.prototype.getBoundaries = function(elem) {
	var offset = {
			top: 	elem.offset({ scroll: false }).top,
			left: 	elem.offset({ scroll: false }).left,
			right: 	false,
			bottom: false
		};
		offset.right = parseInt(offset.left) + parseInt(elem.width());
		offset.bottom = parseInt(offset.top) + parseInt(elem.height());
	return offset;
};

NavigationControl.prototype.onCityChosen = function(res) {
    LPM.map.setCenterAndZoom(res.lat, res.lon, this.CITY_ZOOM);
    this.districtoverlay.hide();
    this.setSliderValue(this.CITY_ZOOM);

    this.DISTRICT_LABEL.html(this.defaultDistrictLabel);
    this.STREET_FIELD.val(this.STREET_FIELD.attr("title"));
    
    LPM.onPositionChanged("city");
};

NavigationControl.prototype.onDistrictChosen = function(res) {
    LPM.map.setCenterAndZoom(res.lat, res.lon, this.DISTRICT_ZOOM);
    this.districtoverlay.hide();    
    this.setSliderValue(this.DISTRICT_ZOOM);

    this.DISTRICT_LABEL.html(res.name);
    this.STREET_FIELD.val(this.STREET_FIELD.attr("title"));
    LPM.onPositionChanged('district', res);

}

NavigationControl.prototype.onSearchResultChosen = function(res) {
    LPM.map.setCenterAndZoom(res.lat, res.lon, this.STREET_ZOOM);
    this.setSliderValue(this.STREET_ZOOM);

    var self=this;
    LPM.locationByLatLon(res.lat, res.lon, function(res) {
        res.zoom = zoom;
        self.onStreetChosen(res);
    })
    
    LPM.onPositionChanged('street');
}

NavigationControl.prototype.onStreetChosen = function(res) {
    log("street chosen", res);
    this.DISTRICT_LABEL.html(res.district);
    this.STREET_FIELD.val(res.street);
}

NavigationControl.prototype.onZoomChanged = function(res) {
    LPM.map.setZoom(res.value);
}

NavigationControl.prototype.initSlider = function(){
    var self = this;
	if($.browser.safari)
		$('div#slider-button').css({ height: '174px' });
	$('div#slider-button').slider({ 
        stop: function(e,ui){
            self.onZoomChanged(ui);
            },
        slide: function(e, ui){
            self.sliderUpdate(e,ui);
            },
		axis:'vertical', 
        min: this.CITY_ZOOM,
        max: this.STREET_ZOOM,
        steps: this.STREET_ZOOM - this.CITY_ZOOM
        });
		

    //remove unbind the click event
    var area = $('#slider-button');
    area.unbind();
    
    if (this.currentSliderValue) 
		this.setSliderValue(this.currentSliderValue);
};

NavigationControl.prototype.sliderUpdate = function(e,ui){
    var handler = $('.ui-slider-handle'); 
    var top = handler.css('top');
    top = -156 + parseInt(top)+'px';
    $('#slider-button').css({backgroundPosition:'0 '+top});
    this.currentSliderValue = ui;
    // this.onZoomChanged(ui);    removed it, to save cpu-power (greenIT) 
};

NavigationControl.prototype.setSliderValue = function(value) {
    $('#slider-button').slider('moveTo', value)
}

GossipRefresher = function(){};
GossipRefresher.prototype.init = function(context){
    var self = this;
    this.pri = null;
    this.refreshclass = context.parent().attr("class");
    this.refreshtime = parseInt(context.attr("ajax:refreshinterval")); 
    if (this.pri == null){
        this.pri = setInterval("GR.updateGossip()", this.refreshtime);
    }
};
GossipRefresher.prototype.updateGossip = function(){
    clearInterval(this.pri);
    LPM.refreshCssClass({cssClass: this.refreshclass});
};

LPM=new LovelyPageManager();

/*
* ExtInfoWindow Class, v1.02 
*  Copyright (c) 2007, Joe Monahan (http://www.seejoecode.com)
* 
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* 
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This class lets you add an info window to the map which mimics GInfoWindow
* and allows for users to skin it via CSS.  Additionally it has options to
* pull in HTML content from an ajax request, triggered when a user clicks on
* the associated marker.
*/


/**
 * Creates a new ExtInfoWindow that will initialize by reading styles from css
 *
 * @constructor
 * @param {GMarker} marker The marker associated with the info window
 * @param {String} windowId The DOM Id we will use to reference the info window
 * @param {String} html The HTML contents
 * @param {Object} opt_opts A contianer for optional arguments:
 *    {String} ajaxUrl The Url to hit on the server to request some contents 
 *    {Number} paddingX The padding size in pixels that the info window will leave on 
 *                    the left and right sides of the map when panning is involved.
 *    {Number} paddingY The padding size in pixels that the info window will leave on 
 *                    the top and bottom sides of the map when panning is involved.
 *    {Number} beakOffset The repositioning offset for when aligning the beak element. 
 *                    This is used to make sure the beak lines up correcting if the 
 *                    info window styling containers a border.
 */
function ExtInfoWindow(marker, windowId, html, opt_opts) {
  this.html_ = html;
  this.marker_ = marker;
  this.infoWindowId_ = windowId;

  this.options_ = opt_opts == null ? {} : opt_opts;
  this.ajaxUrl_ = this.options_.ajaxUrl == null ? null : this.options_.ajaxUrl;
  this.callback_ = this.options_.ajaxCallback == null ? null : this.options_.ajaxCallback;

  this.borderSize_ = this.options_.offsetY == null ? 0 : this.options_.offsetY;
  this.paddingX_ = this.options_.paddingX == null ? 0 : this.options_.paddingX;
  this.paddingY_ = this.options_.paddingY == null ? 0 : this.options_.paddingY;
  this.paddingXR_ = this.options_.paddingXR == null ? 0 : this.options_.paddingXR;
  this.paddingXL_ = this.options_.paddingXL == null ? 0 : this.options_.paddingXL;
  this.offsetX_ = this.options_.offsetX == null ? 0 : this.options_.offsetX;
  this.shadow_ = this.options_.shadow == 0 ? false : true;

  this.map_ = null;

  this.container_ = document.createElement('div');
  this.container_.style.position = 'relative';
  this.container_.style.display = 'none';

  this.contentDiv_ = document.createElement('div');
  this.contentDiv_.id = this.infoWindowId_ + '_contents';
  this.contentDiv_.innerHTML = this.html_;
  this.contentDiv_.style.display = 'block';
  this.contentDiv_.style.visibility = 'hidden';

  this.wrapperDiv_ = document.createElement('div');
  
  // Shadow
  	this.shadowdiv_=document.createElement("div");
	this.shadowdiv_.id="shadowdiv";
	this.shadowdiv_.className="large_bubble_shadow";
	this.shadowdiv_.style.position = "absolute";
  
  
};

//use the GOverlay class
ExtInfoWindow.prototype = new GOverlay();

/**
 * Called by GMap2's addOverlay method.  Creates the wrapping div for our info window and adds
 * it to the relevant map pane.  Also binds mousedown event to a private function so that they
 * are not passed to the underlying map.  Finally, performs ajax request if set up to use ajax
 * in the constructor.
 * @param {GMap2} map The map that has had this extInfoWindow is added to it.
 */
ExtInfoWindow.prototype.initialize = function(map) {
  this.map_ = map;

  this.defaultStyles = {
    containerWidth: this.map_.getSize().width / 2,
    borderSize: 1
  };

  this.wrapperParts = {
    tl:{t:0, l:0, w:0, h:0, domElement: null},
    t:{t:0, l:0, w:0, h:0, domElement: null},
    tr:{t:0, l:0, w:0, h:0, domElement: null},
    l:{t:0, l:0, w:0, h:0, domElement: null},
    r:{t:0, l:0, w:0, h:0, domElement: null},
    bl:{t:0, l:0, w:0, h:0, domElement: null},
    b:{t:0, l:0, w:0, h:0, domElement: null},
    br:{t:0, l:0, w:0, h:0, domElement: null},
    beak:{t:0, l:0, w:0, h:0, domElement: null},
    close:{t:0, l:0, w:0, h:0, domElement: null}
  };

  for (var i in this.wrapperParts ) {
    var tempElement = document.createElement('div');
    tempElement.id = this.infoWindowId_ + '_' + i;
    tempElement.style.visibility = 'hidden';
    document.body.appendChild(tempElement);
    tempElement = document.getElementById(this.infoWindowId_ + '_' + i);
    var tempWrapperPart = eval('this.wrapperParts.' + i);    
    tempWrapperPart.w = parseInt(this.getStyle_(tempElement, 'width'));
    tempWrapperPart.h = parseInt(this.getStyle_(tempElement, 'height'));
    if(document.getElementById(tempElement.id))document.body.removeChild(tempElement);
  }
  for (var i in this.wrapperParts) {
    if (i == 'close' ) {
      //first append the content so the close button is layered above it
      this.wrapperDiv_.appendChild(this.contentDiv_);
    }
    var wrapperPartsDiv = null;
    if (this.wrapperParts[i].domElement == null) {
      wrapperPartsDiv = document.createElement('div');
      this.wrapperDiv_.appendChild(wrapperPartsDiv);
    } else {
      wrapperPartsDiv = this.wrapperParts[i].domElement;
    }
    wrapperPartsDiv.id = this.infoWindowId_ + '_' + i;
    wrapperPartsDiv.style.position = 'absolute';
    wrapperPartsDiv.style.width = this.wrapperParts[i].w + 'px';
    wrapperPartsDiv.style.height = this.wrapperParts[i].h + 'px';
    wrapperPartsDiv.style.top = this.wrapperParts[i].t + 'px';
    wrapperPartsDiv.style.left = this.wrapperParts[i].l + 'px';
    this.wrapperParts[i].domElement = wrapperPartsDiv;
  }
  
  this.map_.getPane(G_MAP_FLOAT_PANE).appendChild(this.container_);
  this.container_.id = this.infoWindowId_;
  var containerWidth  = this.getStyle_(document.getElementById(this.infoWindowId_), 'width');
  this.container_.style.width = (containerWidth == null ? this.defaultStyles.containerWidth : containerWidth);

  this.map_.getContainer().appendChild(this.contentDiv_);
  this.contentWidth = this.getDimensions_(this.container_).width;
  this.contentDiv_.style.width = this.contentWidth + 'px';
  this.contentDiv_.style.position = 'absolute';

  this.container_.appendChild(this.wrapperDiv_);
  
  // The shadow :-)
  
  if(this.shadow_){
  	
  	this.map_.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(this.shadowdiv_);
		
		}  

  GEvent.bindDom(this.container_, 'mousedown', this,this.onClick_);

  GEvent.trigger(this.map_, 'extinfowindowopen');
  if (this.ajaxUrl_ != null && document.getElementById("mbBigBubble")) {
    this.ajaxRequest_(this.ajaxUrl_);
  }
};

/**
 * Private function to steal mouse click events to prevent it from returning to the map.
 * Without this links in the ExtInfoWindow would not work, and you could click to zoom or drag 
 * the map behind it.
 * @private
 * @param {MouseEvent} e The mouse event caught by this function
 */
ExtInfoWindow.prototype.onClick_ = function(e) {
  if(navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  } else {
    e.preventDefault();
    e.stopPropagation();
  }
};

/**
 * Remove the extInfoWindow container from the map pane. 
 */
ExtInfoWindow.prototype.remove = function() {
  if (this.map_.getExtInfoWindow() != null) {
    GEvent.trigger(this.map_, 'extinfowindowbeforeclose');
    
    GEvent.clearInstanceListeners(this.container_);
    if (this.container_.outerHTML) {
      this.container_.outerHTML = ''; //prevent pseudo-leak in IE
    }
    if (this.container_.parentNode) {
      this.container_.parentNode.removeChild(this.container_);
    }
    this.container_ = null;
    
     if (this.shadowdiv_.parentNode) {
      this.shadowdiv_.parentNode.removeChild(this.shadowdiv_);
    }
    
    this.shadowdiv_= null;
    
    GEvent.trigger(this.map_, 'extinfowindowclose');
    this.map_.setExtInfoWindow_(null);
    
     }
};

/**
 * Return a copy of this overlay, for the parent Map to duplicate itself in full. This
 * is part of the Overlay interface and is used, for example, to copy everything in the 
 * main view into the mini-map.
 * @return {GOverlay}
 */
ExtInfoWindow.prototype.copy = function() {
  return new ExtInfoWindow(this.marker_, this.infoWindowId_, this.html_, this.options_);
};

/**
 * Draw extInfoWindow and wrapping decorators onto the map.  Resize and reposition
 * the map as necessary. 
 * @param {Boolean} force Will be true when pixel coordinates need to be recomputed.
 */
ExtInfoWindow.prototype.redraw = function(force) {
  if (!force || this.container_ == null) return;



  //set the content section's height, needed so  browser font resizing does not affect the window's dimensions
  var contentHeight = this.contentDiv_.offsetHeight;
  this.contentDiv_.style.height = contentHeight + 'px';

  //reposition contents depending on wrapper parts.
  //this is necessary for content that is pulled in via ajax
  this.contentDiv_.style.left = this.wrapperParts.l.w + 'px';
  this.contentDiv_.style.top = this.wrapperParts.tl.h + 'px';
  this.contentDiv_.style.visibility = 'visible';
  
 


  //create the decoration wrapper DOM objects
  //append the styled info window to the container
  for (var i in this.wrapperParts) {
    if (i == 'close' ) {
      //first append the content so the close button is layered above it
      this.wrapperDiv_.insertBefore(this.contentDiv_, this.wrapperParts[i].domElement);
    }
  }

  //add event handler for the close box
  var currentMarker = this.marker_;
  var thisMap = this.map_;
  GEvent.addDomListener(this.wrapperParts.close.domElement, 'click', 
    function() {
      thisMap.closeExtInfoWindow();
    }
  );

  //position the container on the map, over the marker
  var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());
  this.container_.style.position = 'absolute';
  var markerIcon = this.marker_.getIcon();
  
   var cLeft = (pixelLocation.x 
    - (this.contentWidth / 2) + this.offsetX_
    // - markerIcon.iconAnchor.x 
    // + markerIcon.infoWindowAnchor.x
  ); 
  
  this.container_.style.left = cLeft + 'px';

  	
	
   var cTop = (pixelLocation.y
    - this.wrapperParts.bl.h
    - contentHeight
    - this.wrapperParts.tl.h
    - this.wrapperParts.beak.h
    - markerIcon.iconAnchor.y
    + markerIcon.infoWindowAnchor.y
    + this.borderSize_
  );
  
  this.container_.style.top = cTop+ 'px';

  this.container_.style.display = 'block';

 if(this.shadow_){
 	if ($.browser.msie)var shadowplus=0; else var shadowplus=0;
  	//this.shadowdiv_.style.visibility = 'visible';
	this.shadowdiv_.style.display = 'block';
	this.shadowdiv_.style.top=cTop + 70 + 'px';
	this.shadowdiv_.style.left=cLeft - 44 + shadowplus + 'px';
	
	log("container-style-top:"+cTop+"; container-style-left:"+cLeft);
	
	}



  if(this.map_.getExtInfoWindow() != null) {
    this.repositionMap_();
  }
  
 
  
};

/**
 * Determine the dimensions of the contents to recalculate and reposition the 
 * wrapping decorator elements accordingly.
 */
ExtInfoWindow.prototype.resize = function(){
  
  //Create temporary DOM node for new contents to get new height
  //This is done because if you manipulate this.contentDiv_ directly it causes visual errors in IE6
  var tempElement = this.contentDiv_.cloneNode(true);
  tempElement.id = this.infoWindowId_ + '_tempContents';
  tempElement.style.visibility = 'hidden';	
  tempElement.style.height = 'auto';
  document.body.appendChild(tempElement);
  tempElement = document.getElementById(this.infoWindowId_ + '_tempContents');
  var contentHeight = tempElement.offsetHeight;
  document.body.removeChild(tempElement);

  //Set the new height to eliminate visual defects that can be caused by font resizing in browser
  this.contentDiv_.style.height = contentHeight + 'px';

  var contentWidth = this.contentDiv_.offsetWidth;
  var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());

  var oldWindowHeight = this.wrapperParts.t.domElement.offsetHeight + this.wrapperParts.l.domElement.offsetHeight + this.wrapperParts.b.domElement.offsetHeight;	
  var oldWindowPosTop = this.wrapperParts.t.domElement.offsetTop;

  //resize info window to look correct for new height
  this.wrapperParts.l.domElement.style.height = contentHeight + 'px';
  this.wrapperParts.r.domElement.style.height = contentHeight + 'px';
  var newPosTop = this.wrapperParts.b.domElement.offsetTop - contentHeight;
  this.wrapperParts.l.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.r.domElement.style.top = newPosTop + 'px';
  this.contentDiv_.style.top = newPosTop + 'px';
  windowTHeight = parseInt(this.wrapperParts.t.domElement.style.height);
  newPosTop -= windowTHeight;
  this.wrapperParts.close.domElement.style.top = newPosTop + this.borderSize_ + 'px';
  this.wrapperParts.tl.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.t.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.tr.domElement.style.top = newPosTop + 'px';

  this.repositionMap_();
};

/**
 * Check to see if the displayed extInfoWindow is positioned off the viewable 
 * map region and by how much.  Use that information to pan the map so that 
 * the extInfoWindow is completely displayed.
 * @private
 */
ExtInfoWindow.prototype.repositionMap_ = function(){
  //pan if necessary so it shows on the screen
  var mapNE = this.map_.fromLatLngToDivPixel(
    this.map_.getBounds().getNorthEast()
  );
  var mapSW = this.map_.fromLatLngToDivPixel(
    this.map_.getBounds().getSouthWest()
  );
  var markerPosition = this.map_.fromLatLngToDivPixel(
    this.marker_.getPoint()
  );

  var panX = 0;
  var panY = 0;
  var paddingX = this.paddingX_;
  var paddingY = this.paddingY_;


  var offsetTop = Math.round(markerPosition.y - this.paddingY_);
  if (offsetTop < mapNE.y) {
    panY = mapNE.y - offsetTop;
  } else {
    //test bottom of screen
    

    var offsetBottom = markerPosition.y + this.paddingY_;
    /*
    Nope...Fine without, ´cause our bottom ist always perfect :-)
    if (offsetBottom >= mapSW.y) {
      panY = -(offsetBottom - mapSW.y);
    }
    */
  }

  //test right of screen
  var offsetRight = Math.round(markerPosition.x + this.paddingX_ + this.paddingXR_ );
  if (offsetRight > mapNE.x) {
    panX = -( offsetRight - mapNE.x);
  } else {
    //test left of screen
    var offsetLeft = Math.round(markerPosition.x - (this.paddingX_+ this.paddingXL_));
    if( offsetLeft < mapSW.x) {
      panX = mapSW.x - offsetLeft;
    }
  }

log("Bound mapSW: "+mapSW.x+"x"+mapSW.y+" mapNE: "+mapNE.x+"x"+mapNE.y+" Offsets: "+offsetTop+" "+offsetRight+" "+offsetBottom+" "+offsetLeft+" PX: "+paddingX+" PY: "+paddingY);

  if (panX != 0 || panY != 0 && this.map_.getExtInfoWindow() != null ) {

    this.map_.panBy(new GSize(panX,panY));
  }
};

/**
 * Private function that handles performing an ajax request to the server.  The response
 * information is assumed to be HTML and is placed inside this extInfoWindow's contents region.
 * Last, check to see if the height has changed, and resize the extInfoWindow accordingly.
 * @private
 * @param {String} url The Url of where to make the ajax request on the server
 */
ExtInfoWindow.prototype.ajaxRequest_ = function(url){
  var thisMap = this.map_;
  var thisCallback = this.callback_;
  GDownloadUrl(url, function(response, status){
    if (thisMap.getExtInfoWindow() != null) 
    { 
    	var infoWindow = document.getElementById(thisMap.getExtInfoWindow().infoWindowId_ + '_contents');
    if (response == null || status == -1 ) {
      infoWindow.innerHTML = '<span class="error">ERROR: The Ajax request failed to get HTML content from "' + url + '"</span>';
    } else {
      infoWindow.innerHTML = response;
    }
    if (thisCallback != null ) {
      thisCallback();
    }
    thisMap.getExtInfoWindow().resize();
	}
    GEvent.trigger(thisMap, 'extinfowindowupdate');
  });
};

/**
 * Private function derived from Prototype.js to get a given element's
 * height and width
 * @private
 * @param {Object} element The DOM element that will have height and 
 *                    width will be calculated for it.
 * @return {Object} Object with keys: width, height
 */
ExtInfoWindow.prototype.getDimensions_ = function(element) {
  var display = this.getStyle_(element, 'display');
  if (display != 'none' && display != null) { // Safari bug
    return {width: element.offsetWidth, height: element.offsetHeight};
  }

  // All *Width and *Height properties give 0 on elements with display none,
  // so enable the element temporarily
  var els = element.style;
  var originalVisibility = els.visibility;
  var originalPosition = els.position;
  var originalDisplay = els.display;
  els.visibility = 'hidden';
  els.position = 'absolute';
  els.display = 'block';
  var originalWidth = element.clientWidth;
  var originalHeight = element.clientHeight;
  els.display = originalDisplay;
  els.position = originalPosition;
  els.visibility = originalVisibility;
  return {width: originalWidth, height: originalHeight};
};

/**
 * Private function derived from Prototype.js to get a given element's
 * value that is associated with the passed style
 * @private
 * @param {Object} element The DOM element that will be checked.
 * @param {String} style The style name that will be have it's value returned.
 * @return {Object}
 */
ExtInfoWindow.prototype.getStyle_ = function(element, style) {
  var found = false;
  style = this.camelize_(style);
  var value = element.style[style];
  if (!value) {
    if (document.defaultView && document.defaultView.getComputedStyle) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    } else if (element.currentStyle) {
      value = element.currentStyle[style];
    }
  }
  if((value == 'auto') && (style == 'width' || style == 'height') && (this.getStyle_(element, 'display') != 'none')) {
    if( style == 'width' ) {
      value = element.offsetWidth;
    }else {
      value = element.offsetHeight;
    }
  }
  if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) {
    if (this.getStyle_(element, 'position') == 'static') value = 'auto';
  } 
  return (value == 'auto') ? null : value;
};

/**
 * Private function pulled from Prototype.js that will change a hyphened
 * style name into camel case.
 * @private
 * @param {String} element The string that will be parsed and made into camel case
 * @return {String}
 */
ExtInfoWindow.prototype.camelize_ = function(element) {
  var parts = element.split('-'), len = parts.length;
  if (len == 1) return parts[0];
  var camelized = element.charAt(0) == '-'
    ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
    : parts[0];

  for (var i = 1; i < len; i++) {
    camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
  }
  return camelized;
};

GMap.prototype.ExtInfoWindowInstance_ = null;
GMap.prototype.ClickListener_ = null;
GMap.prototype.InfoWindowListener_ = null;

/**
 * Creates a new instance of ExtInfoWindow for the GMarker.  Register the newly created 
 * instance with the map, ensuring only one window is open at a time. If this is the first
 * ExtInfoWindow ever opened, add event listeners to the map to close the ExtInfoWindow on 
 * zoom and click, to mimic the default GInfoWindow behavior.
 *
 * @param {GMap} map The GMap2 object where the ExtInfoWindow will open
 * @param {String} cssId The id we will use to reference the info window
 * @param {String} html The HTML contents
 * @param {Object} opt_opts A contianer for optional arguments:
 *    {String} ajaxUrl The Url to hit on the server to request some contents 
 *    {Number} paddingX The padding size in pixels that the info window will leave on 
 *                    the left and right sides of the map when panning is involved.
 *    {Number} paddingX The padding size in pixels that the info window will leave on 
 *                    the top and bottom sides of the map when panning is involved.
 *    {Number} beakOffset The repositioning offset for when aligning the beak element. 
 *                    This is used to make sure the beak lines up correcting if the 
 *                    info window styling containers a border.
 */
GMarker.prototype.openExtInfoWindow = function(map, cssId, html, opt_opts) {
  if (map == null) {
    throw 'Error in GMarker.openExtInfoWindow: map cannot be null';
    return false;
  }
  if (cssId == null || cssId == '') {
    throw 'Error in GMarker.openExtInfoWindow: must specify a cssId';
    return false;
  }
  
  map.closeInfoWindow();
  if (map.getExtInfoWindow() != null) {
    map.closeExtInfoWindow();
  }
  if (map.getExtInfoWindow() == null) {
    map.setExtInfoWindow_( new ExtInfoWindow(
      this,
      cssId,
      html,
      opt_opts
    ) );
    if (map.ClickListener_ == null) {
      //listen for map click, close ExtInfoWindow if open
      map.ClickListener_ = GEvent.addListener(map, 'click',
      function(event) {
          if( !event && map.getExtInfoWindow() != null ){
            map.closeExtInfoWindow();
          }
        }
      );
    }
    if (map.InfoWindowListener_ == null) {
      //listen for default info window open, close ExtInfoWindow if open
      map.InfoWindowListener_ = GEvent.addListener(map, 'infowindowopen', 
      function(event) {
          if (map.getExtInfoWindow() != null) {
            map.closeExtInfoWindow();
          }
        }
      );
    }
    map.addOverlay(map.getExtInfoWindow());
  }
};

/**
 * Remove the ExtInfoWindow instance
 * @param {GMap2} map The map where the GMarker and ExtInfoWindow exist
 */
GMarker.prototype.closeExtInfoWindow = function(map) {
  map.closeExtInfoWindow();
};

/**
 * Get the ExtInfoWindow instance from the map
 */
GMap2.prototype.getExtInfoWindow = function(){
  return this.ExtInfoWindowInstance_;
};
/**
 * Set the ExtInfoWindow instance for the map
 * @private
 */
GMap2.prototype.setExtInfoWindow_ = function( extInfoWindow ){
  this.ExtInfoWindowInstance_ = extInfoWindow;
}
/**
 * Remove the ExtInfoWindow from the map
 */
GMap2.prototype.closeExtInfoWindow = function(){
  this.ExtInfoWindowInstance_.remove();
};

AjaxCommands.styledUpload = function(node, params) {
    if($.browser.safari) return;
    
    var wrapper = $("<div style='position:relative'></div>")
    node.wrap(wrapper);
    var container=node.parent();
  
    container.append("<input class='visible_text' type='text' />");
    container.append("<img class='visible_browse' src='++resource++img/forms/btn-browse.png' alt='browse'/>");
  
    node.addClass("hidden");
  
    var visiblepathfield=container.children('.visible_text');
    node.bind("change", function() {
      visiblepathfield.val($(this).val());
    });
}

AjaxCommands.customDropDown = function(dd, params) {

    //get the data and fill the dropdown
    $('select', dd).children('option').each(function() {
      $("div.container", dd).append("<div ajax:value='"+$(this).val()+"' id='dd-"+$(this).parent().attr("name")+"."+$(this).val()+"'>"+$(this).text()+"</div>");
    
      if ($(this).attr("selected")) {
        $("div.middle", dd.children("div.selected")).append($(this).text());
        $("input[@type=hidden]", dd).val($(this).val());
      }
    });
  
    //create a hidden input field for storing values if the select has a name    
    if ($('select', dd).attr('name')) {
      var name = $('select', dd).attr('name');
      $("span.dd-result", dd).html("<input type='hidden' name='"+name+"' id='"+name+"' value='"+$('select', dd).val()+"'/>");
    }
      
    //remove the data source
    $('select', dd).remove();
  
    //set events for options
    $('div.container', dd).children().bind("mouseover",  function() {
        $(this).css("background-color", "#BBBBBB");
    });
    $('div.container', dd).children().bind("mouseout",  function() {
      $(this).css("background-color", "transparent");
    });
  
    $('div.container', dd).children().bind("click", function() {
      val = $(this).attr("ajax:value");
          
      //store the value
      $('input', $("span.dd-result", dd)).val(val);
      //update the selection
      $("div.middle", dd.children("div.selected")).empty().append($(this).text());
    
      //close the dropdown
      dd.attr("class", "custom-dd closed");
    });
  
    //set click actions for the dropdown
    dd.children("div.selected").bind("click", function() {
      var isOpen = dd.attr("class").indexOf("open") != -1
      if (isOpen) {
        dd.attr("class", "custom-dd closed");
      } else {
        dd.attr("class", "custom-dd open");
      
        //set the dropdown body height if in ie
        if ($.browser.msie) {
          var ddbody=$('div.body', $(this).parent());
          ddbody.css('height', ddbody.height());
        }
      
        dd.bind("mouseover", function() {
          $('body').unbind("click");
        });
        dd.bind("mouseout", function() {
          $('body').bind("click", function() {
            dd.attr("class", "custom-dd closed");
          });
        });
      }
    }); 
}
  
AjaxCommands.genderSelector = function(node, attr) {
  
    var context = node;
    var form=LHM.getCurrentHover();
  
    //attach a hidden inputfield carrying the value of the select and remove the select afterwards
    var name = $('select', context).attr("name");
    var val = $('select', context).val();
    //dont use the value ( preselection)
    context.append("<input type='hidden' id='"+name+"' name='"+name+"' value='"+val+"' />");
    $('select', context).remove();
  
    $('div.male', context).bind("click", function() {
      $(this).parent().addClass("active");
      $("div.female", context).parent().removeClass("active");
      $("div.female", context).parent().addClass("inactive");
      $("input[@name="+name+"]", context).val("male");
    
      //notify the form about the change
      form.onGenderChange("male");
    
    });
    $('div.female', context).bind("click", function() {
      $(this).parent().addClass("active");
      $('div.male', context).parent().removeClass("active");
      $('div.male', context).parent().addClass("inactive");
      $("input[@name="+name+"]", context).val("female");

      //notify the form about the change
      form.onGenderChange("female");
    });
  
    if (form) form.onGenderChange("male");
}
MbPageManager = function() {}
MbPageManager.prototype = new LovelyPageManager();
MbPageManager.prototype.toString = function() {return '[MbPageManager object]'};

LPM = new MbPageManager();
$(function(){
  LPM.init();
})

TrackingManager = function(){};
TrackingManager.prototype.init = function(manager) {
  this.manager = manager;
  this.pause = false; // true, if logging is paused
  this.interval = 800; // time to wait between calls
  this.ivw = new IVWManager();
  this.ivw.init();
  this.track("home");
  log("initialized statistic");
};
TrackingManager.prototype.pageView = function(state) {};
TrackingManager.prototype.initialView = function() {};
TrackingManager.prototype.action = function(action) {};
TrackingManager.prototype.track = function(state) { // Function to trigger from outside
		this.webtrekk(state);	
		this.ivw.newPage(state);

};
TrackingManager.prototype.search = function(searchterm) { // Function to trigger from outside searches
	if((!this.pause) && (!this.isHover()))
	{
		this.pageView(searchterm);
		this.webtrekk("search", searchterm);	
		this.preventDoubleCalls(true);
	}
};
TrackingManager.prototype.coldStart = function() {
	this.initialView();
	if(typeof(wt_sendinfo))wt_sendinfo();
};
TrackingManager.prototype.webtrekk = function(state, searchterm) {	
	wt_cd=this.ivw.hash; // customer id 
 	wt_is=searchterm || ""; // internal search
	wt_mc=""; // mediacode
	wt_lp=""; // link position
	
	warn("webtrekk called: " + state);
	
	wt_cg=LPM.mode + ";" + LPM.getGlobals().loginStatus + this.getTab(";"); // content group(s)
	var fire = this.setWebtrekkCode(state);
	
	if(typeof(wt_sendinfo) != "undefined" && fire)
	{
		wt_sendinfo();
		log("sending webtrekk: " + wt_be + " - " + wt_cg + state+wt_cd + " searched: " + wt_is);	
	}	
};
TrackingManager.prototype.getTab = function(separator) {
	var tab = "";
	if (LPM.currentPage)tab=separator+LPM.currentPage.tab;
	return tab;
};
TrackingManager.prototype.getTitle = function(){	
	var title = false;
	if(LPM.title)title = LPM.title;
	return title;
};
TrackingManager.prototype.isHover = function() {
	return LHM.getCurrentHover();
};
TrackingManager.prototype.setWebtrekkCode = function(state) {
	var fire = true, title = false;
	
	if(state)
	{
		switch (true)
		{			
			case (state == "home"):
				wt_be="home";
				break;
			case (state=="pageReady"):
				title = this.getTitle() || LPM.currentPage.id;
				wt_be=LPM.mode+".page."+title;
				break;
			case (state=="hover"):
				title = this.getTitle() || LHM.getCurrentHover().viewUrl;
				wt_be=LPM.mode+".hover."+ title;
				break;
			case (state == "modeChange"):
				title = this.getTitle() || LPM.currentPage.id;
				wt_be=LPM.mode+".newMode."+title;
				break;
			case (state=="zoomend"):
				wt_be=LPM.mode + ".zoom." + LPM.map.map.getZoom();
				if (LPM.mode == "magazine") {
					title = this.getTitle() || LPM.currentPage.id;
					wt_be=LPM.mode+".page."+title;
				}
				break;
			default:
				wt_be=LPM.mode + "." + state;
				break;
		}
	}
	return fire;
};
TrackingManager.prototype.preventDoubleCalls = function(state) {
	this.pause = state;
	log("webtrekk.pause: "+ this.pause);
	if(this.pause)window.setTimeout("LPM.tracker.preventDoubleCalls()", this.interval);
};
// #############################  IVW ################################
IVWManager = function() {
	this.hash = false;
	this.szmvar = false;
	this.IVW = false;
	this.pause = false;
	this.container = $('#ivw-container');
	this.mClientTag="http://mclient2.ivwbox.de/cgi-bin/ivw/CP/1207/meinberl/";
	this.fraboUrl = "http://meinberl.ivwbox.de/2004/01/survey.js";
	this.firstRun = false;
};
IVWManager.prototype.init = function() {
	this.getHash();
	szmvars = this.getSzm();
};
IVWManager.prototype.newPage = function(page) {
		var ivw_image = this.getIVW();
		var frabotag = "";
		var mClient_image = "";

		if(this.hash) 
			mClient_image = '<img src="'+this.mClientTag+this.hash+'" width="1" height="1" alt="szmmctag" />';
		
		if(page!="home")
			window.setTimeout("LPM.tracking.ivw.getFrabo()", 200);
			
		this.container.empty().append(ivw_image + "\n" + mClient_image);
};
IVWManager.prototype.getHash = function(status) {
    var url = LPM.getGlobals().portalUrl + "/szmHash";
    var self = this;
	$.get(url, function(data){
	   if($.trim(data)!="not")
       {
           //if(LPM.getGlobals().loginStatus != "loggedIn")
           		self.hash = $.trim(data);
		   		warn("ivw.mclient true: " + self.hash);
				if (status=="logging")
					self.callSzm();
       }
       else
       {
           self.hash=false;
		   warn("ivw.mclient false: " + self.hash);
		   if (status=="logging")
				self.callSzm();
       }
    });
};
IVWManager.prototype.logging = function() {
	this.getHash("logging");
};
IVWManager.prototype.callSzm = function() {
	var mClient_image = '<img src="'+this.mClientTag+this.hash+'" width="1" height="1" alt="szmmctag" />';
	this.container.empty().append(mClient_image);
};
IVWManager.prototype.getIVW = function() {
	var src = "http://meinberl.ivwbox.de/cgi-bin/ivw/CP/mb" + LPM.mode;	
	var ivw_image = '<img src="'+ src +'?r='+escape(document.referrer)+'&d='+(Math.random()*100000)+'" width="1" height="1" alt="szmtag" />';		
	return ivw_image;
};
IVWManager.prototype.getSzm = function() {
	var szmvar="meinberl//CP//mb" + LPM.mode;	
	return szmvar;
};
IVWManager.prototype.getFrabo = function() {
	
	if (this.firstRun && !$.browser.safari)
		mbLoadAnyScript(this.fraboUrl);
	else {
		var iframe = document.createElement("iframe");
		iframe.name = "frabo"
		iframe.id = "frabo";
		iframe.src = "";
		this.container.append(iframe);
		
		if (iframe) {
			var iframeDoc;
			if (iframe.contentDocument) {
				iframeDoc = iframe.contentDocument;
			}
			else if (iframe.contentWindow) {
				iframeDoc = iframe.contentWindow.document;
			}
			else if (window.frames[iframe.name]) {
				iframeDoc = window.frames[iframe.name].document;
			}
			if (iframeDoc) {
				iframeDoc.open();
				iframeDoc.write('<html><head><script>var szmvars = "' + this.getSzm() + '"; <\/script><script src="'+ this.fraboUrl +'"><\/script><\/head><body><\/body><\/html>');
				iframeDoc.close();
			}
		}	
		this.firstRun = true;	
	}
	log("frabo called");
};

IVWManager.prototype.preventDoubleCalls = function(state) {
	this.pause = state;
	log("ivw.pause: "+ this.pause);
	if(this.pause)window.setTimeout("ivw.preventDoubleCalls()", 800);
};
// ########################################################################
// #####################   Own Stuff - do not delete   ####################
// ########################################################################

var wt_dm="track.webtrekk.de"; // track url
var wt_ci="942565534022140"; // webtrekk id(s)
var wt_be="de.startseite"; // content id

////// OPTIONAL
//// content group(s)
var wt_cg="";

//// click tracking												

var wt_ln=""; // click tracking: (auto|standard|link)
var wt_ln_attribute="";   // optional: for "standard" only
var wt_linktrack_params=""; // optional: for "link" only

//// heatmap tracking

var wt_hm=""; // activate heatmap tracking

//// form tracking

var wt_fm=""; // activate form tracking 
var wt_fm_anonymous=""; // anonymous data
var wt_fm_full_content=""; // full contents fields
var wt_fm_attribute="";

//// campaigns

var wt_mc=""; // mediacode
var wt_lp=""; // link position
var wt_kw=""; // keyword

//// custom parameter

var wt_pa="";

//// customer id 

var wt_cd="";

//// internal search

var wt_is="";

//// cookie handling

var wt_cookie="1"; // (3|1, 3 is default, 1st or 3rd party cookie)

// ########################################################################
// ##############   Webtrekk Stuff - pls check right version   ############
// ########################################################################

var wt_version = 179;
var wt_va = Array("wt_t1", "wt_t2", "wt_ln", "wt_fm", "wt_ba", "wt_co", "wt_qn", "wt_ca", "wt_pi", "wt_ov", "wt_cr", "wt_oi", "wt_cd", "wt_cg", "wt_st", "wt_linktrack_be", "wt_mc", "wt_mcvalue", "wt_cookie", "wt_cookie_sid", "wt_cookie_eid", "wt_cookie_l_v", "wt_cookie_one", "wt_cookie_sid_timeout", "wt_cookie_eid_timeout", "wt_linktrack_params", "wt_lp", "wt_hm", "wt_pa", "wt_be", "wt_dm", "wt_ci", "wt_kw", "wt_ln_attribute", "wt_fm_anonymous", "wt_reporturl", "wt_is", "wt_fm_full_content", "wt_fm_attribute", "wt_ep");
for (var i = 0; i < wt_va.length; i++) 
    eval("if(typeof(" + wt_va[i] + ")!='string')var " + wt_va[i] + "='';");
var wt_browserName = navigator.appName, wt_browserName = (wt_indexOf(wt_browserName, "Microsoft") ? wt_browserName : "MSIE"), wt_browserNameNS = (wt_browserName == "Netscape"), wt_browserNameIE = (wt_browserName == "MSIE");
if (!wt_be) 
    wt_be = wt_url2contentid(document.location.href);
function wt_href(){
    return wt_location().href;
};
function wt_location(){
    var r = document.location;
    if (!document.layers && document.getElementById) {
        eval("try {r=top.document.location;}catch(e){};");
    }
    else {
        r = top.document.location;
    };
    return r;
};
function wt_length(a){
    return a != "undefined" ? a.length : 0;
};
function wt_url2contentid(url){
    if (!url) 
        return "no_content";
    var tmp = new RegExp("//(.*)").exec(url);
    if (tmp.length < 1) 
        return "no_content";
    return tmp[1].split("?")[0].replace(/\./g, "_").replace(/\//g, ".").replace(/\.{2,};/g, ".").toLowerCase();
};
function wt_include(s){
    if (!document.createElement) 
        return false;
    var html_doc = document.getElementsByTagName('head').item(0);
    var js = document.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', s);
    html_doc.appendChild(js);
    return true;
};
function wt_indexOf(a, b, c){
    return a.indexOf(b, c ? c : 0);
};
function wt_typeof(v){
    return (typeof v != "undefined") ? 1 : 0;
};
function wt_registerEvent(obj, e, f){
    if (obj.addEventListener) {
        obj.addEventListener(e, f, false);
    }
    else {
        if (obj.attachEvent) {
            obj.attachEvent("on" + e, f);
        }
    }
};
function wt_maxlen(v, l){
    if (v && v.length > l) 
        return v.substring(0, l - 1);
    return v;
};
function wt_escape(u){
    if (typeof(encodeURIComponent) == 'function') 
        return encodeURIComponent(u);
    return escape(u);
};
function wt_unescape(u){
    if (typeof(decodeURIComponent) == 'function') 
        return decodeURIComponent(u);
    return unescape(u);
};
function wt_decoder(u){
    var tmp = unescape(u);
    if (document.layers) 
        return wt_escape(tmp);
    if (document.getElementById) {
        eval("try {tmp=decodeURIComponent(u);}catch(e){};");
    }
    else {
        tmp = decodeURIComponent(u);
    };
    return wt_escape(tmp);
};
function wt_encoding(){
    var tmp = "";
    if (typeof(encodeURIComponent) != 'function') 
        tmp += "&enc0=old";
    tmp += "&enc1=&enc2=";
    if (document.characterSet) 
        tmp += document.characterSet.toLowerCase();
    if (document.charset) 
        tmp += document.charset.toLowerCase();
    return tmp;
};
function wt_crypt(t){
    var org = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var rep = "NOPQRSTUVWXYZABCDEFGHIJKLM5678901234";
    t = t.replace(new RegExp("[A-Z]|[a-z]|[0-9]", "gi"), function($1){
        var sp = /[A-Z]/g;
        var pos = org.indexOf($1.toUpperCase());
        if (sp.test($1)) {
            return rep.charAt(pos);
        }
        else {
            return rep.charAt(pos).toLowerCase();
        }
    });
    return t;
};
function wt_zeroPad(n, countZeros){
    var result = n + '';
    return "000000000000".substring(0, (countZeros - result.length)) + result;
};
function wt_sid(){
    return '2' + wt_zeroPad(Math.floor(new Date().getTime() / 1000), 10) + wt_zeroPad(Math.floor(Math.random() * 1000000), 8);
};
function wt_getexpirydate(mins){
    var UTCstring;
    var Today = new Date();
    var nomilli = Date.parse(Today);
    Today.setTime(nomilli + mins * 60 * 1000);
    UTCstring = Today.toUTCString();
    return UTCstring;
};
function wt_setCookie(name, value, duration){
    var d = location.hostname.split(".");
    d = d[d.length - 2] + "." + d[d.length - 1];
    var c;
    if (duration) 
        c = name + "=" + escape(value) + ";domain=" + d + ";path=/;expires=" + wt_getexpirydate(duration);
    else 
        c = name + "=" + escape(value) + ";path=/;domain=" + d;
    document.cookie = c;
};
function wt_getCookie(cookiename){
    var cookiestring = "" + document.cookie;
    var index1 = cookiestring.indexOf(cookiename);
    if (index1 == -1 || cookiename == "") 
        return "";
    var index2 = cookiestring.indexOf(';', index1);
    if (index2 == -1) 
        index2 = cookiestring.length;
    return unescape(cookiestring.substring(index1 + cookiename.length + 1, index2));
};
function wt_urlParam(url, param, def){
    var p = new Array();
    if (url.indexOf("?") > 0) 
        p = url.substring(url.indexOf("?") + 1).replace(/&amp;/, "&").split("&");
    for (var i = 0; i < p.length; i++) {
        if (p[i].indexOf(param + "=") == 0) {
            return wt_unescape(p[i].substring(param.length + 1).replace(/\+/, "%20"));
        }
    };
    return def;
};
function wt_checkCookie(){
    if (wt_getCookie("wt_cookietest") == "1") 
        return true;
    wt_setCookie("wt_cookietest", "1", 0);
    return wt_getCookie("wt_cookietest") == "1";
};
var wt_linktrack_p = "";
var wt_linktrack_namedlinks_only;
if (wt_ln == "auto" || wt_ln == "link") {
    wt_linktrack_namedlinks_only = false;
}
else {
    wt_linktrack_namedlinks_only = true;
};
if (wt_ln) {
    wt_registerEvent(window, "load", wt_ltinstall);
};
function wt_ltinstall(){
    for (c = 0; c < document.links.length; c++) {
        var name = document.links[c].name;
        if (wt_ln_attribute != "") {
            var tmp = "";
            eval("tmp = (document.links[c].getAttribute(wt_ln_attribute)?document.links[c].getAttribute(wt_ln_attribute):'')");
            if (tmp) 
                name = tmp;
        };
        if (name || !wt_linktrack_namedlinks_only) {
            wt_registerEvent(document.links[c], 'mousedown', wt_linktrack);
        }
    }
};
function wt_linktrack(e){
    if ((e.which && e.which == 1) || (e.button && e.button == 1)) {
        var a = document.all ? window.event.srcElement : this;
        for (var i = 0; i < 4; i++) {
            if (a.tagName && a.tagName.toLowerCase() != "a" && a.tagName.toLowerCase() != "area") {
                a = a.parentElement
            }
        };
        a.lname = (a.name ? a.name : "");
        if (wt_ln_attribute != "") {
            var tmp = "";
            eval("tmp = (a.getAttribute(wt_ln_attribute)?a.getAttribute(wt_ln_attribute):'')");
            if (tmp) 
                a.lname = tmp;
        };
        a.lpos = 0;
        if (!wt_length(a.lpos) && a.tagName && a.tagName.toLowerCase() != "area") {
            c = document.links;
            for (d = 0; d < wt_length(c); d++) {
                if (a == c[d]) {
                    a.lpos = d + 1;
                    break
                }
            }
        };
        if (a.lpos) {
            if (wt_ln == "link") {
                var y = a.href.indexOf("//");
                var y = (y >= 0 ? a.href.substr(y + 2) : a.href);
                if (typeof(wt_linktrack_pattern) != 'undefined') {
                    if (typeof(wt_linktrack_replace) != 'string') 
                        wt_linktrack_replace = "";
                    y = y.replace(wt_linktrack_pattern, wt_linktrack_replace);
                };
                wt_linktrack_p = wt_be.split(";")[0] + "." + (a.lname ? (a.lname + ".") : "") + y.split("?")[0].replace(/\//g, ".");
                var p = wt_linktrack_params.replace(/;/g, ",").split(",");
                for (var i = 0; i < p.length; i++) {
                    var v = wt_urlParam(y, p[i], "");
                    if (v) 
                        wt_linktrack_p += "." + p[i] + "." + v;
                }
            }
            else 
                if (wt_ln == "auto") {
                    if (!a.lname) 
                        wt_linktrack_p = (wt_linktrack_be ? (wt_linktrack_be + ".") : (wt_be.split(";")[0] + ".link.")) + a.lpos;
                    else 
                        wt_linktrack_p = wt_be.split(";")[0] + "." + a.lname;
                }
                else 
                    if (wt_ln == "standard" && a.lname) 
                        wt_linktrack_p = a.lname;
            if (wt_linktrack_p && a.target != "") 
                wt_send();
        }
    }
};
var wt_gatherforms_p = "";
var wt_form = null;
var wt_form_focus = "";
var wt_form_submit = false;
if (wt_fm) {
    wt_registerEvent(window, "load", wt_ftinstall);
};
function wt_ftinstall(){
    wt_findform();
    if (!wt_form) 
        return;
    for (var j = 0; j < wt_form.elements.length; j++) {
        var e = wt_form.elements[j];
        wt_registerEvent(e, "focus", wt_formfocus);
    };
    wt_registerEvent(wt_form, "submit", wt_formsubmit);
};
function wt_findform(){
    wt_form = null;
    if (document.forms) 
        wt_form = document.forms[0];
    var f = document.forms;
    for (var i = 0; i < f.length; i++) {
        var cf = f[i];
        if (wt_typeof(cf.elements["wt_form"])) {
            wt_form = cf;
            return;
        }
    }
};
function wt_formsubmit(){
    wt_form_submit = true;
};
function wt_formfocus(e){
    var a = document.all ? window.event.srcElement : e.target;
    if (!a.name || a.type == "submit" || a.type == "image") 
        return;
    wt_form_focus = (wt_form.name ? wt_form.name : wt_be.split(";")[0]) + "." + a.name + "." + a.type;
};
function wt_gatherForm(){
    var del = ";";
    if (!wt_form) 
        return;
    var f = wt_form;
    var p = wt_form.name ? wt_form.name : wt_be.split(";")[0];
    if (wt_fm_attribute) {
        var tmp = "";
        eval("tmp = (f.getAttribute(wt_fm_attribute)?f.getAttribute(wt_fm_attribute):'')");
        if (tmp) 
            p = tmp;
    };
    var fl = "";
    if (wt_typeof(f.elements["wt_fields"])) 
        fl = f.elements["wt_fields"].value;
    if (!fl) {
        for (var i = 0; i < f.elements.length; i++) {
            var e = f.elements[i];
            if (e.name) 
                fl += e.name + del;
        };
        fl = fl.substring(0, fl.lastIndexOf(del))
    };
    var fields = fl.split(del);
    var fields_length = fields.length;
    var full_fields = wt_fm_full_content.split(del);
    var pa = "";
    var emptyradios = new Array();
    for (var i = 0; i < f.elements.length; i++) {
        var e = f.elements[i], value, value2, use = false;
        if (fl) {
            for (var j = 0; j < fields_length; j++) 
                if (e.name == fields[j]) 
                    use = true;
        }
        else {
            if (e.name) 
                use = true;
        };
        if (use) {
            value = null;
            if (e.type == 'select-multiple') {
                for (var j = 0; j < e.options.length; j++) {
                    var found = false;
                    if (e.options[j].selected) {
                        found = true;
                        pa += ";" + p + ".select-multiple." + e.name.replace(/[\.|;]/, "_") + "." + e.options[j].value.replace(/[\.|;]/, "_");
                    };
                    if (!found) 
                        value = "empty";
                }
            };
            if (e.type == 'select-one') {
                if (e.selectedIndex != -1) {
                    value = e.options[e.selectedIndex].value.replace(/[\.|;]/, "_");
                    if (!value) 
                        value = "empty";
                }
            };
            if (e.type == 'checkbox') {
                if (!e.checked) 
                    value = "empty";
                else 
                    value = e.value.replace(/[\.|;]/, "_");
            };
            if (e.type == 'radio') {
                if (e.checked) 
                    value = e.value.replace(/[\.|;]/, "_");
                emptyradios[emptyradios.length] = e.name;
            };
            if (e.type == "password" || e.type == "text" || e.type == "textarea") {
                value = (e.value ? "filled_out" : "empty");
                for (var k = 0; k < full_fields.length; k++) 
                    if (full_fields[k] == e.name) 
                        value = wt_maxlen(e.value, 30);
                if (!value) 
                    value = "empty";
            };
            if (value) {
                name = e.name.replace(/[\.|;]/, "_");
                value2 = ";" + p + "." + name + "." + e.type + "|";
                if (pa.indexOf(value2) == -1) 
                    pa += value2 + (wt_fm_anonymous != "" ? "anon" : value);
            }
        }
    };
    for (var i = 0; i < emptyradios.length; i++) {
        var n = ";" + p + "." + emptyradios[i].replace(/[\.|;]/, "_") + ".radio|";
        if (pa.indexOf(n) == -1) 
            pa += n + (wt_fm_anonymous != "" ? "anon" : "empty");
    };
    if (pa) {
        pa = pa.substring(1);
    };
    return pa;
};
if (wt_fm || wt_ln) {
    wt_registerEvent(window, (wt_browserNameIE && wt_typeof(window.onbeforeunload)) ? "beforeunload" : "unload", wt_unload);
};
function wt_unload(){
    if (wt_form) 
        wt_gatherforms_p = wt_gatherForm();
    var p = "";
    if (wt_linktrack_p) 
        p += "&ct=" + wt_escape(wt_maxlen(wt_linktrack_p, 255));
    if (wt_gatherforms_p) {
        p += "&ft=" + wt_escape(wt_gatherforms_p);
        p += "&fs=" + (wt_form_submit ? "1" : "0") + "&ff=" + wt_escape(wt_form_focus);
    };
    if (p) {
        if (typeof(wt_ep) == 'string' && wt_ep != '') {
            wt_ep = wt_ep.split(/;/);
            for (z in wt_ep) {
                wtep = wt_ep[z].split(/=/);
                wtep[1] = wt_escape(wtep[1]);
                p += '&' + wtep[0] + '=' + wtep[1];
            }
        };
        wt_quicksend(wt_escape(wt_be.split(";")[0]) + ",1," + wt_baseparams(), p + wt_encoding());
        wt_linktrack_p = "";
        wt_gatherforms_p = "";
    }
};
if (typeof(time_start) == "number" && typeof(wt_be) == "string" && !document.layers) {
    var time_stop = (new Date()).getTime();
    wt_registerEvent(window, "load", wt_ttonload);
};
function wt_ttonload(){
    if (typeof(time_start) == "number") {
        wt_t1 = time_stop - time_start;
        var time_stop2 = new Date().getTime();
        wt_t2 = time_stop2 - time_start;
        wt_send();
        time_start = "";
        wt_t1 = "";
        wt_t2 = "";
    }
};
if (wt_mc) {
    var m = wt_mc.split(";");
    wt_mcvalue = "";
    for (var i = 0; i < m.length; i++) {
        if (wt_mcvalue != "") 
            wt_mcvalue += "|";
        wt_mcvalue += wt_urlParam(wt_href(), m[i], "");
    }
};
var wt_tmp = wt_urlParam(wt_href(), "wt_lp", "");
if (wt_tmp != "") 
    wt_lp = wt_tmp;
wt_tmp = wt_urlParam(wt_href(), "wt_kw", "");
if (wt_tmp != "") 
    wt_kw = wt_tmp;
if (wt_hm) {
    var exit = false;
    if (typeof(wt_heatmap_sites) == 'object' && typeof(wt_heatmap_sites_ini) == 'string') {
        wt_registerEvent(window, "load", wt_hminstall);
        exit = true;
    }
    else {
        if (!document.layers && document.getElementById) {
            var stags = document.getElementsByTagName('script');
            for (var i = 0; i < stags.length; i++) {
                if (stags[i].src.match(/webtrekk.*\.js/g) && !exit) {
                    wt_include(wt_hm_config_file = stags[i].src.replace(/webtrekk[a-z|A-Z|0-9|_]*\.js/g, '') + 'heatmap_config.js?' + Math.random());
                    wt_registerEvent(window, "load", wt_hminstall);
                    exit = true;
                }
            }
        }
    }
};
function wt_hminstall(){
    if (typeof(wt_heatmap_sites) == 'object' && typeof(wt_heatmap_sites_ini) == 'string') {
        for (var z = 0; z < wt_heatmap_sites.length; z++) {
            if (wt_heatmap_sites[z].toLowerCase() == wt_be.split(";")[0].toLowerCase() && wt_heatmap_sites_ini.toLowerCase() == wt_crypt(wt_heatmap_sites.join('')).replace(/\./g, '').toLowerCase() && wt_heatmap_on == false) {
                wt_registerEvent(document, "mousedown", wt_recordClick);
            }
        }
    }
    else {
        if (typeof(wt_heatmap_retry) == "undefined") 
            wt_heatmap_retry = 0;
        wt_heatmap_retry++;
        if (wt_heatmap_retry < 60) 
            window.setTimeout("wt_hminstall()", 100);
    }
};
function wt_recordClick(e){
    if (typeof(wt_refpoint_id) != 'string') {
        wt_refpoint_id = 'wt_refpoint';
    }
    else {
        if (wt_refpoint_id == '') {
            wt_refpoint_id = 'wt_refpoint';
        }
    };
    var isOpera = (navigator.userAgent.indexOf('Opera') != -1);
    var isIE = (!isOpera && navigator.userAgent.indexOf('MSIE') != -1);
    var pos = {
        left: -1,
        top: -1
    };
    if (document.getElementById(wt_refpoint_id)) {
        var obj = document.getElementById(wt_refpoint_id);
        if (typeof obj.offsetLeft != 'undefined') {
            while (obj) {
                pos.left += obj.offsetLeft;
                pos.top += obj.offsetTop;
                obj = obj.offsetParent;
            }
        }
    };
    var posx = 0;
    var posy = 0;
    if (!e) {
        var e = window.event;
    };
    if (e.pageX || e.pageY) {
        posx = e.pageX;
        posy = e.pageY;
    }
    else 
        if (e.clientX || e.clientY) {
            posx = e.clientX;
            posy = e.clientY;
            if (isIE) {
                if (document.body.scrollLeft > 0 || document.body.scrollTop > 0) {
                    posx += document.body.scrollLeft;
                    posy += document.body.scrollTop;
                }
                else 
                    if (document.documentElement.scrollLeft > 0 || document.documentElement.scrollTop > 0) {
                        posx += document.documentElement.scrollLeft;
                        posy += document.documentElement.scrollTop;
                    }
            }
        };
    var width1 = 0;
    if (isIE) {
        width1 = document.body.clientWidth;
    }
    else {
        width1 = self.innerWidth - 16;
    };
    var sendPixel = true;
    if (posx >= width1) {
        sendPixel = false;
    };
    if ((pos.top >= 0 || pos.left >= 0) && posx > pos.left && posy > pos.top) {
        posx = '-' + (posx - pos.left);
        posy = '-' + (posy - pos.top);
    };
    if (sendPixel) 
        wt_quicksend(wt_escape(wt_be.split(";")[0]) + "," + posx + "," + posy, '', "hm.pl");
};
var wt_heatmap_on = (wt_href().indexOf("wt_heatmap=1") >= 0);
function wt_heatmap0(){
    if (typeof(wt_heatmap) != "undefined") {
        window.setTimeout("wt_heatmap()", 1000);
    }
    else {
        if (typeof(wt_heatmap_retry) == "undefined") 
            wt_heatmap_retry = 0;
        wt_heatmap_retry++;
        if (wt_heatmap_retry < 60) 
            window.setTimeout("wt_heatmap0()", 1000);
    }
};
if (wt_href().indexOf("wt_heatmap=0") >= 0) {
    wt_heatmap_on = false;
};
if (wt_heatmap_on) {
    if (wt_reporturl == '') 
        wt_reporturl = 'report.webtrekk.de/cgi-bin/wt';
    if (wt_include(location.protocol + "//" + wt_reporturl + "/heatmap.pl?wt_be=" + wt_escape(wt_be.split(";")[0]) + "&x=" + new Date().getTime() + wt_encoding())) 
        if (navigator.userAgent.indexOf('MSIE 6') != -1 && navigator.userAgent.indexOf('Windows NT 5.0') != -1) {
            alert("Click OK to start heatmap.");
        };
    wt_registerEvent(window, "load", wt_heatmap0);
};
function wt_overlay0(){
    if (typeof(wt_overlay) != "undefined") 
        wt_overlay();
    else {
        if (typeof(wt_overlay_retry) == "undefined") 
            wt_overlay_retry = 0;
        wt_overlay_retry++;
        if (wt_overlay_retry < 60) 
            window.setTimeout("wt_overlay0()", 1000);
    }
};
var wt_overlay_on = (wt_href().indexOf("wt_overlay=1") >= 0 || document.cookie.indexOf("wt_overlay=1") >= 0);
if (wt_href().indexOf("wt_overlay=0") >= 0) {
    wt_overlay_on = false;
    document.cookie = "wt_overlay=0; expires=Thu, 01-Jan-70 00:00:01 GMT;";
};
if (wt_overlay_on) {
    document.cookie = "wt_overlay=1";
    if (wt_reporturl == '') 
        wt_reporturl = 'report.webtrekk.de/cgi-bin/wt';
    if (wt_include(location.protocol + "//" + wt_reporturl + "/overlay.pl?wt_be=" + wt_escape(wt_be.split(";")[0]) + "&x=" + new Date().getTime() + wt_encoding())) 
        wt_registerEvent(window, "load", wt_overlay0);
};
if (wt_cookie == "1") {
    var wt_cookie_one = false;
    var wt_cookie_sid = wt_getCookie("wt_sid");
    var wt_cookie_l_v = wt_getCookie("wt_l_v");
    var wt_cookie_eid = wt_getCookie("wt_eid");
    if (!wt_cookie_eid_timeout) 
        wt_cookie_eid_timeout = 60;
    if (!wt_cookie_sid_timeout) 
        wt_cookie_sid_timeout = 30;
    var tmp = parseInt(wt_cookie_sid);
    var tmp2 = Math.floor(new Date().getTime() / 1000);
    if (tmp > 0 && (tmp + wt_cookie_sid_timeout * 60) < tmp2) 
        wt_cookie_sid = "";
    if (!wt_cookie_sid) {
        wt_cookie_sid = wt_sid();
        wt_cookie_one = true;
    };
    if (!wt_cookie_eid) {
        wt_cookie_eid = wt_cookie_sid;
        wt_setCookie("wt_eid", wt_cookie_eid, wt_cookie_eid_timeout * 30 * 24 * 60);
    };
    wt_cookie_l_v = new Date().getTime();
    wt_setCookie("wt_l_v", wt_cookie_l_v);
    wt_setCookie("wt_sid", wt_cookie_sid);
};
function wt_sendinfo(p, mode, ep){
    if ((typeof(time_start) != "number" && (wt_be != "" || p != "")) || document.layers) 
        wt_send(p, mode, ep);
};
function wt_quicksend(baseparams, params, script){
    if (!wt_dm || !wt_ci) 
        return;
    if (!script) 
        script = "wt.pl";
    if (wt_cookie == "1") {
        params = "&sid=" + wt_cookie_sid + "&l_v=" + wt_cookie_l_v + "&eid=" + wt_cookie_eid + "&one=" + (wt_cookie_one ? "1" : "0") + params;
    };
    var wt_url = (location.protocol == "https:" ? "https:" : "http:") + "//" + wt_dm + "/" + wt_ci + "/" + script + "?p=" + wt_version + "," + baseparams + params;
    if (document.images) {
        if (typeof(wt_i) == "undefined") 
            wt_i = new Array();
        var ii = wt_i.length;
        wt_i[ii] = new Image();
        wt_i[ii].src = wt_url;
    }
    else {
        document.write("<img src='" + wt_url + "' height='1' width='1'>");
    }
};
function wt_baseparams(){
    var wt_c = screen.width + "x" + screen.height + "," + (navigator.appName != 'Netscape' ? screen.colorDepth : screen.pixelDepth) + ",";
    wt_c += ((navigator.cookieEnabled == true) ? "1," : ((navigator.cookieEnabled == false) ? "0," : ((document.cookie.indexOf("=") != -1) ? "1," : "0,")));
    wt_c += new Date().getTime() + ",";
    var wt_ref = 0;
    if (!wt_ref && document.referrer.length > 0) 
        wt_ref = wt_decoder(document.referrer);
    wt_c += wt_ref;
    var h = 0;
    if (!document.layers && document.getElementById) {
        eval("try {h = top.window.innerHeight;}catch(e){};");
    }
    else {
        h = top.window.innerHeight;
    };
    if (!h) 
        eval("try {h = top.document.body.clientHeight;}catch(e){};");
    if (!h) 
        eval("try {h = top.document.documentElement.clientHeight;}catch(e){};");
    var w = 0;
    if (!document.layers && document.getElementById) {
        eval("try {w = top.window.innerWidth;}catch(e){};");
    }
    else {
        w = top.window.innerWidth;
    };
    if (!w) 
        eval("try {w = top.document.body.clientWidth;}catch(e){};");
    if (w == 'undefined') 
        w = -1;
    if (h == 'undefined') 
        h = -1;
    wt_c += "," + w + "x" + h;
    wt_c += "," + (navigator.javaEnabled() ? "1" : "0");
    return wt_c;
};
function wt_send(p, mode, ep){
    if (mode == "link") {
        wt_linktrack_p = p;
        wt_ln = "manual";
        wt_ep = ep;
        wt_registerEvent(window, (wt_browserNameIE && wt_typeof(window.onbeforeunload)) ? "beforeunload" : "unload", wt_unload);
        return;
    };
    if (mode == "click") {
        wt_linktrack_p = p;
        wt_ep = ep;
        wt_unload();
        return;
    };
    var wt_content = (p ? p : wt_be);
    if (!wt_content) 
        wt_content = "no_content";
    var wt_s_base = wt_escape(wt_content) + ",1,";
    wt_s_base += wt_baseparams();
    var wt_s = wt_encoding();
    var wt_la = "";
    if (typeof(navigator.language) == "string") 
        wt_la = navigator.language;
    else 
        if (typeof(navigator.userLanguage) == "string") 
            wt_la = navigator.userLanguage;
    var wt_len = navigator.plugins.length, wt_np = "";
    if (wt_len > 0) {
        var wt_plugs = Array();
        var wt_np = '';
        for (var i = 0; i < wt_len; i++) {
            if (navigator.plugins && navigator.appName != 'Microsoft Internet Explorer') {
                if (navigator.plugins[i].name == "Shockwave Flash") {
                    wt_np = navigator.plugins[i].description;
                }
                else {
                    wt_np = navigator.plugins[i].name;
                };
                for (var j in wt_plugs) {
                    if (wt_np == wt_plugs[j]) 
                        wt_np = "";
                };
                if (wt_np != "") {
                    wt_plugs.push(wt_np);
                }
            }
        };
        wt_np = wt_plugs.join("|");
    };
    var wt_cp = '';
    if (typeof(wt_c) == 'object') {
        for (z in wt_c) {
            wt_cp += '&c' + z + '=' + wt_escape(wt_c[z]);
        }
    };
    if (wt_ov) 
        wt_s += "&ov=" + wt_escape(wt_ov);
    if (wt_cr) 
        wt_s += "&cr=" + wt_escape(wt_cr);
    if (wt_oi) 
        wt_s += "&oi=" + wt_escape(wt_oi);
    if (wt_ba) 
        wt_s += "&ba=" + wt_escape(wt_ba);
    if (wt_co) 
        wt_s += "&co=" + wt_escape(wt_co);
    if (wt_qn) 
        wt_s += "&qn=" + wt_escape(wt_qn);
    if (wt_ca) 
        wt_s += "&ca=" + wt_escape(wt_ca);
    if (wt_pi) 
        wt_s += "&pi=" + wt_escape(wt_pi);
    if (wt_st) 
        wt_s += "&st=" + wt_escape(wt_st);
    if (wt_cd) 
        wt_s += "&cd=" + wt_escape(wt_cd);
    if (wt_t1) 
        wt_s += "&t1=" + wt_escape(wt_t1);
    if (wt_t2) 
        wt_s += "&t2=" + wt_escape(wt_t2);
    if (wt_la) 
        wt_s += "&la=" + wt_escape(wt_la);
    if (wt_cg) 
        wt_s += "&cg=" + wt_escape(wt_cg);
    if (wt_mcvalue) 
        wt_s += "&mcv=" + wt_escape(wt_mcvalue);
    if (wt_length(wt_mcvalue)) {
        wt_s += "&mc=" + wt_mc;
        wt_s += "&mcd=" + wt_location().hostname;
    };
    if (wt_pa) 
        wt_s += "&pa=" + wt_escape(wt_maxlen(wt_pa, 255));
    if (wt_lp) 
        wt_s += "&lp=" + wt_escape(wt_maxlen(wt_lp, 255));
    if (wt_kw) 
        wt_s += "&kw=" + wt_escape(wt_maxlen(wt_kw, 255));
    if (wt_is) 
        wt_s += "&is=" + wt_escape(wt_maxlen(wt_is, 255));
    if (wt_cp) 
        wt_s += wt_cp;
    if (wt_cookie == "1") {
        if (wt_cookie_one) 
            wt_s += "&np=" + wt_escape(wt_np);
    }
    else {
        wt_s += "&np=" + wt_escape(wt_np);
    };
    wt_quicksend(wt_s_base, wt_s);
};



// szm_mclient.js 20041209
var szm_mccookie = "szm_mc";
var szm_prefix='http://mclient2.ivwbox.de/cgi-bin/ivw/CP/1207/';
var szm_prefixssl='https://mclientssl2.ivwbox.de/cgi-bin/ivw/CP/1207/';
// on every page
function szm_client(szm_site, szm_hcode, szm_isssl) {
if (szm_getcookie() != szm_hcode)
{ szm_getmclient(szm_site,szm_isssl,szm_hcode);
szm_setcookie(szm_hcode);
}
}
// before login, logout
function szm_clear() {
szm_setcookie("spring.de");
}
// privates
function szm_getcookie() {
var split = new Array();
split = document.cookie.split(";");
for(var i=0; i<split.length;i++) {
if(split[i].match(".*"+szm_mccookie+".*")) {
return (split[i].split("="))[1];
}
} return "";
}
function szm_getmclient(szm_site,szm_isssl,szm_hcode) {
var img = new Image();
if(szm_isssl) img.src = szm_prefixssl+szm_site+'/'+szm_hcode;
else img.src = szm_prefix+szm_site+'/'+szm_hcode;
}
function szm_setcookie(code) {
document.cookie = szm_mccookie+"="+code;
}
// EOF
