var debug = false;

var ui = null;

function init() {

  ui = new UserInterfaceObj();
  ui.start();
  
  document.getElementById("z"+ui.scale).className = "zon";
}

function TileObj(init_tile_set, init_frame, init_div, init_anchor_top,
                 init_anchor_left, init_frame_width, init_frame_height,
		 init_tile_width, init_tile_height, init_xpos, init_ypos) {
  ui.printMessage("new TileObj(init_tile_set.status: "+init_tile_set.status+
                      "init_frame: "+init_frame+", init_div: "+init_div+
		      ", init_anchor_top: "+init_anchor_top+
		      ", init_anchor_left: "+init_anchor_left+
		      ", init_frame_width: "+init_frame_width+
		      ", init_frame_height: "+init_frame_height+
		      ", init_tile_width: "+init_tile_width+
		      ", init_tile_height: "+init_tile_height+", init_xpos: "+
		      init_xpos+", init_ypos: "+init_ypos+")");
  this.id = 0;
  this.src = "";
  this.frame = init_frame;
  this.div = init_div;
  this.status = "prepared";
  this.retry_status = false;

  this.xpos = init_xpos;
  this.ypos = init_ypos;

  this.anchor_top = init_anchor_top;
  this.anchor_left = init_anchor_left;
  this.frame_height = init_frame_height;
  this.frame_width = init_frame_width;
  this.tile_width = init_tile_width;
  this.tile_height = init_tile_height;

  this.inter = init_tile_set.inter;
  this.priority = 2;
  this.preload_id = 0;
  this.tile_set = init_tile_set;

  this.img = null;
}

TileObj.prototype.destroy = function() {
  ui.printMessage("[id: "+this.id+"] TileObj.destroy()");
  if (this.status == "complete") {
    this.div.removeChild(this.img);
  }
  delete this.img;
}

TileObj.prototype.updateSrc = function (init_inter, init_id, init_src,
  interlace, init_retry) {
  
  ui.printMessage("[id: "+init_id+"] TileObj.updateSrc(init_inter, "+
                      "init_id: "+init_id+", init_src: "+init_src+
		      ", interlace: "+interlace+", init_retry: "+
		      init_retry+")");
		      
  this.inter = init_inter;
  this.id = init_id;
  this.src = init_src;
  this.retry_status = init_retry;
  this.status = "loading";
  this.addImg(interlace);
  this.preload_id = this.inter.preload(this, this.img, init_src,
    this.priority);
}

TileObj.prototype.addImg = function(interlace) {
  ui.printMessage("[id: "+this.id+"] TileObj.addImg(interlace: "+
                      interlace+")");
  if (this.status == "loading") {
    if (this.img) {
      this.div.removeChild(this.img);
      delete this.img;
    }
    this.img = this.frame.document.createElement("img");
    this.img.src = this.src;
    this.img.id = "map_img_"+this.id;

    this.img.style.visibility = (interlace) ? "visible" : "hidden";
    this.positionImg();
    this.div.appendChild(this.img);
  } else {
    return false;
  }
}

TileObj.prototype.updateStatus = function () {
  ui.printMessage("[id: "+this.id+"] TileObj.updateStatus()");
  this.status = "complete";
  this.img.style.visibility = "visible";

  this.tile_set.checkStatus();
}

TileObj.prototype.zoom = function (new_anchor_top, new_anchor_left,
  new_tile_width, new_tile_height) {
  
  ui.printMessage("[id: "+this.id+"] TileObj.zoom(new_anchor_top: "+
                      new_anchor_top+", new_anchor_left: "+
		      new_anchor_left+", new_tile_width: "+
		      new_tile_width+", new_tile_height"+
		      new_tile_height+")");
  this.anchor_top = new_anchor_top;
  this.anchor_left = new_anchor_left;
  this.tile_width = new_tile_width;
  this.tile_height = new_tile_height;

  if (this.status == "complete") {
    this.positionImg();
  }
}

TileObj.prototype.positionImg = function() {
  ui.printMessage("[id: "+this.id+"] TileObj.positionImg()");

  this.img.style.top = this.anchor_top+"px";
  this.img.style.left = this.anchor_left+"px";
  this.img.style.width = this.tile_width+"px";
  this.img.style.height = this.tile_height+"px";
}


function PlacemarkObj(init_id, init_category, init_tile_set, init_x, init_y) {
  ui.printMessage("new PlacemarkObj(init_id: "+init_id+
                      ", init_category.id: "+init_category.id+
		      ", init_tile_set.status: "+init_tile_set.status
		      +", init_x: "+init_x+", init_y: "+init_y+")");
  this.id = init_id;
  this.category = init_category;
  this.tile_set = init_tile_set;
  this.x = init_x;
  this.y = init_y;

  this.bubble_loading = false;
  this.bubble_loaded = false;
  this.block_bubble = false;
  this.bubble = null;

  this.content = "";

  this.img = null;
}

PlacemarkObj.prototype.destroy = function () {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.destroy()");
  this.hide();
  if (this.img) {
    this.img.parentNode.removeChild(this.img);
    delete this.img;
  }

  if (this.bubble) {
    this.bubble.destroy();
  }
}

PlacemarkObj.prototype.show = function() {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.show()");
  if (!this.img) {
    this.img = this.tile_set.frame.document.createElement("img");
    if (ui.useSmallIcons) {
      this.img.src = omgeo_icon_path+this.category.parent_cat.icon_url;
//FIXME: Bei mehrstufigen Kategorien gibts Probleme:
//      this.img.src = omgeo_icon_path+this.category.parent_cat.parent_cat.icon_url;
    } else {
      this.img.src = omgeo_icon_path+this.category.icon_url;
    }
    this.img.style.zIndex = this.category.zIndex;
    this.img.style.position = "absolute";
    this.img.onmouseover = this.getOnMouseOverHandler();
    this.img.onmouseout = this.getOnMouseOutHandler();
    var append = true;
  } else {
    var append = false;
  }
  
  var d = (ui.useSmallIcons) ? 5 : 10;
  this.img.style.top = (this.y - d)+"px";
  this.img.style.left = (this.x - d)+"px";
  if (append) {
    this.category.div.appendChild(this.img);
  }
}

PlacemarkObj.prototype.hide = function() {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.hide()");
  if (this.img) {
    this.img.style.visibility = "hidden";
  }
  if (this.bubble) {
    this.bubble.destroy();
    delete this.bubble;
  }
}

PlacemarkObj.prototype.getBubbleAnchor = function(bubble_width, bubble_height) {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.getBubbleAnchor("+
                      "bubble_width: "+bubble_width+", bubble_height: "+
		      bubble_height+")");
  var frame_width = this.tile_set.frame_width;
  var frame_height = this.tile_set.frame_height;
  var bubble_top = this.tile_set.getYScreen(this.y) + 
                   Math.floor(this.img.height / 2);
  var position = "under";
  if (bubble_top + bubble_height > frame_height - omgeo_bubble_padding) {
    bubble_top -= this.img.height;
    position = "beside";
    if (bubble_top + bubble_height > frame_height - omgeo_bubble_padding) {
      bubble_top -= bubble_height - 2;
      position = "over";
      if (bubble_top < omgeo_bubble_padding) {
        bubble_top = frame_height - bubble_height - omgeo_bubble_padding;
	position = "beside";
      }
    }
  }
  
  if (position == "beside") {
    var bubble_left = this.tile_set.getXScreen(this.x) +
		      Math.floor(this.img.width/2);
    if (bubble_left + bubble_width > frame_width - omgeo_bubble_padding){
       bubble_left = this.tile_set.getXScreen(this.x) -
		     Math.floor(this.img.height/2) - bubble_width;
       if (bubble_left < omgeo_bubble_padding) {
	 bubble_left = frame_width - bubble_width - omgeo_bubble_padding;
       }
    }
  } else {
    ui.printMessage(frame_width - bubble_width - omgeo_bubble_padding);
    var bubble_left = (this.tile_set.getXScreen(this.x) < frame_width
		       - bubble_width - omgeo_bubble_padding) ? 
		       this.tile_set.getXScreen(this.x) - 1: frame_width
		       - bubble_width - omgeo_bubble_padding;  
  }
   
  ui.printMessage("bubble_top: "+bubble_top+", bubble_left: "+bubble_left+
                      ", frame_width: "+frame_width+", frame_height: "
		      +frame_height+", omgeo_bubble_padding: "+
		      omgeo_bubble_padding+", img.width: "+this.img.width+
		      ", img.height: "+this.img.height+", x: "+
		      this.tile_set.getXScreen(this.x)+", y: "+
		      this.tile_set.getYScreen(this.y));
  return {"top": bubble_top, "left": bubble_left};
}

PlacemarkObj.prototype.initBubble = function(init_content) {
  ui.printMessage("[id: "+this.id+"]"+
    " PlacemarkObj.initBubble(init_content.length: "+init_content.length+")");
  if (init_content.length > 1) {
    this.content = init_content;
    this.bubble_loaded = true;
    if (!this.block_bubble) {
      this.bubble = new BubbleObj(this.tile_set.frame, this, init_content);
    }
  }
  this.bubble_loading = false;
}

PlacemarkObj.prototype.showBubble = function() {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.showBubble()");
  this.bubble = new BubbleObj(this.tile_set.frame, this, this.content);
}

PlacemarkObj.prototype.hideBubble = function() {
  ui.printMessage("[id: "+this.id+"] PlacemarkObj.hideBubble()");
  this.bubble.destroy();
  delete this.bubble;
}

PlacemarkObj.prototype.getOnMouseOverHandler = function() {
  var placemark = this;
  return function (ev) {
    if (!placemark.bubble && !document.getElementById("bubble_frame")) {
      if (placemark.bubble_loaded) {
	placemark.showBubble(placemark.content);
      } else if (!placemark.bubble_loading) {
	ui.inter.newRequest(new GetBubbleContentRequestObj(placemark));
	placemark.bubble_loading = true;
      }
    }
    placemark.block_bubble = false;
    return false;
  }
}

PlacemarkObj.prototype.getOnMouseOutHandler = function() {
  var frame = this.tile_set.frame;
  var placemark = this;
  return function (ev) {
    ui.printMessage("placemark.img.onmouseout:");
    if (!ev) {
      ev = frame.event;
    }
    if (ev.target) {
      var target = ev.target;
    } else {
      var target = ev.srcElement;
    }
    ui.printMessage("target.id: "+target.id);
    if (target == placemark.img && placemark.bubble) {
      var related_target = (ev.relatedTarget) ? ev.relatedTarget : ev.toElement;
      while (related_target && related_target.nodeName != "BODY" &&
             related_target != placemark.bubble.bubble_div &&
	     related_target.parentNode) {
	ui.printMessage(related_target.nodeName);
	related_target = related_target.parentNode;
      }
      if (related_target != placemark.bubble.bubble_div) {
        placemark.hideBubble();
      }
    } else if (target == placemark.img) {
      placemark.block_bubble = true;
    }
    return false;
  }
}


function PMCategoryObj(init_id, init_name, init_icon_url, init_parent_cat,
                       init_zIndex, init_isFolder, init_inter, init_active) {
  ui.printMessage("new PMCategoryObj(init_id: "+init_id+", init_name: "+
                      init_name+", init_icon_url: "+init_icon_url+
		      ", init_parent_cat.id: "+
		      ((init_parent_cat) ? init_parent_cat.id : "null")+
		      ", init_zIndex: "+init_zIndex+", init_isFolder: "+
		      init_isFolder+", init_inter, init_active: "+init_active+
		      ")");
  this.id = init_id;
  this.name = init_name;
  this.icon_url = init_icon_url;
  this.placemarks = new Array();
  this.parent_cat = init_parent_cat;
  this.inter = init_inter;
  this.active = (init_active) ? true : false;
  ui.printMessage("[id: "+this.id+"] active: "+this.active);
  this.triggered = false;

  this.zIndex = init_zIndex;
  this.isFolder = init_isFolder;

  this.ckbox = (this.isFolder) ? document.getElementById("ck_fol_"+this.id) :
                                 document.getElementById("ck_cat_"+this.id);
  if (this.ckbox) {
    if (this.active) {
      this.toggleCheckbox(true);
      if (this.parent_cat) this.parent_cat.toggleCheckbox(true);
    } else {
      this.active = this.ckbox.checked;
    }
    var cat = this;
    this.ckbox.onclick = function() {cat.catOnClickHandler()};
  }

  this.updated = false;

  this.child_cats = new Array();
  if (this.parent_cat) {
    this.parent_cat.addChild(this);
  }

  this.cats = "";
  this.queued = false;
  this.initialized = false;

  this.appendDiv();
}

PMCategoryObj.prototype.destroy = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.destroy()");
  delete this.placemarks;
  for (var i=0; i<this.child_cats.length; i++) {
    this.child_cats[i].destroy();
    delete this.child_cats[i];
  }
  delete this.child_cats;
  if (this.div) {
    this.div.parentNode.removeChild(this.div);
    delete this.div;
  }
}

PMCategoryObj.prototype.createChildCategories = 
  function (children, active_cats) {
  
  ui.printMessage("[id: "+this.id+"] "+
                  "PMCategoryObj.createChildCategories(children)");
  for (var i=0; i<children.length; i++) {
    var cat_data = children[i];
    var activate = this.active;
    if (!activate) {
      for (var j=0; j<active_cats.length; j++) {
        if (active_cats[j] == cat_data.id) {
	  activate = true;
	  break;
	}
      }
    }
    var isFolder = (this == ui.root);
    var zIndex = (isFolder) ? "0" : cat_data.zIndex;
    var cat = new PMCategoryObj(cat_data.id, cat_data.name, cat_data.icon_url,
                                this, zIndex, isFolder, this.inter, activate);
    if (cat_data.children)
      cat.createChildCategories(cat_data.children, active_cats);
  }
}

PMCategoryObj.prototype.appendDiv = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.appendDiv()")
  this.div = ui.map_frame.document.createElement("div");
  this.div.style.zIndex = this.zIndex;
  if (this.active) {
    this.div.style.visibility = "visible";
  } else {
    this.div.style.visibility = "hidden";
  }
  if (ui && ui.active_tile_set) ui.active_tile_set.div.appendChild(this.div); 
}

PMCategoryObj.prototype.addChild = function(new_child) {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.addChild(new_child.id"+
                      new_child.id+")");
  this.child_cats[this.child_cats.length] = new_child;
}

PMCategoryObj.prototype.addPlacemark = function(new_placemark) {
  ui.printMessage("[id: "+this.id+
                      "] PMCategoryObj.addPlacemark(new_placemark.id: "+
		      new_placemark.id+")");
  if (!this.div) this.appendDiv();
  this.placemarks[this.placemarks.length] = new_placemark;
  if (this.active) new_placemark.show();
}

PMCategoryObj.prototype.catOnClickHandler = function () {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.catOnClickHandler()");
  if (this.ckbox.checked) {
    for (ii=0;ii<omgeo_data_layer2category.length;ii++) {
      if (omgeo_data_layer2category[ii][1] == this.id) {
	    document.getElementById("checkbox_vector_"+omgeo_data_layer2category[ii][0]).checked = true;
        ui.changeLayer();
    	}
    }
    this.show(true);
  } else {
    this.hide();
  }
}

PMCategoryObj.prototype.show = function(doLoad) {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.show(doLoad: "+doLoad
                      +")");
  this.active = true;
  this.triggered = false;
  this.toggleCheckbox(true);
  if (!this.isFolder && this.parent_cat) {
    this.parent_cat.toggleCheckbox(true);
  }
  if (!this.div) this.appendDiv();
  if (this.icon_url != "") {
    if (doLoad) this.startRequest();
    if (!this.updated) {
      for (var i=0; i<this.placemarks.length; i++) {
        this.placemarks[i].show();
      }
    }
    this.div.style.visibility = "visible";
  }
  if (this.child_cats.length > 0) {
    for (var i=0; i<this.child_cats.length; i++) {
      this.child_cats[i].show(false);
    }
  }

  this.funToolTrigger();
}

PMCategoryObj.prototype.hide = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.hide()");
  this.active = false;
  this.triggered = false;
  this.toggleCheckbox(false);
  if (!this.isFolder && this.parent_cat) {
    this.parent_cat.toggleCheckbox(false);
  }
  if (this.div) this.div.style.visibility = "hidden";
  if (this.child_cats.length > 0) {
    for (var i=0; i<this.child_cats.length; i++) {
      this.child_cats[i].hide();
    }
  }
}

PMCategoryObj.prototype.trigger = function(categories, force) {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.trigger(categories: ["+
                      categories.join(",")+"], force: "+force);
  var flag = force;
  if (!flag) {
    for (var i=0; i<categories.length; i++) {
      if (this.id == categories[i]) {
        var flag = true;
	categories = categories.slice(0,i).concat(categories.slice(i+1));
	break;
      }
    }
  }
  
  if (flag) {
    this.triggered = (this.active) ? this.triggered : true;
    this.active = true;
    if (!this.div) {
      this.appendDiv();
    } else {
      this.div.style.visibility="visible";
    } 
    this.toggleCheckbox(true);
    if (!this.isFolder && this.parent_cat) {
      this.parent_cat.toggleCheckbox(true);
    }
  }
  
  for (var i=0; i<this.child_cats.length && (flag||categories.length>0); i++) {
    categories = this.child_cats[i].trigger(categories, flag);
    this.triggered = false;
  }

  return categories;
}

PMCategoryObj.prototype.untrigger = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.untrigger()"); 
  if (this.triggered) this.hide();
  
  for (var i=0; i<this.child_cats.length; i++)
    this.child_cats[i].untrigger();
}

PMCategoryObj.prototype.toggleCheckbox = function(value) {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.toggleCheckbox(value: "+
                      value+")");
  var doCheck = value;
  if (!value && this.isFolder) {
    for (var i=0; i<this.child_cats.length; i++) {
      if (this.child_cats[i].active) {
        doCheck = true;
        break;
      }
    }
  }
  if (this.ckbox) {
    this.ckbox.checked = doCheck;
  }

}

PMCategoryObj.prototype.getCategoryById = function(search_id) {
  ui.printMessage("[id: "+this.id+
                      "] PMCategoryObj.getCategoryById(search_id: "+
		      search_id+")");
  if (this.id == search_id) {
    return this;
  } else {
    if (this.child_cats.length > 0) {
      for (var i = 0; i < this.child_cats.length; i++) {
        var response = this.child_cats[i].getCategoryById(search_id);
        if (response) {
          break;
        }
      }
      return response;
    } else {
      return false;
    }
  }
}

PMCategoryObj.prototype.getPlacemarkById = function(search_id) {
  ui.printMessage("[id: "+this.id+
                      "] PMCategoryObj.getPlacemarkById(search_id: "+
		      search_id+")");
  var response = false;
  for (var i=0; i<this.placemarks.length; i++) {
    if (this.placemarks[i].id == search_id) {
      response = this.placemarks[i];
      break;
    }
  }

  if (!response) {
    for (i=0; i<this.child_cats.length; i++) {
      response = this.child_cats[i].getPlacemarkById(search_id);
      if (response) {
        break;
      }
    }
  }
  
  return response;
}

PMCategoryObj.prototype.startRequest = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.startRequest()");
  var categories = this.getChildrenToUpdate();
  if (categories.length > 0 && ui.active_tile_set.status != "prepared" &&
      ui.active_tile_set.status != "requiring")
    this.inter.newRequest(new GetPlacemarksRequestObj(ui.active_tile_set,
                          ui.active_tile_set.getTiles(), categories));
}

PMCategoryObj.prototype.getChildrenToUpdate = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.getChildrenToUpdate()");
  var categories = new Array();
  if (!this.isFolder && !this.updated) {
    categories[0] = this.id;
    this.updated = true;
  }
  for (var i=0; i<this.child_cats.length; i++) {
    categories = categories.concat(this.child_cats[i].getChildrenToUpdate());
  }
  return categories;
}

PMCategoryObj.prototype.getActiveCategories = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.getActiveCategories()");
  var categories = new Array();
  if (this.active) {
    categories[0] = this.id;
    this.updated = true;
  } else {
    this.updated = false;
  }
  for (var i=0; i<this.child_cats.length; i++) {
     categories = categories.concat(this.child_cats[i].getActiveCategories());
  }
  return categories;
}

PMCategoryObj.prototype.removePlacemarks = function() {
  ui.printMessage("[id: "+this.id+"] PMCategoryObj.removePlacemarks()");
  for (var i=0; i<this.placemarks.length; i++) {
    this.placemarks[i].destroy();
    delete this.placemarks[i];
  }
  this.placemarks.length = 0;
  for (i=0; i<this.child_cats.length; i++) {
    this.child_cats[i].removePlacemarks();
  }
  if (this.div) {
    if (this.div.parentNode) this.div.parentNode.removeChild(this.div);
    delete this.div;
  }
  this.updated = false;
}

PMCategoryObj.prototype.funToolTrigger = function(exceptions, bubbleUp) {
  if (!exceptions) {
    var found = false;
    for (var i = 0; i < omgeo_placemark_triggers.length; i++) {
      if (omgeo_placemark_triggers[i].catid &&
          omgeo_placemark_triggers[i].catid == this.id) {
	if (omgeo_placemark_triggers[i].deactivate) {
	  exceptions = new Array();
	  for (var j=0; j<omgeo_placemark_triggers[i].except.length; j++) {
            exceptions[exceptions.length] = omgeo_placemark_triggers[i].except[j];
	  }
          if (this.parent_cat) {
	    this.parent_cat.funToolTrigger(exceptions, true);
	    return;
	  }
	  found = true;
	  break;
	} else {
	  return;
	}
      }
    }
    if (!found) return;
  } else if (bubbleUp && this.parent_cat) {
    this.parent_cat.funToolTrigger(exceptions, true);
    return;
  }
  
  var deactivate = true;
  for (var i=0; i < exceptions.length; i++) {
    if (this.id == exceptions[i]) {
      deactivate = false;
      break;
    }
  }
  if (deactivate) {
    if (this.child_cats.length > 0 ) {
      for (var i=0; i < this.child_cats.length; i++) {
        this.child_cats[i].funToolTrigger(exceptions, false);
      }
    } else {
      this.hide();
    }
  }
}

function BubbleObj(init_map_frame, init_placemark, init_content) {
  ui.printMessage("new BubbleObj(init_map_frame.name: "+init_map_frame.name
                      +", init_placemark.id: "+init_placemark.id+
		      ", init_content)");
  this.placemark = init_placemark;
  this.map_frame = init_map_frame;
  this.map_div = init_placemark.tile_set.div;
  this.padding = omgeo_bubble_padding;
  this.frame_height = init_placemark.tile_set.height;
  this.frame_width = init_placemark.tile_set.width;

  this.bubble_div = this.map_frame.document.createElement("div");
  this.bubble_div.id = "bubble_frame";
  this.bubble_div.name = "bubble_frame";
  this.bubble_div.className = "bubble_frame";
  
  this.bubble_div.style.borderColor = omgeo_color_border;

  this.bubble_div.innerHTML = init_content;
  this.bubble_div.style.visibility = "hidden";
  
  this.bubble_div.onmouseout = this.getOnMouseOutHandler();
  this.bubble_div.onmousedown = this.getOnMouseButtonHandler();
  this.bubble_div.onmouseup = this.getOnMouseButtonHandler();
  this.map_frame.document.body.appendChild(this.bubble_div);
  
  this.frame_width = this.bubble_div.offsetWidth;
  this.frame_height = this.bubble_div.offsetHeight;
  ui.printMessage("bubble dimension: "+this.frame_width+"x"+this.frame_height);
  
  var anchor = this.placemark.getBubbleAnchor(this.frame_width, this.frame_height);
  this.bubble_div.style.position = "absolute";
  this.bubble_div.style.top = anchor.top+"px";
  this.bubble_div.style.left = anchor.left+"px";
  this.bubble_div.style.visibility = "visible";
}

BubbleObj.prototype.destroy = function() {
  ui.printMessage("BubbleObj.destroy()");
  this.bubble_div.style.visibility = "hidden";
  this.bubble_div.parentNode.removeChild(this.bubble_div);
  delete this.bubble_div;
}

BubbleObj.prototype.getOnMouseOutHandler = function() {
  var frame = this.map_frame;
  var placemark = this.placemark;
  var div = this.bubble_div;
  return function (ev) {
    ui.printMessage("bubble.onmouseout")
    if (!ev) {
      ev = frame.event;
    }
    if (ev.target) {
      var target = ev.target;
    } else {
      var target = ev.srcElement;
    }
    var related_target = (ev.relatedTarget) ? ev.relatedTarget : ev.toElement;
    while (related_target && related_target != div &&
           related_target != placemark.img && related_target.nodeName != "BODY"
	   && related_target.parentNode) {
      related_target = related_target.parentNode;
    }
    if (related_target) ui.printMessage(related_target.nodeName);
    if (related_target != div && related_target != placemark.img) {
      placemark.hideBubble();
    }
    return false;
  }
}

BubbleObj.prototype.getOnMouseButtonHandler = function() {
  var frame = this.map_frame;
  return function (ev) {
    if (!ev) {
      ev = frame.event;
    }
    var target = (ev.target) ? ev.target : ev.srcElement;
    ui.printMessage("bubble_div.onmousedown/up: target: "+target.nodeName);
    if (target.nodeName != "A") {
      ev.cancelBubble = true;
      if (ev.stopPropagation) ev.stopPropagation();
    }
    return false;
  }
}

function CircleObj(init_x, init_y, init_doc, init_div) {
  ui.printMessage("new CircleObj(x: "+init_x+", y: "+init_y+", init_div)");
  this.x = init_x;
  this.y = init_y;
  this.div = init_div;
  
  this.visible = true;
  this.circle = init_doc.createElement("img");
  this.circle.src = "images/redcircle_cross.gif";
  this.circle.style.position = "absolute";
  this.circle.style.zIndex = "3";
  
  this.show();
  this.div.appendChild(this.circle);
}

CircleObj.prototype.destroy = function() {
  ui.printMessage("CircleObj.destroy()");
  this.visible = false;
  this.div.removeChild(this.circle);
  delete this.circle;
}

CircleObj.prototype.reset = function(new_x, new_y) {
  ui.printMessage("CircleObj.reset(new_x: "+new_x+", new_y: "+new_y+")");
  this.hide();
  this.x = new_x;
  this.y = new_y;
  this.show();
}

CircleObj.prototype.show = function() {
  ui.printMessage("CircleObj.show()");
  this.circle.style.top = String(this.y-20)+"px";
  this.circle.style.left = String(this.x-20)+"px";
  this.circle.style.visibility = "visible";
  this.visible = true;
}

CircleObj.prototype.hide = function() {
  ui.printMessage("CircleObj_hide()");
  this.circle.style.visibility = "hidden";
  this.visible = false;
}

function QueryToolObj() {
  this.query = null;

  var query_tool = this;
  
  this.result_frame = window.result_frame;
  this.result_frame_element = document.getElementById("result_frame");
  
  this.result_frame_table = document.getElementById("result_frame_table");
  
  this.result_img_show = document.getElementById("result_img_show");
  this.result_img_show.onclick = function(ev) {query_tool.showResultFrame()};
  
  this.result_img_hide = document.getElementById("result_img_hide");
  this.result_img_hide.onclick = function(ev) {query_tool.hideResultFrame()};
  
  this.result_message = document.getElementById("result_message").firstChild;
  this.result_message_tr = document.getElementById("result_message_tr");
  
  this.input_addr = document.getElementById("addr");
  this.input_loc = document.getElementById("plz_ort");
}

QueryToolObj.prototype.checkValidQuery = function(addr, loc) {
  var count = 0;
  for (var i=0; i<addr.length; i++) {
    if (addr[i] != " " && addr[i] != "*" && addr[i] != ".") count++;
  }
  if (count < 3) {
    count = 0;
    for (var i=0; i<loc.length; i++) {
      if (loc[i] != " " && loc[i] != "*" && loc[i] != ".") count++;
    }
  }
  return (count >= 3) ? true : false;
}

QueryToolObj.prototype.startQuery = function() {
  ui.printMessage("QueryToolObj.startQuery()");
  var addr = this.input_addr.value;
  var loc = this.input_loc.value;
  if (this.checkValidQuery(addr, loc)) {
    this.query = new QueryObj(this, ui.inter, ui.active_tile_set, addr, loc,
			      this.query);
    this.showResultMessage("Suche ...");
  } else {
    alert("Bitte in einem Eingabefeld mindestens 3 Buchstaben angeben!");
  }
}

QueryToolObj.prototype.loadResultFrame = function(qid) {
  ui.printMessage("QueryToolObj.loadResultFrame()")
  this.result_frame_element.src = "bin/result_frame.phpcgi?qid="+qid;
}

QueryToolObj.prototype.resultFrameOnLoadHandler = function() {
  ui.printMessage("QueryToolObj.resultFrameOnLoadHandler")
  this.result_frame_table.style.display="block";
  this.result_frame_element.style.display = "block";
  this.result_frame_element.height = 120;
  var height = (this.result_frame.document.body.scrollHeight) ?
		this.result_frame.document.body.scrollHeight : 120;
  height = Math.min(height, 120);
  if (height > 0) {
    this.query.assignEvents();
    this.result_frame_element.height = height;
    this.result_message.nodeValue = "Wählen Sie aus:";
    this.result_img_show.style.display = "none";
    this.result_img_hide.style.display = "block";
    this.query.highlightSelection();
  } else {
    this.result_frame_table.style.display = "none";
    this.result_frame_element.style.display = "none";
  }
  return true;
}

QueryToolObj.prototype.showResultMessage = function(message) {
  this.result_message.nodeValue = message;
  this.result_img_show.style.display = "none";
  this.result_img_hide.style.display = "none";
  this.result_frame_table.style.display = "none";
  this.result_frame_element.style.display = "none";
  this.result_message_tr.style.display = "block";
}

QueryToolObj.prototype.showResultFrame = function() {
  this.result_frame_table.style.display = "block";
  this.result_frame_element.style.display = "block";
  this.result_img_hide.style.display = "block";
  this.result_img_show.style.display = "none";
  this.result_message.nodeValue = "Wählen Sie aus:";
}

QueryToolObj.prototype.hideResultFrame = function() {
  this.result_frame_table.style.display = "none";
  this.result_frame_element.style.display = "none";
  this.result_img_hide.style.display = "none";
  this.result_img_show.style.display = "block";
  this.result_message.nodeValue = "Suchergebnis anzeigen";
}

function QueryObj(init_query_tool, init_inter, init_tile_set, init_addr,
                  init_loc, prev_query) {
  ui.printMessage("new QueryObj(init_query_tool, init_inter, "+
                  "init_tile_set.status:"+init_tile_set.status+", init_addr: "+
		  init_addr+", init_loc: "+init_loc+")");
  this.addr = init_addr;
  this.loc = init_loc;
  this.query_tool = init_query_tool;
  this.inter = init_inter;
  this.tile_set = init_tile_set;

  this.id = 0;
  this.results = new Array();

  this.stop = true;

  this.selected = null;

  if (prev_query && prev_query.selected) {
    this.inter.newRequest(new QueryRequestObj(this, this.addr, this.loc,
      this.tile_set.getCenterXMap(), this.tile_set.getCenterYMap(),
      prev_query.id, prev_query.selected.id));
  } else {
    this.inter.newRequest(new QueryRequestObj(this, this.addr, this.loc,
      this.tile_set.getCenterXMap(), this.tile_set.getCenterYMap()));
  }
}

QueryObj.prototype.destroy = function() {
  for (var i=0; i<this.results.length; i++) {
    this.results[i].destroy;
    delete this.results[i];
  }
  delete this.results;
}

QueryObj.prototype.init = function(init_id, init_results, message, isValid) {
  ui.printMessage("[id: "+init_id+"] QueryObj.init(init_id: "+init_id+
                      ", init_results.length: "+init_results.length+
		      ", message: "+message+")");
  this.id = init_id;
  if (init_results.length > 0) {
    for (var i=0; i<init_results.length; i++) {
      if (init_results[i].pmid && ui.root) {
        new_result = new ResultObj(init_results[i].id, init_results[i].x, 
	  init_results[i].y, init_results[i].pmid, init_results[i].catid);
      } else {
        new_result = new ResultObj(init_results[i].id, init_results[i].x,
	  init_results[i].y, null);
      }
      this.results[this.results.length] = new_result;
    }
    this.query_tool.loadResultFrame(this.id);
  } else {
    this.query_tool.showResultMessage(message);
  }
  if (isValid) {
    this.stop = false;
    if (init_results.length == 1) {
      var result = this.results[0];
      this.select(result);
      ui.goToScale(result.x, result.y, omgeo_query_result_scale);
      this.showCircle();
      result.showCategory();
    }
  } else {
    this.stop = true;
    if (this.tile_set.status != "prepared" &&
        this.tile_set.status != "requiring")
      this.updateAll(this.tile_set);
  }
  ui.printMessage("results.length: "+this.results.length);
}

QueryObj.prototype.assignEvents = function() {
  ui.printMessage("[id: "+this.id+"] QueryObj.assignEvents()");
  ui.printMessage("results.length: "+this.results.length);
  var query = this;
  for (var i=0; i<this.results.length; i++) {
    this.results[i].assignEvent(this);
  }
}

QueryObj.prototype.updateAll = function(new_tile_set) {
  ui.printMessage("[id: "+this.id+"] QueryObj.updateAll(new_tile_set.id:"+
                      new_tile_set.id+")");
  this.stop = true;
  this.inter.newRequest(new UpdateResultsRequestObj(this, new_tile_set.id));
  this.tile_set = new_tile_set;
}

QueryObj.prototype.updateResult = function(result_id, new_x, new_y) {
  ui.printMessage("[id: "+this.id+"] QueryObj.updateResult(result_id: "+
                      result_id+", new_x: "+new_x+", new_y: "+new_y+")");
  for (var i=0; i<this.results.length; i++) {
    if (this.results[i].id == result_id) {
      this.results[i].update(new_x, new_y);
      break;
    }
  }
}

QueryObj.prototype.goToResult = function(result) {
  ui.printMessage("[id: "+this.id+"] QueryObj.goToResult(result.id: "+result.id
                  +")");
  if (!this.stop) {
    this.select(result);
    ui.goToScale(result.x, result.y, omgeo_query_result_scale);
    this.showCircle();
    result.showCategory();
  }
}

QueryObj.prototype.select = function(result) {
  ui.printMessage("[id: "+this.id+"] QueryObj.select(result.id: "+result.id+
                      ")");
  this.unselect();
  
  this.selected = result;
  
  this.highlightSelection();
}

QueryObj.prototype.unselect = function() {
  ui.printMessage("[id: "+this.id+"] QueryObj.unselect()")
  if (this.selected) {
    var doc = this.query_tool.result_frame.document;
    var selected_result_td = doc.getElementById("rtd_"+this.selected.id);
    selected_result_td.style.border = "";
  } 
}

QueryObj.prototype.highlightSelection = function () {
  ui.printMessage("[id: "+this.id+"] QueryObj.highlightSelection()");

  if (this.selected) {
    var doc = this.query_tool.result_frame.document;
    ui.printMessage("selected.id: "+this.selected.id);
    var selected_result_td = doc.getElementById("rtd_"+this.selected.id);
    if (selected_result_td) selected_result_td.style.border = "1px solid red";
  }
}

QueryObj.prototype.showCircle = function () {
  ui.printMessage("[id: "+this.id+"] QueryObj.showCircle()");
  if (this.selected && ui.active_tile_set.status != "prepared" && 
      ui.active_tile_set.status != "requiring")
    ui.showCircle(this.selected.x, this.selected.y, ui.active_tile_set);
}

QueryObj.prototype.getResult = function(result_id) {
  for (var i=0; i<this.results.length; i++) {
    if (this.results[i].id == result_id) {
      return this.results[i];
    }
  }
  return null;
}

QueryObj.prototype.getResultXPosition = function(result_id) {
  for (var i=0; i<this.results.length; i++) {
    if (this.results[i].id == result_id) {
      var ret_x = this.results[i].x;
      break;
    }
  }
  if (!ret_x) var ret_x = false;
  return ret_x;
}

QueryObj.prototype.getResultYPosition = function(result_id) {
  for (var i=0; i<this.results.length; i++) {
    if (this.results[i].id == result_id) {
      var ret_y = this.results[i].y;
      break;
    }
  }
  if (!ret_y) var ret_y = false;
  return ret_y;
}

QueryObj.prototype.showCategory = function(result_id, doQueue) {
  for (var i=0; i<this.results.length; i++) {
    if (this.results[i].id == result_id) {
      this.results[i].showCategory(doQueue);
      break;
    }
  }
}

function ResultObj(init_id, init_x, init_y, init_pmid, init_catid) {
   this.id = init_id;
   this.x = init_x;
   this.y = init_y;
   if (init_pmid && init_catid) this.isPlacemark = true;
   this.pmid = init_pmid;
   this.catid = init_catid;
}

ResultObj.prototype.destroy = function() {
}

ResultObj.prototype.update = function(new_x, new_y) {
  this.x = new_x;
  this.y = new_y;
}

ResultObj.prototype.assignEvent = function (query) {
  var result = this;
  query.query_tool.result_frame.document.getElementById("ra_"+this.id).onclick =
    function () {query.goToResult(result); return false;};
}

ResultObj.prototype.showCategory = function() {
  if (this.isPlacemark) {
    var cat = ui.root.getCategoryById(this.catid);
    cat.untrigger();
    cat.show(true);
  }
}

function TileSetObj(init_prev_tile_set, init_inter, init_frame,
                    init_frame_width, init_frame_height, init_tolerance,
		    init_scale, init_layer) {
  ui.printMessage("new TileSetObj(init_prev_tile_set: "+init_prev_tile_set+
                    ", init_inter: "+init_inter+", init_frame"+
		    ", init_frame_width: "+init_frame_width+
		    ", init_frame_height:"+init_frame_height+
		    ", init_tolerance: "+init_tolerance+
		    ", init_scale: "+init_scale+", init_layer: "+init_layer+
		    ")");
  this.id = 0;
  this.prev_tile_set = init_prev_tile_set;
  this.inter = init_inter;
  this.frame = init_frame;
  this.frame_width = parseInt(init_frame_width);
  this.frame_height = parseInt(init_frame_height);
  this.tolerance = parseInt(init_tolerance);
  this.scale = parseInt(init_scale);
  this.layer = init_layer;
  
  this.succ_layer = init_layer;

  this.zIndex = (this.prev_tile_set) ? this.prev_tile_set.zIndex - 1 : 2;
  
  this.zoom_factor = 1;
  this.curr_zoom_factor = 1;
  this.base_zoom_factor = 1;

  this.destroyPrevTileSet = false;

  this.div = this.frame.document.createElement("div");
  this.div.className = "map_div";
  this.div.style.zIndex = String(this.zIndex);
  ui.map_div.appendChild(this.div);
  
  this.coords_mode_circle = null;
  
  this.status = "prepared";

  this.min_xpos = 0;
  this.min_ypos = 0;
  
  this.tile_rows = Math.ceil((this.frame_height + 2 * this.tolerance) /
    omgeo_max_tile_height);
  this.tile_cols = Math.ceil((this.frame_width + 2 * this.tolerance) /
    omgeo_max_tile_width);
  this.tile_width = Math.max(Math.ceil((this.frame_width + 2 * this.tolerance) /
    (2 * this.tile_cols)) * 2, omgeo_min_tile_width);
  this.tile_height = Math.max(Math.ceil((this.frame_height + 2 * this.tolerance)
    / (2 * this.tile_rows)) * 2, omgeo_min_tile_height);
  this.frame_top = Math.floor((this.tile_rows * this.tile_height -
    this.frame_height) / 2);
  this.frame_left = Math.floor((this.tile_cols * this.tile_width -
    this.frame_width) / 2);
  this.tiles = new Array(this.tile_rows);
  
  for (var i=0; i < this.tile_rows; i++) {
    this.tiles[i] = new Array(this.tile_cols);
    for (var j=0; j < this.tile_cols; j++) {
      this.tiles[i][j] = "empty!";
    }
  }
}

TileSetObj.prototype.destroy = function(preservePrevTileSet) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.destroy()");
  
  if (!preservePrevTileSet && this.prev_tile_set &&
      this.prev_tile_set.status != "destroyed") {
    this.prev_tile_set.destroy();
    delete this.prev_tile_set;
  }
  
 if (this.status == "zooming") window.clearInterval(this.zoom_interval);
  
  for (var i=0; i < this.tile_rows; i++) {
    for (var j=0; j < this.tile_cols; j++) {
      if (this.tiles[i][j] && this.tiles[i][j] != "empty!") {
        this.tiles[i][j].destroy();
        delete this.tiles[i][j];
      }
    }
  }
  
  if (this.coords_mode_circle) {
    this.coords_mode_circle.destroy();
    delete this.coords_mode_circle;
  }

  ui.map_div.removeChild(this.div);
  delete this.div;

  this.status = "destroyed";
}

TileSetObj.prototype.setTileDims = function() {
}

TileSetObj.prototype.move = function(delta_x, delta_y) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.move(delta_x: "+delta_x+", delta_y: "+
		      delta_y+")");
  if (this.prev_tile_set && this.prev_tile_set.status != "destroyed") {
    this.prev_tile_set.move(delta_x, delta_y);
  }

  var new_frame_top = this.frame_top + delta_y;
  var new_frame_left = this.frame_left + delta_x;
  if (this.pan_limits && this.pan_limits.north)
    var new_frame_top = Math.max(new_frame_top, this.pan_limits.north);
  if (this.pan_limits && this.pan_limits.south)
    var new_frame_top =
      Math.min(new_frame_top, this.pan_limits.south - this.frame_height);
  if (this.pan_limits && this.pan_limits.east)
    var new_frame_left =
      Math.min(new_frame_left, this.pan_limits.east - this.frame_width);
  if (this.pan_limits && this.pan_limits.west)
    var new_frame_left = Math.max(new_frame_left, this.pan_limits.west);
  
  this.frame_top = new_frame_top;
  this.frame_left = new_frame_left;
  
  if (this.status == "loading" || this.status == "active") {
    this.addTiles();
  }

  this.div.style.top = String(-this.frame_top)+"px";
  this.div.style.left = String(-this.frame_left)+"px";
}

TileSetObj.prototype.addTiles = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.addTiles()");

  neededAreaTop = Math.floor((this.frame_top - this.tolerance) /
                             this.tile_height) - this.min_ypos;

  if (neededAreaTop < 0) {
    for (var i = this.tile_rows - neededAreaTop - 1; i >= 0; i--) {
      if (i >= this.tile_rows) {
        this.tiles[i] = new Array(this.tile_cols);
      }
      if (i >= -neededAreaTop) {
        for (var j = 0; j < this.tile_cols; j++) {
          this.tiles[i][j] = this.tiles[i+neededAreaTop][j];
	}
      } else {
        for (j = 0; j < this.tile_cols; j++) {
	  this.tiles[i][j] = "empty!";
	}
      }
    }
    this.tile_rows -= neededAreaTop;

    this.min_ypos += neededAreaTop;
    neededAreaTop = 0;
  }
  
  neededAreaLeft = Math.floor((this.frame_left - this.tolerance) /
                              this.tile_width) - this.min_xpos;
  if (neededAreaLeft < 0) {
    for (var i = 0; i < this.tile_rows; i++) {
      for (var j = this.tile_cols - neededAreaLeft - 1; j >= 0; j--) {
        if (j >= -neededAreaLeft) {
          this.tiles[i][j] = this.tiles[i][j+neededAreaLeft];
	} else {
          this.tiles[i][j] = "empty!";
	}
      }
    }
    this.tile_cols -= neededAreaLeft; 

    this.min_xpos += neededAreaLeft;
    neededAreaLeft = 0;
  }
  
  neededAreaBottom = Math.ceil((this.frame_top + this.frame_height + 
                               this.tolerance) / this.tile_height) -
			       this.min_ypos;
  if (neededAreaBottom >=this.tile_rows) {
    for (var i = this.tile_rows; i <= neededAreaBottom; i++) {
      this.tiles[i] = new Array(this.tile_cols);
      for (var j = 0; j < this.tile_cols; j++) {
        this.tiles[i][j] = "empty!";
      }
    }
    this.tile_rows = neededAreaBottom+1;
  }
  
  neededAreaRight = Math.ceil((this.frame_left + this.frame_width +
                              this.tolerance) / this.tile_width)
			      - this.min_xpos;
  if (neededAreaRight >= this.tile_cols) {
    for (var i = 0; i < this.tile_rows; i++) {
      for (var j = this.tile_cols; j <= neededAreaRight; j++) {
        this.tiles[i][j] = "empty!";
      }
    }
    this.tile_cols = neededAreaRight+1;
  }
  
  this.initTiles(neededAreaLeft, neededAreaTop, neededAreaRight,
                 neededAreaBottom)
}

TileSetObj.prototype.frameResize = function(new_frame_width, new_frame_height) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.frameResize(new_frame_width: "+
		      new_frame_width+", new_frame_height: "+
		      new_frame_height+")");

  this.frame_width = new_frame_width;
  this.frame_height = new_frame_height;

  this.move(0,0);
}

TileSetObj.prototype.zoom = function(center_x, center_y, factor, interval, new_scale) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.zoom(center_x: "+center_x+", center_y :"+
		      center_y+", factor: "+factor+", interval: "+interval+
		      ", new_scale:"+new_scale+")");
  if (this.coords_mode_circle) this.coords_mode_circle.hide();
  
  ui.scalebar_div.style.visibility = "hidden";
  ui.copyright_div.style.visibility = "hidden";

  var last_ready = this.getLastReady();
  if (last_ready) {
    var new_center_x = last_ready.getXMap(center_x);
    var new_center_y = last_ready.getYMap(center_y);
		   
    var new_tile_set = new TileSetObj(this, this.inter, this.frame, 
				      this.frame_width, this.frame_height,
				      this.tolerance, new_scale,
				      this.succ_layer);
    if (ui.showCoords && this.coords_mode_lat && this.coords_mode_lon)
      new_tile_set.setLatLon(this.coords_mode_lat, this.coords_mode_lon);
    
    new_tile_set.start(last_ready.id, new_center_x, new_center_y, -1);
    
    if (factor < 1) new_tile_set.hide();
  }
  
  this.startZoom(new_tile_set, center_x, center_y, factor, interval);

  return new_tile_set;
}

TileSetObj.prototype.getZoomFunction = function(succ_tile_set, center_x, center_y,factor) {
  var tile_set = this;
  var start_time = new Date().getTime();
  var prev_center_x = Math.floor(this.frame_width / 2) + this.frame_left;
  var prev_center_y = Math.floor(this.frame_height / 2) + this.frame_top;
  var prev_tile_width = this.tile_width;
  var prev_tile_height = this.tile_height;
  var delta_x = center_x - Math.floor(this.frame_width / 2);
  var delta_y = center_y - Math.floor(this.frame_height / 2);
  var ln2 = Math.LN2;
  var Tzoom = Math.abs(Math.log(factor) / ln2 * omgeo_msec_to_double_size);
  /*var ax = delta_x / (omgeo_max_recenter_time*omgeo_max_recenter_time);
  var ay = delta_y / (omgeo_max_recenter_time*omgeo_max_recenter_time);*/
  var ax = 6 * delta_x / Math.pow(Math.min(omgeo_max_recenter_time, Tzoom), 3);
  var ay = 6 * delta_y / Math.pow(Math.min(omgeo_max_recenter_time, Tzoom), 3);
  var a = Math.sqrt (ax*ax+ay*ay);
  if (a < omgeo_min_recenter_deceleration) {
    ax = ax * omgeo_min_recenter_deceleration / a;
    ay = ay * omgeo_min_recenter_deceleration / a;
    a = omgeo_min_recenter_deceleration;
  }
  //var Tdist = Math.sqrt(Math.sqrt(delta_x*delta_x + delta_y*delta_y)/ a);
  var Tdist = Math.pow(6*Math.sqrt(delta_x*delta_x + delta_y*delta_y) / a, 1/3);
  if (this.prev_tile_set && this.prev_tile_set.status != "destroyed") {
    this.prevZoom = this.prev_tile_set.getZoomFunction(null, center_x,
      center_y, factor);
  } 
  ui.printMessage("factor: "+factor+", a: "+a+", Tzoom: "+Tzoom+", Tdist: "+
                      Tdist+", prev_center: "+prev_center_x+", "+prev_center_y+
		      ", delta_x: "+delta_x+", delta_y: "+delta_y);
  return function() {
    ui.printMessage("[status: "+tile_set.status+"] zoomFunction()");
    var t = new Date().getTime() - start_time;
    if (factor > 1) {
      var fzoom = Math.min(Math.exp(ln2*t/omgeo_msec_to_double_size), factor);
    } else {
      var fzoom = Math.max(Math.exp(-ln2*t/omgeo_msec_to_double_size), factor);
    }
    var tile_width = Math.floor(prev_tile_width * fzoom);
    var tile_height = Math.floor(prev_tile_height * fzoom);
    /*var dx = (t <= Tdist) ? (delta_x - ax*(t - Tdist)*(t - Tdist)) :
                            delta_x;
    var dy = (t <= Tdist) ? (delta_y - ay*(t - Tdist)*(t - Tdist)) :
                            delta_y;*/
    var dx = (t <= Tdist) ? ax * t*t * (Tdist/2 - t/3) : delta_x;
    var dy = (t <= Tdist) ? ay * t*t * (Tdist/2 - t/3) : delta_y;
    ui.printMessage("dx, dy: "+dx+", "+dy);
    var new_center_x = Math.floor((prev_center_x + dx) * fzoom);
    var new_center_y = Math.floor((prev_center_y + dy) * fzoom);
    tile_set.zoomStep(fzoom, new_center_x, new_center_y, tile_width,
                      tile_height);
    if (tile_set.prev_tile_set && tile_set.prev_tile_set.status != "destroyed")
      tile_set.prevZoom();
    if (t >= Tzoom && t >= Tdist) {
      if (succ_tile_set) succ_tile_set.toForeground();
      tile_set.stopZoom();
    }
  }
}

TileSetObj.prototype.startZoom = function(new_tile_set, center_x, center_y, factor, interval) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.startZoom("+
                      "center_x: "+center_x+", center_y: "+center_y+
		      ", factor: "+factor+", interval: "+interval+")");
  if (this.status == "zooming") {
    factor = factor * this.zoom_factor / this.curr_zoom_factor;
    this.zoom_factor = factor * this.zoom_factor;
    this.base_zoom_factor = this.curr_zoom_factor;
    window.clearInterval(this.zoom_interval);
  } else {
    this.status = "zooming";
    this.base_zoom_factor = this.zoom_factor;
    this.zoom_factor = factor * this.zoom_factor;
  }
 
  try {
    this.zoom_interval =
      window.setInterval(
	this.getZoomFunction(new_tile_set, center_x, center_y, factor),
	interval);
  } catch (e) {
    ui.printMessage(e.toString());
  }
}

TileSetObj.prototype.zoomStep = function(f, new_center_x, new_center_y, new_tile_width, 
                             new_tile_height) {
  ui.printMessage("TileSetObj_zoomStep(f: "+f+", new_center_x: "+
                      new_center_x+", new_center_y: "+new_center_y+
		      ", new_tile_width: "+new_tile_width+", new_tile_height: "
		      +new_tile_height+")");
  this.curr_zoom_factor = this.base_zoom_factor * f;
		      
  this.frame_top = new_center_y - Math.floor(this.frame_height / 2);
  this.frame_left = new_center_x - Math.floor(this.frame_width / 2);
  this.tile_width = new_tile_width;
  this.tile_height = new_tile_height;
  
  this.div.style.top = String(-this.frame_top)+"px";
  this.div.style.left = String(-this.frame_left)+"px";
  
  for (var i=0; i < this.tile_rows; i++) {
    for (var j=0; j < this.tile_cols; j++) {
      if (this.tiles[i][j] != "empty!") {
	this.tiles[i][j].zoom((this.min_ypos + i) * this.tile_height,
	                      (this.min_xpos + j) * this.tile_width,
	                      this.tile_width, this.tile_height);
      }
    }
  }
}

TileSetObj.prototype.stopZoom = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.stopZoom()")
  try {
    window.clearInterval(this.zoom_interval);
  } catch (e) {
    ui.printMessage(e.toString());
  }
  this.toBackground();
  this.status = "inactive";
}

TileSetObj.prototype.changeLayer = function(new_layer) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.changeLayer(new_layer: "+new_layer+")");
  
  var last_ready = this.getLastReady();
  if (last_ready) {
    var center_x = last_ready.getXMap(Math.floor(this.frame_width/2));
    var center_y = last_ready.getYMap(Math.floor(this.frame_height/2));

    var new_tile_set = new TileSetObj(this, this.inter, this.frame, 
				      this.frame_width, this.frame_height,
				      this.tolerance, this.scale, new_layer);
    if (ui.showCoords && this.coords_mode_lat && this.coords_mode_lon)
      new_tile_set.setLatLon(this.coords_mode_lat, this.coords_mode_lon);
    
    new_tile_set.start(last_ready.id, center_x, center_y, -1);
    
    last_ready.succ_layer = new_layer;
    
    this.toBackground();
  
    this.status = "inactive";
  
    return new_tile_set;
  } else {
    alert("Bitte warten Sie, bis die Karte geladen wurde!");
    return this;
  }
  
  
}

TileSetObj.prototype.hide = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.hide()");
  if (this.div) this.div.style.display = "none";
}

TileSetObj.prototype.toBackground = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.toBackground()");
  if (this.prev_tile_set) this.prev_tile_set.toBackground();
  if (this.status != "destroyed") {
    this.zIndex--;
    this.div.style.zIndex = String(this.zIndex);
    ui.printMessage("z-index: "+this.zIndex+", "+this.div.style.zIndex);
  }
}

TileSetObj.prototype.toForeground = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.toForeground()");
  ui.printMessage("div.visibility: "+this.div.style.visibility);
  this.div.style.display = "block";
  this.zIndex = 2;
  this.div.style.zIndex = "2";
  if (this.destroyPrevTileSet && this.prev_tile_set.status !="destroyed") {
    ui.printMessage("destroy previous tile set");
    this.prev_tile_set.destroy();
    delete this.prev_tile_set;
    this.destroyPrevTileSet = false;
  }
}

TileSetObj.prototype.checkStatus = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.checkStatus()");
  if (this.status == "loading") {
    visible_tiles_minx = Math.floor(this.frame_left / this.tile_width)
                         - this.min_xpos;
    visible_tiles_maxx = Math.floor((this.frame_left + this.frame_width) /
                                     this.tile_width) - this.min_xpos;
    visible_tiles_miny = Math.floor(this.frame_top / this.tile_height)
                         - this.min_ypos;
    visible_tiles_maxy = Math.floor((this.frame_top + this.frame_height) /
                                     this.tile_height) - this.min_ypos;
    
    if (visible_tiles_maxy < this.tile_rows ||
        visible_tiles_maxx < this.tile_cols) {
      var flag = true;
      for (var i = visible_tiles_miny; i <= visible_tiles_maxy; i++) {
	for (var j = visible_tiles_minx; j <= visible_tiles_maxx; j++) {
	  if (this.tiles[i][j] == "empty!" ||
	      this.tiles[i][j].status != "complete") {
	    flag = false;
	    break;
	  }
	}
      }
    } else {
      var flag = false;
    }
    
    if (flag) {
      this.status = "active";
      if (this.prev_tile_set) {
        if(this.prev_tile_set.status == "inactive") {
	  var tile_set = this;
	  window.setTimeout(function() {tile_set.destroyPredecessor()},
	                    omgeo_predecessor_removal_delay);
	  this.destroyPrevTileSet = false;
	} else if (this.prev_tile_set.status == "zooming") {
          this.destroyPrevTileSet = true;
	}
      }
    }
  }
  
}

TileSetObj.prototype.destroyPredecessor = function() {
  if (this.prev_tile_set && this.prev_tile_set.status != "destroyed") {
    this.prev_tile_set.destroy();
    delete this.prev_tile_set;
  }
}

TileSetObj.prototype.firstStart = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.firstStart()");
  this.status = "requiring";
  var layer_str = this.layer;
  this.inter.newRequest(new NewTileSetRequestObj(this, this.tile_width,
                        this.tile_height, this.tile_rows, this.tile_cols,
			this.scale, layer_str, -1, -1, -1, -1));
}

TileSetObj.prototype.startFromInitPos = function(init_lat, init_lon, init_poi,
                                     init_circle_lat, init_circle_lon) {
  this.status="requiring";
  var layer_str = this.layer;
  if (init_poi && init_poi != -1) {
    this.inter.newRequest(new NewTileSetRequestObj(this, this.tile_width,
                          this.tile_height, this.tile_rows, this.tile_cols,
			  this.scale, layer_str, -1, -1, -1, init_lat,
			  init_lon, init_poi));
  } else if (init_circle_lat && init_circle_lon) {
    this.inter.newRequest(new NewTileSetRequestObj(this, this.tile_width,
                          this.tile_height, this.tile_rows, this.tile_cols,
                          this.scale, layer_str, -1, -1, -1, init_lat,
			  init_lon, -1, init_circle_lat, init_circle_lon));
  } else {
    this.inter.newRequest(new NewTileSetRequestObj(this, this.tile_width,
                          this.tile_height, this.tile_rows, this.tile_cols,
                          this.scale, layer_str, -1, -1, -1, init_lat,
			  init_lon));
  }
}

TileSetObj.prototype.start = function(tsid, center_x, center_y) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.start(tsid: "+tsid+", center_x: "+center_x+
		      ", center_y: "+center_y+")");
  this.status = "requiring";
  this.inter.newRequest(new NewTileSetRequestObj(this, this.tile_width, 
    this.tile_height, this.tile_rows, this.tile_cols, this.scale, this.layer,
    tsid, center_x, center_y));
}

TileSetObj.prototype.init = function(init_id, init_ref_lat, init_ref_lon, 
                         init_degperpix_x, init_degperpix_y, init_maps, 
			 init_scalebar_url, init_copyright_label,
			 init_pan_limits, init_poi_catid) {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.init(init_id: "+init_id+", init_ref_lon: "+
		      init_ref_lon+", init_ref_lat: "+init_ref_lat+
		      ", init_degperpix_x: "+init_degperpix_x+
		      ", init_degperpix_y: "+init_degperpix_y+
		      ", init_scalebar_url: "+init_scalebar_url+
		      ", init_copyright_label: "+init_copyright_label+
		      ", init_pan_limits: "+init_pan_limits+
		      ", init_poi_catid: "+init_poi_catid+")");
  this.status = "loading";
  this.id = init_id;
  this.ref_lat = parseFloat(init_ref_lat);
  this.ref_lon = parseFloat(init_ref_lon);
  this.degperpix_x = parseFloat(init_degperpix_x);
  this.degperpix_y = parseFloat(init_degperpix_y);
  this.scalebar_url = init_scalebar_url;
  this.copyright_label = init_copyright_label;
  this.pan_limits = init_pan_limits;

  this.div.style.top = String(-this.frame_top)+"px";
  this.div.style.left = String(-this.frame_left)+"px"; 
  
  var interlace = (this.prev_tile_set) ? false : true;
  for (var i=0; i<init_maps.length; i++) {
    var map = init_maps[i];
    this.tiles[map.ypos][map.xpos] =
      new TileObj(this, this.frame, this.div, map.ypos * this.tile_height, 
                  map.xpos * this.tile_width, this.frame_width, 
		  this.frame_height, this.tile_width, this.tile_height,
		  map.xpos, map.ypos);
    var retry = (map.retry) ? true : false;
    this.tiles[map.ypos][map.xpos].updateSrc(this.inter, map.id, map.src,
      interlace, retry);
  }
 
  this.resetLatLon();
  this.checkRetryStatus();
}

TileSetObj.prototype.checkRetryStatus = function() {
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.checkRetryStatus()");
  var tiles_array = new Array();
  for (var i=0; i<this.tile_rows; i++) {
    for (var j=0; j<this.tile_cols; j++) {
      if (this.tiles[i][j].retry_status) {
        this.tiles[i][j].retry_status = false;
        tiles_array[tiles_array.length] = this.tiles[i][j];
      }
    }
  }
  
  if (tiles_array.length > 0)
    this.inter.newRequest(new GetMapsRequestObj(this, tiles_array));
}

TileSetObj.prototype.initTiles = function(min_xindex, min_yindex, max_xindex, max_yindex) {
  function orderSort(a, b) {
    return b.pri - a.pri;
  }
  ui.printMessage("[status: "+this.status+
                      "] TileSetObj.initTiles(min_xindex: "+min_xindex+
		      ", min_yindex: "+min_yindex+", max_xindex: "+max_xindex+
		      ", max_yindex: "+max_yindex+")");
  ui.printMessage("tile_rows: "+this.tile_rows+", tile_cols: "+
                      this.tile_cols);
  var order = new Array();
  for (var i=min_yindex; i<=max_yindex; i++) {
    for (var j=min_xindex; j<=max_xindex; j++) {
      if (this.tiles[i][j] == "empty!") {
	this.tiles[i][j] = new TileObj(this, this.frame, this.div,
				       (this.min_ypos + i) * this.tile_height, 
				       (this.min_xpos + j) * this.tile_width,
				       this.frame_width, this.frame_height,
				       this.tile_width, this.tile_height,
				       j + this.min_xpos, i + this.min_ypos);

	order[order.length] = {x:j, y:i, pri:this.getPriority(i,j)};
      }
    }
  }
  if (order.length > 0) {
    order.sort(orderSort);
    
    var tiles_array = new Array();
    for (var k=0; k<order.length; k++) {
      xpos = order[k].x + this.min_xpos;
      ypos = order[k].y + this.min_ypos;
      
      tiles_array[tiles_array.length] = this.tiles[order[k].y][order[k].x];
      
    }
    
    this.inter.newRequest(new GetMapsRequestObj(this, tiles_array));
    
    ui.tileSetOnGetMapsHandler(this, tiles_array);
  }
}

TileSetObj.prototype.getPriority = function(yindex, xindex) {
  tile_top = yindex * this.tile_height;
  tile_left = xindex * this.tile_width;
  tile_bottom = tile_top + this.tile_height;
  tile_right = tile_left + this.tile_width;

  if (tile_top >= this.frame_top + this.frame_height + this.tolerance ||
      tile_left >= this.frame_left + this.frame_width + this.tolerance ||
      tile_bottom <= this.frame_top - this.tolerance ||
      tile_right <= this.frame_left - this.tolerance) {
    priority = 0;
  } else if (tile_top >= this.frame_top + this.frame_height ||
             tile_left >= this.frame_left + this.frame_width ||
	     tile_bottom <= this.frame_top ||
	     tile_right <= this.frame_left) {
    priority = 1;
  } else {
    priority = 2;
  }
  return priority;
}

TileSetObj.prototype.getTileByPos = function(xpos, ypos) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getTileByPos(xpos: "+
                      xpos+", ypos: "+ypos+")");
  return (this.tiles[ypos-this.min_ypos][xpos-this.min_xpos] == "empty!") ?
         null : this.tiles[ypos-this.min_ypos][xpos-this.min_xpos];
}

TileSetObj.prototype.getTiles = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getTiles()");
  var tiles_array = new Array()
  for (var i=0; i<this.tile_rows; i++) {
    for (var j=0; j<this.tile_cols; j++) {
      var tile = this.tiles[i][j];
      if (tile != "empty!" && tile.xpos > -1000 && tile.ypos > -1000) {
        tiles_array[tiles_array.length] = tile;
      }
    }
  }
  if (tiles_array.length > 0) {
    return tiles_array;
  } else {
    return null;
  }
}

TileSetObj.prototype.getLastReady = function() {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getLastReady()");
  ui.printMessage("id: "+this.id);
  if (this.id > 0) {
    return this;
  } else if (this.prev_tile_set) {
    return this.prev_tile_set.getLastReady();
  } else {
    return false;
  }
}

TileSetObj.prototype.getXScreen = function(x) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getXScreen(x: "+x+
                      ")");
  return x * this.curr_zoom_factor - this.frame_left;
}

TileSetObj.prototype.getYScreen = function(y) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getYScreen(y: "+y+
                      ")");
  return y * this.curr_zoom_factor - this.frame_top;
}

TileSetObj.prototype.getXMap = function(x) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getXMap(x: "+x+
                      ")");
  return Math.floor((x + this.frame_left) / this.curr_zoom_factor);
}

TileSetObj.prototype.getYMap = function(y) {
  ui.printMessage("[status: "+this.status+"] TileSetObj.getYMap(y: "+y+
                      ")");
  return Math.floor((y + this.frame_top) / this.curr_zoom_factor);
}

TileSetObj.prototype.getCenterXMap = function() {
  return Math.floor((this.frame_width / 2 + this.frame_left)
                    / this.curr_zoom_factor);
}

TileSetObj.prototype.getCenterYMap  = function() {
  return Math.floor((this.frame_height / 2 + this.frame_top)
                    / this.curr_zoom_factor);
}

TileSetObj.prototype.getLat = function(y) {
  return this.ref_lat - y*this.degperpix_y;
}

TileSetObj.prototype.getLon = function(x) {
  return this.ref_lon + x*this.degperpix_x;
}

TileSetObj.prototype.resetLatLon = function() {
  if (ui.showCoords && this.coords_mode_lat && this.coords_mode_lon) {
    var x = Math.floor((this.coords_mode_lon-this.ref_lon) / this.degperpix_x);
    var y = Math.floor((this.ref_lat-this.coords_mode_lat) / this.degperpix_y);
    this.showLatLon(x, y);
  }
}

TileSetObj.prototype.showLatLon = function(x, y) {
  if (!this.coords_mode_circle) {
    this.coords_mode_circle =
      new CircleObj(x, y, this.frame.document, this.div);
  } else {
    this.coords_mode_circle.reset(x, y);
  }
  
  this.coords_mode_lat = this.getLat(y);
  this.coords_mode_lon = this.getLon(x);
  
  if (ui.lat_td.firstChild) {
    ui.lat_td.firstChild.nodeValue = this.coords_mode_lat;
  } else {
    ui.lat_td.appendChild(document.createTextNode(this.coords_mode_lat));
  }
  if (ui.lon_td.firstChild) {
    ui.lon_td.firstChild.nodeValue = this.coords_mode_lon;
  } else {
    ui.lon_td.appendChild(document.createTextNode(this.coords_mode_lon));
  }
}

TileSetObj.prototype.setLatLon = function(lat, lon) {
  this.coords_mode_lat = lat;
  this.coords_mode_lon = lon;
}

TileSetObj.prototype.showCircle = function(x, y) {
  ui.printMessage("TileSetObj.showCircle(x: "+x+", y: "+y+")");
  if (this.circle) {
    this.circle.reset(x, y);
  } else {
    this.circle = new CircleObj(x, y, this.frame.document, this.div);
  }
}

TileSetObj.prototype.goTo = function(x, y) {
  this.move(this.getXScreen(x) - Math.floor(this.frame_width/2), 
            this.getYScreen(y) - Math.floor(this.frame_height/2));
}

TileSetObj.prototype.getPDFUrl = function(pdf_url) {
  var ret = pdf_url+"?tsid="+this.id+"&center_x="+this.getCenterXMap()+
            "&center_y="+this.getCenterYMap()+"&width="+this.frame_width+
	    "&height="+this.frame_height;
  ui.printMessage(ret);
  return ret;
}

TileSetObj.prototype.getURL = function() {
  var lat = this.ref_lat - this.getCenterYMap() * this.degperpix_y;
  var lon = this.ref_lon + this.getCenterXMap() * this.degperpix_x;
  var ret = "scale="+this.scale+"&layer="+this.layer+"&lat="+lat+"&lon="+lon;
  return ret;
}

function InterfaceObj(init_requestURL, init_session) {
  this.requestURL = init_requestURL;
  this.session = init_session;

  this.requests = new Array();
  this.request_id_sequence = 0;

  this.preloaders = new Array();
  this.preload_id_sequence = 0;
  this.top_priority = 0;
}

InterfaceObj.prototype.destroy = function() {
  ui.printMessage("InterfaceObj.destroy()");
  for (var i = 0; i < this.requests.length; i++) {
    this.requests[i].destroy();
    delete this.requests[i];
  }
  for (i = 0; i < this.preloaders.length; i++) {
    this.preloaders[i].destroy();
    delete this.preloaders[i];
  }
  delete requests;
  delete preloaders;
}

InterfaceObj.prototype.getReadyStateHandler = function(inter, request) {
  return function() {
    if (request.req.readyState == 4) {
      if (request.req.status == 200) {
        request.handle();
      } else {
        ui.printMessage("[id: "+request.id+"] HTTP Fehler:"+
	  request.req.statusText);
      }
      inter.terminateRequest(request.id);
    }
  }
}

InterfaceObj.prototype.newRequest = function(request) {
  ui.printMessage("InterfaceObj.newRequest(request.type: "+request.type+
                      ")");
  this.requests[this.requests.length] = request;
  request.req.onreadystatechange =
    this.getReadyStateHandler(this, request);
  request.start(this, this.request_id_sequence);
  this.request_id_sequence++;
  this.showStatus();
}

InterfaceObj.prototype.preload = function(tile, img, src, priority) {
  ui.printMessage("InterfaceObj.preload(tile.id: "+tile.id+", img, src: "+
                      src+", priority: "+
                      priority+")");
  preloader = new PreloaderObj(tile, img, src, priority);
  this.preloaders[this.preloaders.length] = preloader;
  
  if (priority >= this.top_priority) {
    this.top_priority = priority;
    this.preload_id_sequence++;
    preloader.start(this, this.preload_id_sequence);
  }
  
  return this.preload_id_sequence;
}

InterfaceObj.prototype.updatePriority = function(id, new_priority) {
  ui.printMessage("InterfaceObj.updatePriority(id: "+id+", new_priority:"+
                      new_priority+")");
  for (var i = 0; i < this.preloaders.length; i++) {
    if (this.preloaders[i].id == id) {
      preloader = this.preloaders[i];
      break;
    }
  }
  
  preloader.priority = new_priority;
  if (new_priority >= this.top_priority) {
    this.top_priority = new_priority;
    this.preload_id_sequence++;
    preloader.start(this, this.preload_id_sequence);
  }
}

InterfaceObj.prototype.terminatePreload = function(id) {
  ui.printMessage("InterfaceObj.terminatePreload(id: "+id+")");
  for (var i = 0; i < this.preloaders.length; i++) {
    if (this.preloaders[i].id == id) {
      this.preloaders[i].destroy();
      delete this.preloaders[i];
      this.preloaders[i] = null;
      for (var j = i+1; j < this.preloaders.length; j++) {
        this.preloaders[j-1] = this.preloaders[j];
      }
      this.preloaders.length--;
      break;
    }
  }

  new_top_priority = 0;
  for (i = 0; i < this.preloaders.length; i++) {
    if (this.preloaders[i].priority > new_top_priority) {
      new_top_priority = this.preloaders[i].priority;
    }
  }

  if (new_top_priority < this.top_priority) {
    this.top_priority = new_top_priority;
    for (i=0; i<this.preloaders.length; i++) {
      preloader = this.preloaders[i];
      if (preloader.priority == new_top_priority &&
          preloader.status == "prepared")  {
        this.preload_id_sequence++;
        preloader.start(this, this.preload_id_sequence)
      }
    }
  }
}

InterfaceObj.prototype.terminateAllPreloads = function() {
  ui.printMessage("InterfaceObj.terminateAllPreloads()");
  for (var i=0; i<this.preloaders.length; i++) {
    this.preloaders[i].destroy();
    delete this.preloaders[i];
  }
  this.preloaders.length = 0;
}

InterfaceObj.prototype.terminateRequest = function(id) {
  ui.printMessage("InterfaceObj.terminateRequest(id: "+id+")");
  for (var i = 0; i < this.requests.length; i++) {
    if (this.requests[i].id == id) {
      this.requests[i].destroy;
      delete this.requests[i];
      this.requests[i] = null;
      for (var j = i+1; j < this.requests.length; j++) {
        this.requests[j-1] = this.requests[j];
      }
      this.requests.length--;
      break;
    }
  }
  this.showStatus();
}

InterfaceObj.prototype.terminateAllRequests = function() {
  ui.printMessage("InterfaceObj.terminateAllRequests()");
  for (var i = 0; i < this.requests.length; i++) {
    this.requests[i].destroy();
    delete this.requests[i];
  }
  this.requests.length = 0;
  this.showStatus();
}

InterfaceObj.prototype.showStatus = function() {
  ui.printMessage("InterfaceObj.showStatus()");
  var request_priority = {"newtileset":1, "getmaps":2, "getpms":3,
    "getbubblecontent":4, "query":5, "updateresults":6};
  var doShow = false;
  var curr_priority = 7;
  var curr_type = "";
  for (var i=0; i < this.requests.length; i++) {
    if (request_priority[this.requests[i].type] < curr_priority) {
      curr_type = this.requests[i].type;
      curr_priority = request_priority[this.requests[i].type];
      doShow = true;
    }
  }
  ui.printMessage("type: "+curr_type+", curr_priority: "+curr_priority);
  if (doShow) {
    for (node = ui.status_div.firstChild; node != null; node = node.nextSibling) {
      if (node.nodeName == "DIV") {
        if (node.id == curr_type+"_div") {
	  node.style.display = "block";
	} else {
          node.style.display = "none";
	}
      }
    }
    ui.status_div.style.visibility = "visible";
  } else {
    ui.status_div.style.visibility = "hidden";
  }
}

function RequestObj() {
}

RequestObj.prototype.initRequest = function() {
  try {
    this.req = new XMLHttpRequest();
  } catch (error_1) {
    try {
      this.req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (error_2) {
      try {
        this.req = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (error_3) {
        this.req = null;
	alert("Problem mit dem Browser: \nXMLHTTPRequest nicht verfuegbar!");
      }
    }
  }
}

RequestObj.prototype.destroy = function() {
  this.req.onreadystatechange = function() {};
  this.req.abort();
  delete this.req;
}

RequestObj.prototype.start = function(init_inter, init_id) {
  ui.printMessage("[id: "+init_id+", type: "+this.type+"] RequestObj.start"+
                      "(init_inter, init_id: "+init_id+")");
  this.inter = init_inter;
  this.id = init_id;

  ui.printMessage(this.inter.requestURL+"?"+this.inter.session+"&action="+
                      this.type+"&"+this.params);
  this.req.open("GET", this.inter.requestURL+"?"+this.inter.session+"&action="+
                       this.type+"&"+this.params);
  this.req.send(null)
}

RequestObj.prototype.handle = function() {}

RequestObj.prototype.onErrorHandler = function(response) {
  alert("Fehler im Server aufgetreten!");
}

function NewTileSetRequestObj(init_target, init_tile_width, init_tile_height,
                              init_rows, init_cols, init_scale, init_layer,
			      init_tsid, init_center_x, init_center_y,
			      init_lat, init_lon, init_poi, init_circle_lat,
			      init_circle_lon) {
  ui.printMessage("new NewTileSetRequestObj(init_target: "+init_target+
                  ", init_tile_width"+init_tile_width+", init_tile_height"+
		  init_tile_height+", init_rows: "+init_rows+", init_cols: "+
		  init_cols+", init_scale"+init_scale+", init_layer: "+
		  init_layer+", init_tsid: "+init_tsid+", init_center_x: "+
		  init_center_x+", init_center_y"+init_center_y+", init_lat: "+
		  init_lat+", init_lon: "+init_lon+", init_poi: "+init_poi+
		  ", init_circle_lat: "+init_circle_lat+", init_circle_lon: "+
		  init_circle_lon+")");
  this.id = 0;
  this.type = "newtileset";
  this.target = init_target;
  this.inter = null;
  
  this.params = "tilewidth="+init_tile_width+"&tileheight="+init_tile_height+
                "&rows="+init_rows+"&cols="+init_cols+"&scale="+init_scale+
		"&layer="+init_layer;

  if (init_poi && init_poi > -1) {
    this.params += "&poi="+init_poi;
  } else if (init_lat && init_lon) {
    this.params += "&lat="+init_lat+"&lon="+init_lon;
    if (init_circle_lat && init_circle_lon)
      this.params += "&circle_lat="+init_circle_lat+"&circle_lon="+
		      init_circle_lon;
  } else if (init_tsid && init_tsid > -1) {
    this.params += "&tsid="+init_tsid+"&centerx="+init_center_x+
		   "&centery="+init_center_y;
  }
  
  this.initRequest();
}

NewTileSetRequestObj.prototype = new RequestObj();

NewTileSetRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] NewTileSetRequestObj.handle()");
  ui.printXML(this.req.responseText);
  try {
    var response = eval("("+this.req.responseText+")");
  } catch (e) {
    ui.printMessage(e.toString());
    return false;
  }
  
  if (response.errors) {
     this.onErrorHandler(response);
     return false;
  }
  
  ui.printMessage("response:"+response+", response.tileset: "+
		      response.tileset+", response.maps:"+response.maps);
  this.target.init(response.tileset.id, response.tileset.ref_lat,
		   response.tileset.ref_lon, response.tileset.degperpix_x,
		   response.tileset.degperpix_y, response.maps,
		   response.scalebar_url, response.copyright_label,
		   response.tileset.pan_limits, response.poi_catid);
  
  ui.tileSetOnLoadHandler(this.target, response);

  this.target.addTiles();
}

function GetMapsRequestObj(init_target, init_tiles) {
  ui.printMessage("new GetMapsRequestObj(init_target.status: "+
                      init_target.status+", init_tiles: "+init_tiles+")");
  this.id = 0;
  this.type = "getmaps";
  this.target = init_target;
  this.inter = null;

  var tiles_str = ""
  if (init_tiles) {
    var first = true;
    for (var i=0; i<init_tiles.length; i++) {
      if (!first) {
	tiles_str += ",";
      } else {
	first = false;
      }
      tiles_str += init_tiles[i].xpos+","+init_tiles[i].ypos;
    }
  }

  this.params = "tsid="+this.target.id+"&tiles="+tiles_str;
  
  this.initRequest();
}

GetMapsRequestObj.prototype = new RequestObj();

GetMapsRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] GetMapsRequestObj_handle()");
  ui.printXML(this.req.responseText);
  try {
    var maps = eval(this.req.responseText);
  } catch (e) {
    ui.printMessage(e.toString());
    return false;
  }
    
  if (maps.errors) {
     this.onErrorHandler(maps);
     return false;
  }
  
  for (var i=0; i<maps.length; i++) {
    var map = maps[i];
    var retry = (map.retry) ? true : false;
    this.target.getTileByPos(map.xpos, map.ypos).updateSrc(this.inter, map.id,
      map.src, true, retry);
  }
  this.target.checkRetryStatus();
}

function GetPlacemarksRequestObj (init_target, init_tiles, init_categories) {
  ui.printMessage("new GetPlacemarksRequestObj(init_target.status: "+
                      init_target.status+", init_tiles: "+init_tiles+
		      ", init_categories: "+init_categories+")");
  this.id = 0;
  this.type = "getpms";
  this.target = init_target;
  this.inter = null;

  var tiles_str = "";
  if (init_tiles) {
    var first = true;
    for (var i=0; i<init_tiles.length; i++) {
      if (!first) {
	tiles_str += ",";
      } else {
	first = false;
      }
      tiles_str += init_tiles[i].xpos+","+init_tiles[i].ypos;
    }
  }
  
  var cats_str = (typeof init_categories == "string") ? init_categories : 
                  init_categories.join(",");
  
  this.params = "tsid="+this.target.id+"&tiles="+tiles_str+"&cats="+cats_str;

  this.initRequest();
}

GetPlacemarksRequestObj.prototype = new RequestObj();

GetPlacemarksRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] GetPlacemarksRequestObj_handle()");
  ui.printXML(this.req.responseText);
  try {
    var cats = eval(this.req.responseText);
  } catch (e) {
    ui.printMessage(e.toString());
    return false;
  }
  
  if (cats.errors) {
    this.onErrorHandler(cats);
    return false;
  }
  
  for (var i=0; i<cats.length; i++) {
    var cat = ui.root.getCategoryById(cats[i].catid);
    for (var j=0; j<cats[i].placemarks.length; j++) {
      var placemark =
	new PlacemarkObj(cats[i].placemarks[j].id, cat, this.target,
			 cats[i].placemarks[j].x, cats[i].placemarks[j].y);
	cat.addPlacemark(placemark);
    }
  }
}

function GetBubbleContentRequestObj (init_target) {
  ui.printMessage("new GetBubbleContentRequestObj(init_target.id: "+
                      init_target.id+")");
  this.id = 0;
  this.type = "getbubblecontent";
  this.target = init_target;
  this.inter = null;

  this.params = "catid="+this.target.category.id+"&pmid="+this.target.id;

  this.initRequest();
}

GetBubbleContentRequestObj.prototype = new RequestObj();

GetBubbleContentRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] GetBubbleContentRequestObj_handle()");
  ui.printXML(this.req.responseText);

  this.target.initBubble(this.req.responseText);
}

function QueryRequestObj (init_target, init_addr, init_loc, init_center_x,
                          init_center_y, selected_qid, selected_resid) {
  ui.printMessage("new QueryRequestObj(init_target.id: "+
                      init_target.id+", init_addr: "+init_addr+", init_loc: "+
		      init_loc+", init_center_x: "+init_center_x+
		      ", init_center_y: "+init_center_y+", selected_qid: "+
		      selected_qid+", selected_resid: "+selected_resid+")");
  this.id = 0;
  this.type = "query";
  this.target = init_target;
  this.inter = null;

  var addr = encodeURIComponent(init_addr);
  var loc = encodeURIComponent(init_loc);

  this.params = "tsid="+this.target.tile_set.id+"&addr="+addr+"&loc="+loc+
                "&center_x="+init_center_x+"&center_y="+init_center_y;
  if (selected_qid && selected_resid)
    this.params += "&sel_qid="+selected_qid+"&sel_resid="+selected_resid;
		
  this.initRequest();
}

QueryRequestObj.prototype = new RequestObj();

QueryRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] QueryRequestObj_handle()");
  ui.printXML(this.req.responseText);
  try {
    var response = eval("("+this.req.responseText+")");
  } catch (e) {
    ui.printMessage(e.toString());
    return false;
  }
  
  if (response.errors) {
    this.onErrorHandler(response);
    return false;
  }
  
  this.target.init(response.id, response.results, response.message,
    response.isValid);
}

function UpdateResultsRequestObj (init_target, init_tsid) {
  ui.printMessage("new UpdateResultsRequestObj(init_target.id: "+
                      init_target.id+", init_tsid: "+init_tsid+")");
  this.id = 0;
  this.type = "updateresults";
  this.target = init_target;
  this.inter = null;

  this.params = "qid="+this.target.id+"&tsid="+init_tsid;

  this.initRequest();
}

UpdateResultsRequestObj.prototype = new RequestObj();

UpdateResultsRequestObj.prototype.handle = function() {
  ui.printMessage("[id: "+this.id+"] UpdateResultsRequestObj_handle()");
  ui.printXML(this.req.responseText);
  try {
    var response = eval("("+this.req.responseText+")");
  } catch (e) {
    ui.printMessage(e.toString());
    return false;
  }

  if (response.errors) {
    this.onErrorHandler(response);
    return false;
  }
  
  for (var i=0; i<response.results.length; i++) {
    this.target.updateResult(response.results[i].id, response.results[i].x,
                             response.results[i].y);
  }
  
  this.target.stop = false;
  this.target.showCircle();
}

function PreloaderObj(init_target, init_img, init_src, init_priority) {
  ui.printMessage("new PreloaderObj(init_target: "+init_target+
                      ", init_img, init_src: "+init_src+", init_priority: "+
		      init_priority); 
  this.target = init_target;
  this.src = init_src;
  this.priority = init_priority;

  this.id = 0;
  this.inter = null;

  this.img = init_img;

  this.status = "prepared";
}

PreloaderObj.prototype.destroy = function() {
}

PreloaderObj.prototype.start = function(init_inter, init_id) {
  ui.printMessage("[id: "+init_id+
                      "] PreloaderObj.start(init_inter, init_id:"+init_id+")");

  this.status = "loading";
  this.inter = init_inter;
  this.id = init_id;
  var preloader = this;
  this.img.onload = Image_onload = function () { preloader.onComplete() };
  this.img.src = this.src;
}

PreloaderObj.prototype.onComplete = function() {
  this.target.updateStatus();
  this.inter.terminatePreload(this.id);
  this.status = "finished";
}

function UserInterfaceObj() {
  this.div_width = omgeo_map_min_width;
  this.div_height = omgeo_map_min_height;

  this.panning = false;
  this.moved = false;
  this.panning_interval;

  this.reference_x = 0;
  this.reference_y = 0;
  this.mouse_x = -1;
  this.mouse_y = -1;
  this.button = "";

  this.nav_top = omgeo_nav_padding;
  this.nav_left = 0;
  this.nav_x = 0;
  this.nav_y = 0;
  this.nav_dx = 0;
  this.nav_dy = 0;
  this.nav_panning = false;
  this.nav_last_time = 0;

  this.scale = omgeo_def_scale;

  this.inter = null;

  this.active_tile_set = null;

  this.message_window = null;
  
  this.root = null;			   
  this.useSmallIcons = true;
  
  this.query_tool = new QueryToolObj();
  
  var ui = this;
  
  this.map_frame = window.map_frame;
  this.map_frame_element = document.getElementById("map_frame");
  
  this.outer_map_table = document.getElementById("outer_map_table");
  
  this.map_div = this.map_frame.document.getElementById("map_div");
  this.map_div.onmousedown = function(ev) {return ui.mapOnMouseDownHandler(ev)};
  this.map_div.onmouseup = function(ev) {return ui.mapOnMouseUpHandler(ev)};
  this.map_div.onmousemove = function(ev) {return ui.mapOnMouseMoveHandler(ev)};
  this.map_div.onmouseout = function(ev) {return ui.mapOnMouseOutHandler(ev)};
  this.map_div.oncontextmenu = function(ev) {return false;};
  
  this.nav_div = this.map_frame.document.getElementById("nav_div");
  this.nav_div.onmousedown = function(ev) {return ui.navOnMouseDownHandler(ev)};
  this.nav_div.onmouseup = function(ev) {return ui.navOnMouseUpHandler(ev)};
  this.nav_div.onmousemove = function(ev) {return ui.navOnMouseMoveHandler(ev)};
  this.nav_div.onmouseout = function(ev) {return ui.navOnMouseOutHandler(ev)};

  this.scalebar_div = this.map_frame.document.getElementById("scalebar_div");
  this.scalebar_img = this.map_frame.document.getElementById("scalebar_img");
  this.copyright_div = this.map_frame.document.getElementById("copyright_div");
  this.status_div = this.map_frame.document.getElementById("status_div");

  if (omgeo_isCoordsMode) {
    this.checkbox_mode = document.getElementById("checkbox_mode");
    this.checkbox_mode.onclick = function(ev) {ui.toggleCoordsMode()};
    
    this.lat_td = document.getElementById("Lat_td");
    this.lon_td = document.getElementById("Lon_td");
  }
 
  window.onresize = function() {ui.windowResize()};
  
  if (debug) {
    this.message_window = window.open("_blank", "message_window");
  }
}

UserInterfaceObj.prototype.start = function() {
  this.inter = new InterfaceObj(omgeo_interface_url, omgeo_session);
  this.windowResize();
  this.startTileSet();
  if (omgeo_category_data) this.createCategories();
}

UserInterfaceObj.prototype.startTileSet = function() {

  if (req_layer != "") {
    var layer = req_layer;
    var radio = document.getElementById("radio_"+layer);
    if (radio) radio.checked = true;
  } else {
    layer = "default";
  }
  
  if (req_scale != "") {
    this.toggleZoombar(this.scale, parseInt(req_scale));
    this.scale = parseInt(req_scale);
  }
  
  if (useInitPos) {
    if (req_poi != "" && req_scale == "") {
      this.toggleZoombar(this.scale, parseInt(omgeo_poi_def_scale));
      this.scale = parseInt(omgeo_poi_def_scale);
    }
    this.active_tile_set =
      new TileSetObj(null, this.inter, window.map_frame, this.div_width,
                     this.div_height, omgeo_tolerance, this.scale, layer);
	
    if (req_poi != "") {
      this.active_tile_set.startFromInitPos(-1000, -1000, req_poi);
    } else {
      if (req_circle_lat != "" && req_circle_lon != "") {
	this.active_tile_set.startFromInitPos(req_lat, req_lon, -1,
	  req_circle_lat, req_circle_lon);
      } else {
	this.active_tile_set.startFromInitPos(req_lat, req_lon);
      }
    }
  } else {
    this.active_tile_set = new TileSetObj(null, this.inter, window.map_frame,
       this.div_width, this.div_height, omgeo_tolerance, this.scale, "default");
    this.active_tile_set.firstStart();
  }
}

UserInterfaceObj.prototype.createCategories = function () {

  var activate = false;
  for (var j=0; j<req_cats.length; j++) {
    if (req_cats[j] == 0) {
      activate = true;
      break;
    }
  }

  this.root = new PMCategoryObj(omgeo_category_data.id,
                                omgeo_category_data.name,
				omgeo_category_data.icon_url, null, 0, false,
				this.inter, activate);

  this.root.createChildCategories(omgeo_category_data.children, req_cats);
}

UserInterfaceObj.prototype.printMessage = function(message) {
  if (debug && this.message_window) {
    var now = new Date();
    var timeString = now.toGMTString();
    var ms = now.getMilliseconds();
    if (ms < 10) {
      var msString = "00"+ms;
    } else if (ms < 100) {
      var msString = "0"+ms;
    } else {
      var msString = ms;
    }
    var timeString = timeString.substring(0,timeString.indexOf("GMT")-1)+"."+
                     msString+timeString.substring(timeString.indexOf("GMT")-1,
		                               timeString.length);
    this.message_window.document.write("<p style=\"font-family:Arial,"+
                                       "sans-serif;font-size:8pt\">");
    this.message_window.document.write("[ "+timeString+" ] "+message);
    this.message_window.document.writeln("</p>");
  }
}

UserInterfaceObj.prototype.printXML = function(response) {
  if (debug) {
    var processed_response = response.replace(/</g, "&lt;");
    processed_response = processed_response.replace(/>/g, "&gt;");
    var message = "XML Response\n <pre style=\"font-family:Arial,sans-serif;"+
                  "font-size:8pt\">\n"+processed_response+"</pre>";
    this.printMessage(message);
  }
}

UserInterfaceObj.prototype.getWindowWidth = function(target) {
  this.printMessage("getWindowWidth(target.name: "+target.name+")");
  if (target.innerWidth) {
    return target.innerWidth;
  } else if (target.document.documentElement &&
             target.document.documentElement.clientWidth) {
    return target.document.documentElement.clientWidth;
  } else if (target.document.body && target.document.body.clientWidth) {
    return target.document.body.clientWidth;
  }
}

UserInterfaceObj.prototype.getWindowHeight = function(target) {
  this.printMessage("getWindowHeight(target.name: "+target.name+")");
  if (target.innerHeight) {
    return target.innerHeight;
  } else if (target.document.documentElement &&
	     target.document.documentElement.clientHeight) {
    return target.document.documentElement.clientHeight;
  } else if (target.document.body && target.document.body.clientHeight) {
    return target.document.body.clientHeight;
  }
}

UserInterfaceObj.prototype.resizeFrame = function() {
  this.printMessage("resizeFrame()");
  this.map_frame_element.width = ui.div_width;
  this.map_frame_element.height = ui.div_height;
}

UserInterfaceObj.prototype.windowResize = function() {
  this.printMessage("windowResize()");

  var window_width = this.getWindowWidth(top);
  var window_height = this.getWindowHeight(top);
  this.printMessage("window_width: "+window_width+", window_height: "+
		      window_height);
  
  this.div_width = (window_width > omgeo_map_min_width + 
                    omgeo_inner_hor_spacing + omgeo_outer_hor_spacing) ?
		    window_width - omgeo_inner_hor_spacing - 
		    omgeo_outer_hor_spacing : omgeo_map_min_width;
  this.div_height = (window_height > omgeo_map_min_height + 
                    omgeo_inner_ver_spacing + omgeo_outer_ver_spacing) ? 
		    window_height - omgeo_inner_ver_spacing - 
		    omgeo_outer_ver_spacing - omgeo_footer_height : omgeo_map_min_height;

  this.resizeFrame("map_frame", this.div_width, this.div_height);

  this.map_div.style.width = this.div_width+"px";
  this.map_div.style.height = this.div_height+"px";

  this.nav_top = omgeo_nav_padding;
  this.nav_left = this.div_width - omgeo_nav_width - omgeo_nav_padding;
  
  this.outer_map_table.style.visibility = "visible";
  
  if (this.active_tile_set)
    this.active_tile_set.frameResize(this.div_width, this.div_height);
}

UserInterfaceObj.prototype.getNavEventData = function(ev) {
  if (ev.pageX && ev.pageY) {
    var nav_x = ev.pageX - this.nav_left - Math.floor(omgeo_nav_width/2);
    var nav_y = ev.pageY - this.nav_top - Math.floor(omgeo_nav_height/2);
  } else if (ev.clientX && ev.clientY) {
    var nav_x = ev.clientX - this.nav_left - Math.floor(omgeo_nav_width/2);
    var nav_y = ev.clientY - this.nav_top - Math.floor(omgeo_nav_height/2);
  }
  if (nav_x < -Math.floor(omgeo_nav_center_width / 2) ||
      nav_x > Math.floor(omgeo_nav_center_width / 2)) {
    this.nav_dx = nav_x;
  } else {
    this.nav_dx = 0;
  }
  if (nav_y < -Math.floor(omgeo_nav_center_width / 2) ||
      nav_y > Math.floor(omgeo_nav_center_width / 2)) {
    this.nav_dy = nav_y;
  } else {
    this.nav_dy = 0;
  }
}

UserInterfaceObj.prototype.navPan = function() {
  if (this.nav_panning && this.active_tile_set) {
    var l = Math.sqrt(this.nav_dx*this.nav_dx + this.nav_dy*this.nav_dy);
    if (l > omgeo_nav_width/2 || l > omgeo_nav_height/2) {
      var dx = this.nav_dx/l;
      var dy = this.nav_dy/l;
    } else {
      var dx = this.nav_dx/omgeo_nav_width*2;
      var dy = this.nav_dy/omgeo_nav_height*2;
    }
    var now = new Date().getTime();
    var d = omgeo_nav_pixpersecond * (this.nav_last_time - now)/1000;
    this.active_tile_set.move(Math.floor(-d*dx), Math.floor(-d*dy));
    this.nav_last_time = now;
    var ui = this;
    window.setTimeout(function() {ui.navPan()}, omgeo_pan_interval);
  }
}

UserInterfaceObj.prototype.navOnMouseDownHandler = function(ev) {
  if (!ev) ev = this.map_frame.event;
  this.getNavEventData(ev);
  this.nav_panning = true;
  this.nav_last_time = new Date().getTime();
  var ui = this;
  window.setTimeout(function(){ui.navPan();}, omgeo_pan_interval);
  return false;
}

UserInterfaceObj.prototype.navOnMouseUpHandler = function(ev) {
  this.nav_panning = false;
  return false;
}

UserInterfaceObj.prototype.navOnMouseMoveHandler = function(ev) {
  if (this.nav_panning) {
    if (!ev) ev = this.map_frame.event;
    this.getNavEventData(ev);
  }
  return false;
}

UserInterfaceObj.prototype.navOnMouseOutHandler = function(ev) {
  this.nav_panning = false;
  return false;
}

UserInterfaceObj.prototype.mapOnMouseDownHandler = function(ev) {
  if (!ev) var ev = this.map_frame.event;
  this.getMapEventData(ev);
  var target = (ev.target) ? ev.target : ev.srcElement;
  if ((this.button == "left" || this.button == "right") &&
      target.nodeName != "A") {
    this.panning = true;
    this.moved = false;
    this.reference_x = this.mouse_x;
    this.reference_y = this.mouse_y;
    this.mouseDrag();
  }
  return false;
}

UserInterfaceObj.prototype.mapOnMouseUpHandler = function(ev) {
  if (!ev) var ev = this.map_frame.event;
  this.getMapEventData(ev);
  this.panning = false;
  var target = (ev.target) ? ev.target : ev.srcElement;
  if (target.nodeName == "A") {
    return true;
  } else {
    if (!this.moved) {
      switch (this.button) {
	case "left":
	  if (this.scale < omgeo_scales.length-1) {
	    this.zoomTo(this.mouse_x, this.mouse_y, this.scale+1);
	  }
	  break;
	case "right":
	  if (this.scale > 0) {
	    this.zoomTo(this.mouse_x, this.mouse_y, this.scale-1)
	  }
	  break;
	default:
      }
    }
    return false;
  }
}

UserInterfaceObj.prototype.coordsModeOnMouseUpHandler = function(ev) {
  if (!ev) var ev = this.map_frame.event;
  this.getMapEventData(ev);
  var target = (ev.target) ? ev.target : ev.srcElement;
  this.panning = false;
  if (target.nodeName == "A") {
    return true;
  } else if (!this.moved) {
    if (this.active_tile_set && this.active_tile_set.status != "prepared" &&
	this.active_tile_set.status != "requiring") {
      this.active_tile_set.showLatLon(
        this.active_tile_set.getXMap(this.mouse_x),
	this.active_tile_set.getYMap(this.mouse_y));
    }
  }
}

UserInterfaceObj.prototype.mapOnMouseMoveHandler = function(ev) {
  this.getMapEventData(ev);
  this.moved = true;
  return false;
}

UserInterfaceObj.prototype.mapOnMouseOutHandler = function(ev) {
  this.getMapEventData(ev);
  if (this.mouse_x < 0 || this.mouse_x > this.active_tile_set.width || 
      this.mouse_y < 0 || this.mouse_y > this.active_tile_set.height) {
    this.panning = false;
  }
  return false;
}

UserInterfaceObj.prototype.mouseDrag = function() {
  this.printMessage("mouseDrag()");
  this.printMessage("mouse_x: "+this.mouse_x+", mouse_y: "+this.mouse_y);
  if (this.moved) {
    var delta_x = this.reference_x - this.mouse_x;
    var delta_y = this.reference_y - this.mouse_y;
    this.reference_x = this.mouse_x;
    this.reference_y = this.mouse_y;
    this.active_tile_set.move(delta_x, delta_y);
  }
  if (this.panning) {
    var ui = this;
    window.setTimeout(function() {ui.mouseDrag()}, omgeo_pan_interval);
  }
}

UserInterfaceObj.prototype.getMapEventData = function(ev) {
  if (!ev) ev = this.map_frame.event;
  if (ev.pageX && ev.pageY) {
    this.mouse_x = ev.pageX;
    this.mouse_y = ev.pageY;
  } else if (ev.clientX && ev.clientY){
    this.mouse_x = ev.clientX;
    this.mouse_y = ev.clientY;
  }

  if (ev.which && ev.which == 1) {
    this.button = "left";
  } else if (ev.button && ev.button == 1) {
    this.button = "left";
  } else if (ev.button && ev.button == 2) {
    this.button = "right";
  } else if (ev.which && ev.which == 3) {
    this.button = "right";
  } else {
    this.button = "";
  }
}

UserInterfaceObj.prototype.zoomTo = function(center_x, center_y, new_scale) {
  
  this.printMessage("zoomTo(center_x: "+center_x+", center_y: "+center_y+
                    "new_scale: "+new_scale+")");
  if (new_scale == this.scale) return false;
  
  var factor = omgeo_scales[this.scale] / omgeo_scales[new_scale];
  var last_ready = ui.active_tile_set.getLastReady();
  if (last_ready) {
    this.tileSetOnFinishHandler();

    if (last_ready != this.active_tile_set) this.active_tile_set.destroy(true);
    
    this.active_tile_set =
      last_ready.zoom(center_x, center_y, factor, omgeo_pan_interval,
                      new_scale);
      
    this.toggleZoombar(this.scale, new_scale);
    this.scale = new_scale;
  }
  if (this.showCoords) this.active_tile_set.div.style.cursor = "crosshair";
}

UserInterfaceObj.prototype.zoomIn = function () {
  this.printMessage("zoomIn()");
  if (this.scale < omgeo_scales.length) {
    this.toolZoom(ui.scale+1);
  }
}

UserInterfaceObj.prototype.zoomOut = function () {
  this.printMessage("zoomOut()");
  if (this.scale > 0) {
    this.toolZoom(this.scale-1);
  }
}

UserInterfaceObj.prototype.toolZoom = function (new_scale) {
  this.printMessage("toolZoom(new_scale: "+new_scale+")");
  this.zoomTo(Math.floor(this.div_width / 2), Math.floor(this.div_height / 2),
              new_scale);
}

UserInterfaceObj.prototype.toggleZoombar = function(old_scale, new_scale) {
  if (old_scale == new_scale) return false;
  document.getElementById("z"+old_scale).className = "zoff";
  document.getElementById("z"+new_scale).className = "zon";
}

UserInterfaceObj.prototype.resetMap = function() {
  this.printMessage("resetMap()");
  
  this.tileSetOnFinishHandler();
  this.onResetHandler();
  this.active_tile_set.destroy();

  document.getElementById("radio_default").checked = true;
  for (var i=0; i < omgeo_data_layers.length; i++) {
    var ckbox = document.getElementById("checkbox_"+omgeo_data_layers[i]);
    if (ckbox) ckbox.checked = false;
  }

  this.toggleZoombar(this.scale, omgeo_def_scale);
  this.scale = omgeo_def_scale;

  this.active_tile_set =
    new TileSetObj(null, this.inter, window.map_frame, this.div_width, 
                   this.div_height, omgeo_tolerance, this.scale, "default");
  this.active_tile_set.firstStart();
}

UserInterfaceObj.prototype.changeLayer = function() {
  this.printMessage("toolChangeLayer()");
  
  for (var i=0; i < omgeo_layers.length; i++) {
    if (document.getElementById("radio_"+omgeo_layers[i]).checked) {
      var new_layer = omgeo_layers[i];
    }
  }
  for (i = omgeo_data_layers.length-1; i>=0; i--) {
    if (document.getElementById("checkbox_"+omgeo_data_layers[i]).checked) {
      new_layer += ","+omgeo_data_layers[i];
	  /*
  // FIXME Toggle all placemarkk categories to on which are connected to all layers in "new_layer".
//omgeo_data_layer2category [[2,39],[2,38]]
	  for (var ii=0; ii<omgeo_data_layer2category.length; ii++ ) {
	    if ("vector_"+omgeo_data_layer2category[ii][0] == omgeo_data_layers[i]) {
		  var cat = this.root.getCategoryById(omgeo_data_layer2category[ii][1]);
		  cat.show(false);
		}
	  }
	  */
    }
  }
  if (this.active_tile_set.layer == new_layer) return false;

  this.tileSetOnFinishHandler();
  
  this.active_tile_set = this.active_tile_set.changeLayer(new_layer);
  if (this.showCoords) this.active_tile_set.div.style.cursor = "crosshair";
}

UserInterfaceObj.prototype.goToScale = function(x, y, min_scale) {
  this.printMessage("goToScale(x: "+x+", y: "+y+")");
  if (this.scale >= min_scale) {
    this.active_tile_set.goTo(x, y);
  } else {
    this.zoomTo(this.active_tile_set.getXScreen(x),
                this.active_tile_set.getYScreen(y), min_scale);
  }
}

UserInterfaceObj.prototype.showCircle = function(x, y, tile_set) {
  this.printMessage("showCircle(x: "+x+", y: "+y+"tile_set.id: "+tile_set.id+
                    ")");
  if (this.circle) this.circle.destroy();
  this.circle =
    new CircleObj(x, y, this.map_frame.document, tile_set.div);
}

UserInterfaceObj.prototype.getPDF = function() {
  if (this.active_tile_set.status == "active") {
  
    var url = this.active_tile_set.getPDFUrl(pdf_url);
    
    if (this.circle && this.circle.visible) 
      url += "&circle_x="+this.active_tile_set.getXScreen(this.circle.x)+
             "&circle_y="+this.active_tile_set.getYScreen(this.circle.y);
    
    if (this.root) {
      var categories = this.root.getActiveCategories();
      if (categories.length > 0) url += "&cats="+categories.join(",");
    }
    
    window.open(url, "pdf_window");
  }
}

UserInterfaceObj.prototype.bookmark = function() {
  var url = bookmark_url + "?" + this.active_tile_set.getURL();
  if (this.circle && this.circle.visible) {
    var circle_lat = this.active_tile_set.getLat(this.circle.y);
    var circle_lon = this.active_tile_set.getLon(this.circle.x);
    url += "&circle_lat="+circle_lat+"&circle_lon="+circle_lon;
  }
  var categories = this.root.getActiveCategories();
  if (categories.length > 0) url += "&cats=" + categories.join(",");
  if (typeof(window.external.addFavorite) == "undefined") {
    url_window = window.open("_blank", "url_window",
      "width=250,height=190,menubar=no,toolbar=no,location=no,resizable=yes");
    url_window.document.write('<p style="font-size:10pt;'+
      'font-family:arial,helvetica,verdana,sans-serif;">'+"\n");
    url_window.document.write("Klicken Sie mit der Rechten Maustaste auf"+
      " den folgenden Link, um ihn als Lesezeichen zu speichern:<br />\n"+
      "<a href=\""+url+"\" target=\"_top\">Link zur aktuellen Ansicht"+
      "</a></p>\n");
  } else {
    window.external.addFavorite(url, "Xeismobil");
  }
}

UserInterfaceObj.prototype.showLegend = function() {
  if (this.active_tile_set.status == "loading" ||
      this.active_tile_set.status == "active") {
    var url = legend_url +"?" + this.active_tile_set.getURL();
    window.open(url, "legend_window",
      "width=500,height=600,toolbar=no,menubar=no,location=no,resizable=yes"+
      ",scrollbars=yes");
  }
}

UserInterfaceObj.prototype.toggleCoordsMode = function() {
  this.showCoords = this.checkbox_mode.checked;
  var ui = this;
  if (this.showCoords) {
    this.map_div.onmouseup =
      function(ev) {return ui.coordsModeOnMouseUpHandler(ev)};
    this.active_tile_set.div.style.cursor = "crosshair";
  } else {
    this.map_div.onmouseup = function(ev) {return ui.mapOnMouseUpHandler(ev)};
    this.active_tile_set.div.style.cursor = "move";
  }
}

UserInterfaceObj.prototype.tileSetOnLoadHandler = function(tile_set, response) {
  ui.printMessage("tileSetOnLoadHandler()");
   
  this.scalebar_img.src = response.scalebar_url;
  this.scalebar_div.style.visibility = "visible";
  this.copyright_div.innerHTML = response.copyright_label;
  this.copyright_div.style.visibility = "visible";
  
  if (this.root) {
    var setUseSmallIcons = false;
     
    this.root.untrigger();

    for (var i=0; i < omgeo_placemark_triggers.length; i++) {
      if (omgeo_placemark_triggers[i].scale == tile_set.scale) {
	if (omgeo_placemark_triggers[i].small_icons)
	  setUseSmallIcons = true;
	if (omgeo_placemark_triggers[i].categories)
	  this.root.trigger(omgeo_placemark_triggers[i].categories);
      }
    }
    this.printMessage("setUseSmallIcons: "+setUseSmallIcons);
    this.useSmallIcons = setUseSmallIcons;
	
	for (var ii=0; ii<omgeo_data_layer2category.length; ii++ ) {
	  if (document.getElementById("checkbox_vector_"+omgeo_data_layer2category[ii][0]).checked == true) {
	    this.root.trigger(new Array(omgeo_data_layer2category[ii][1]));
      }
    }
    
    if (response.poi_catid) {
      var cat = this.root.getCategoryById(response.poi_catid);
      cat.show(false);
    }
    
    var categories = this.root.getActiveCategories();
    if (categories.length > 0) {
      var tiles_array = tile_set.getTiles();
      this.inter.newRequest(new GetPlacemarksRequestObj(tile_set, tiles_array,
        categories));
    }
  }

  if (this.query_tool && this.query_tool.query) {
    this.query_tool.query.updateAll(tile_set);
    var overrideCircleCoords = (this.query_tool.query.selected) ? true : false;
  }
  
  if (!overrideCircleCoords && response.circle_x && response.circle_y) {
    this.showCircle(response.circle_x, response.circle_y, tile_set);
  }
}

UserInterfaceObj.prototype.tileSetOnGetMapsHandler =
  function (tile_set, new_tiles) {
  
  this.printMessage("tileSetOnGetMapsHandler(tile_set.id: "+tile_set.id+
                    ", new_tiles: "+new_tiles+")");
  
  if (this.root) {
    var categories = this.root.getActiveCategories();
    if (categories.length > 0) {
      this.inter.newRequest(new GetPlacemarksRequestObj(tile_set, new_tiles,
	categories));
    }
  }
}

UserInterfaceObj.prototype.tileSetOnFinishHandler = function () {
  this.printMessage("tileSetOnFinishHandler()");
  
  this.inter.terminateAllRequests();
  this.inter.terminateAllPreloads();
  
  if (this.root) this.root.removePlacemarks();
  if (this.circle) this.circle.hide();
}

UserInterfaceObj.prototype.onResetHandler = function () {
  this.printMessage("tileSetOnResetHandler()");
  if (this.root) this.root.hide();
  if (this.query_tool && this.query_tool.query)
    this.query_tool.query.unselect();
}

//----------------------------------------------------------------------------

function resetMap() {
  if (ui) ui.resetMap();
}

function submitQuery() {
  if (ui && ui.query_tool) ui.query_tool.startQuery();
}

function goToResult(query_id, result_id) {
  //if (ui) ui.goToResult(query_id, result_id);
}

function resultFrameOnLoad() {
  if (ui && ui.query_tool && ui.query_tool.query)
    ui.query_tool.resultFrameOnLoadHandler();
}

function zoomIn() {
  if (ui) ui.zoomIn();
}

function zoomOut() {
  if (ui) ui.zoomOut();
}

function toolZoom(new_scale) {
  if (ui) ui.toolZoom(new_scale);
}

function toolChangeLayer() {
  if (ui) ui.changeLayer();
}

function getPDF() {
  if (ui) ui.getPDF();
}

function bookmark() {
  if (ui) ui.bookmark();
}

function showLegend() {
  if (ui) ui.showLegend();
}

//-----------------------------------------------------------------------------

function unfold(name) {
  ui.printMessage("unfold(name: "+name+")");
  var img = document.getElementById(name);
  var div = document.getElementById(name + "_div");
  var what = img.src.indexOf("images/placemarks/open.gif");
  if (what != -1) {
    div.style.display = "none";
    img.src = "images/placemarks/closed.gif";
  } else {
    div.style.display = "block";
    img.src = "images/placemarks/open.gif";
  }
}

function showDescription() {
  desc_window = 
    window.open("bin/anleitung.phpcgi", "desc_window", "width=500,height=600,"+
                "menubar=yes,toolbar=no,location=no,resizable=yes,"+
		"scrollbars=yes");
}
