function WWData() {

  //=========================
  // Globale Variablen
  //=========================

  var Doc;

  //===========================================
  // Main Folder und ggf. goog-trans einhängen
  //===========================================
  function insertSidebarContent() {
    $('wSidebar').update(); // Inhalt löschen
    $('wSidebar').insert({bottom: $(wwExec.mainFolder.node)});
  }

  //=================================================================================
  // Laden der Daten
  //=================================================================================

  //----------------------------
  // XMLHttpRequest
  //----------------------------
  this.CreateXMLHttpRequest = function() {
    wwLayout.WriteLog('CreateXMLHttpRequest', 1);
    if (window.XMLHttpRequest) {
      try { return new XMLHttpRequest(); } catch(e) {}
    }
    if (window.ActiveXObject) {
      try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
      try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
    }
    return null;
  }

  //-----------------
  // XML Daten Laden
  //-----------------
  var request = false;
  this.LoadXmlData = function() {
    wwLayout.WriteLog('LoadXmlData', 1);

    // xml-Daten einlesen
    request = this.CreateXMLHttpRequest();
    request.open("GET", wwLang.xmlFile, true);
    request.onreadystatechange = SetSidebarData;
    request.send(null);

    if (window.location.search == "") {
      //wwLayout.ShowInfos();
    }
  }

  //------------------------
  // Sidebar initialisieren
  //------------------------
  function SetSidebarData() {
    if (request.readyState != 4) {
      return;
    }

    wwLayout.WriteLog("SetSidebarData()", 1);

    // XML Daten auswerten
    var xmlDoc = request.responseXML;
    Doc = xmlDoc.documentElement.getElementsByTagName("Document")[0];
    var numCams = SetSidebarContent(null, Doc, 0);
    wwExec.mainFolder.setTitle(numCams);
    insertSidebarContent();
    //alert(wwExec.mainFolder.node.innerHTML);

    if (wwParam.searchtext != "") {
      //alert(wwExec.globSelBase + ', ' + wwExec.globSelWebcam + ', ' + wwExec.globSelType + ', ' + wwExec.globSelTime);
      document.CamSelForm.SearchSelText.value = wwParam.searchtext;
      $('radioSearchSel').click();
      wwExec.globSelText = wwParam.searchtextParam;
      if (wwParam.searchtextParam == "") {
        wwExec.globSelBase = 'AllCams';   // kein Suchtext vorhanden, also auf Basis 'All' zurücksetzen
      }
    }
  }

  //------------------------------------
  // Unterordner auswerten, rekursiv
  //------------------------------------
  var arrIdXml = new Array();
  function SetSidebarContent(parentFolder, parentXml, num) {
    if (parentFolder) {
      wwLayout.WriteLog('SetSidebarContent: parentFolder=' + parentFolder.id + ' ' + parentFolder.name + ', num=' + num, 1);
    } else {
      wwLayout.WriteLog('SetSidebarContent: parentFolder=null, num=' + num, 1);
    }
    var numCams = 0;

    // Unterordner und Placemarks des gegebenen Ordners auswerten
    var nodeXml = parentXml.firstChild;
    while (nodeXml != null) {
      if (nodeXml.nodeName == 'Folder') {
        // Unterordner gefunden

        // Folder erstellen
        var folderName = nodeXml.getElementsByTagName('name')[0].firstChild.nodeValue;
        var folder = new Folder(folderName, num, parentFolder);

        // Rekursion über Unterordner
        var numCamsFolder = SetSidebarContent(folder, nodeXml, num + 1);
        numCams += numCamsFolder;
        folder.setNumCams(numCamsFolder);
      }

      if (nodeXml.nodeName == 'Placemark') {
        // Placemark gefunden

        // ID des Placemark
        var idPlaceXml = nodeXml.getAttribute('id'); // Placemark ID aus xml-File
        if (window.location.hostname == 'localhost') {  // Meldung nur lokal
          if (arrIdXml[idPlaceXml]) {
            alert('Error: ' + idPlaceXml);
          } else {
            arrIdXml[idPlaceXml] = 1;
          }
        }

        // Name des Placemark
        var placeName = nodeXml.getElementsByTagName('name')[0].firstChild.nodeValue;

        // Koordinaten für Marker und Wetter
        var strCoordinates = nodeXml.getElementsByTagName('coordinates')[0].firstChild.nodeValue;
        var coordinates = strCoordinates.split(',');
        var lat = Number(coordinates[1]);
        var lng = Number(coordinates[0]);
        lat = Math.round(lat * 1000000) / 1000000;
        lng = Math.round(lng * 1000000) / 1000000;

        var country = wwExec.arrFolders[parentFolder.id].name;
        var species = wwExec.arrFolders[parentFolder.parentFP.id].name;

        // title für Marker
        //var title = nodeXml.getElementsByTagName('name')[0].firstChild.nodeValue;

        // Pfad zum marker image
        var nameMarker = nodeXml.getElementsByTagName('styleUrl')[0].firstChild.nodeValue.slice(5); // slice(5): '#msn_' am Anfang weglassen
        var pathMarker = './files/' + nameMarker + '.png';

        // Cam zu Anzahl Cams des Hauptordners dazuzählen
        numCams += 1;
        //var strDescription = //EvalMarkerDescription(nodeXml, lat, lng);     //*** statt string die Knoten übernehmen?
        var strDescription = "<nobr>" + nodeXml.getElementsByTagName('description')[0].firstChild.nodeValue + "</nobr>";
        var place = new Place(placeName, num, parentFolder, idPlaceXml, lat, lng, pathMarker, strDescription, country, species);
        if (lat == wwParam.centerLatStart && lng == wwParam.centerLngStart) {
          if (wwParam.searchtext == "") {
            wwParam.searchtext = place.idXml;
          } else {
            wwParam.searchtext += " " + place.idXml;
          }
        }
      }

      // weiter zum nächsten Element im Hauptordner
      nodeXml = nodeXml.nextSibling;
    }

    return (numCams);
  }
}


//=========================
// Folder
//=========================
function Folder(name, num, parent) {

  //--------------------------------------------
  // Inititialisierung
  //--------------------------------------------
  this.init(parent, 'f');

  this.name = name;
  wwExec.arrFolders[this.id] = this; // für einfachen Zugriff bei Klick auf ein Objekt

  // Anzahl (selektierte) Cams
  this.numCams    = 0;
  this.numSelCams = 0;

  // Knoten für Folder inkl. Inhalt
  this.node = new Element('div');
  $(this.node).writeAttribute('id', this.id);

  // Knoten für Foldernamen-Zeile anhängen
  this.nodeHead = new Element('div');
  $(this.nodeHead).writeAttribute('style', 'white-space:nowrap;');
  $(this.node).insert({bottom: $(this.nodeHead)});

  // Knoten für Abstand-Symbol anhängen
  for (count = 1; count < num; count++) {
    var nodeImgAbstand = new Element('img');
    $(nodeImgAbstand).writeAttribute('src', wwExec.pathDist);
    $(this.nodeHead).insert({bottom: $(nodeImgAbstand)});
  }

  // Knoten für ecf-Symbol anhängen
  this.nodeImgEcf = new Element('img');
  $(this.nodeImgEcf).writeAttribute('src', wwExec.pathPlus);
  $(this.nodeHead).insert({bottom: $(this.nodeImgEcf)});
  $(this.nodeImgEcf).observe('click', function(event) { wwExec.ExpandCollapseFolder(this.ancestors()[1].id); });

  // Knoten für shm-Symbol anhängen
  this.nodeImgShm = new Element('img');
  $(this.nodeImgShm).writeAttribute('src', wwExec.pathUncheckedF);
  $(this.nodeImgShm).writeAttribute('name', this.id);
  $(this.nodeHead).insert({bottom: $(this.nodeImgShm)});
  $(this.nodeImgShm).observe('click', function(event) { wwExec.ShowHideMarkersF(this.ancestors()[1].id); });

  // Knoten für Foldernamen und Anzahl Cams anhängen
  this.nodeName    = new Element('span');
  if (num < 2) {   // Fettschrift nur für oberste Ordner
    $(this.nodeName).writeAttribute('class', 'cfolderbold');
  } else {
    $(this.nodeName).writeAttribute('class', 'cfolder');
  }
  $(this.nodeName).writeAttribute('name', this.id);
  $(this.nodeName).insert(name);

  this.nodeNumCams = new Element('span');
  $(this.nodeName).insert({bottom: $(this.nodeNumCams)});
  $(this.nodeNumCams).writeAttribute('style', 'font-weight:normal');
  $(this.nodeNumCams).insert(' (');
  this.nodeTextNumCams = new Element('span');
  $(this.nodeTextNumCams).update('0');
  $(this.nodeNumCams).insert({bottom: $(this.nodeTextNumCams)});
  $(this.nodeNumCams).insert(')');

  $(this.nodeHead).insert({bottom: $(this.nodeName)});
  $(this.nodeName).observe('click', function(event) { wwExec.ZoomFolder(this.ancestors()[1].id); });

  // Knoten für Folderinhalt anhängen
  this.nodeContent = new Element('span');
  $(this.nodeContent).hide(); // Folderinhalt im Unterordner zunächst nicht sichtbar
  $(this.node).insert({bottom: $(this.nodeContent)});

  if (num == 0) { // Spezialeinstellungen für mainFolder
    wwExec.mainFolder = this;
    $(this.nodeContent).show(); // Unterordner von MainFolder sind sichtbar
    $(this.nodeImgEcf).hide();    // im MainFolder nicht sichtbar
    $(this.nodeNumCams).hide();   // im MainFolder nicht sichtbar
  }

  if (parent != null) parent.appendChildFP(this);

  //--------------------------------------------
  // Anzahl Cams eintragen
  //--------------------------------------------
  this.setNumCams = function(numCams) {
    this.numCams  = numCams;
    $(this.nodeTextNumCams).update(numCams);
  }

  //--------------------------------------------
  // Anzahl Cams zurückgeben
  //--------------------------------------------
  this.getNumCams = function(numCams) {
    return this.numCams;
  }

  //--------------------------------------------
  // appendChild
  //--------------------------------------------
  this.appendChildFP = function(child) {
    // Knoten für Folder (inkl. Folderinhalt) oder Place anhängen
    $(this.nodeContent).insert({bottom: $(child.node)});
  }

  //--------------------------------------------
  // Title setzen für oberste Zeile
  //--------------------------------------------
  this.setTitle = function() {
    var strTitle = (this.numSelCams > 0) ? 'webcams: ' + this.numCams + ', selected: ' + this.numSelCams : 'webcams: ' + this.numCams;
    $(this.nodeName).writeAttribute('title', strTitle);
  }

}

//=========================
// Place
//=========================
function Place(name, num, parent, idXml, lat, lng, pathMarker, strDescription, country, species) {

  //--------------------------------------------
  // Inititialisierung
  //--------------------------------------------
  this.init(parent, 'p');

  this.name = name;
  this.idXml = idXml;
  this.lat = lat;
  this.lng = lng;
  this.pathMarker = pathMarker;
  this.country = country;
  this.species = species;
  wwExec.arrPlaces[this.id] = this; // für einfachen Zugriff bei Klick auf ein Objekt

  // Placemark HTML Code anhängen

  this.node = new Element('div');

  $(this.node).writeAttribute('id', this.id);
  $(this.node).writeAttribute('style', 'white-space:nowrap;');

  // Knoten für Abstand-Symbol anhängen
  for (var count = 1; count < num; count++) {
    this.nodeImgAbstand = new Element('img');
    $(this.nodeImgAbstand).writeAttribute('src', wwExec.pathDist);
    $(this.node).insert({bottom: $(this.nodeImgAbstand)});
  }

  // Knoten für shm-Symbol anhängen
  this.nodeImgShm = new Element('img');
  $(this.nodeImgShm).writeAttribute('src', wwExec.pathUncheckedP);
  //$(this.nodeImgShm).writeAttribute('name', 'shm');
  $(this.node).insert({bottom: $(this.nodeImgShm)});
  $(this.nodeImgShm).observe('click', function(event) { wwExec.ShowHideMarkerP(this.ancestors()[0].id); });

  // Knoten für Placename anhängen
  this.nodeName = new Element('span');
  $(this.nodeName).writeAttribute('class', 'cplace');
  $(this.nodeName).writeAttribute('title', name);
  $(this.nodeName).insert(name);
  $(this.node).insert({bottom: $(this.nodeName)});
  $(this.nodeName).observe('click', function(event) { wwExec.ZoomPlacemark(this.ancestors()[0].id); });

  // Knoten für Land anhängen (unsichtbar, nur damit der Text mit übersetzt wird)
  this.nodeCountry = new Element('span');
  $(this.nodeCountry).hide();
  $(this.nodeCountry).insert(country);
  $(this.node).insert({bottom: $(this.nodeCountry)});

  // Knoten für Art anhängen (unsichtbar, nur damit der Text mit übersetzt wird)
  this.nodeSpecies = new Element('span');
  $(this.nodeSpecies).hide();
  $(this.nodeSpecies).insert(species);
  $(this.node).insert({bottom: $(this.nodeSpecies)});

  // Knoten für Description anhängen (unsichtbar, nur damit der Text mit übersetzt wird)
  this.nodeDescription = new Element('span');
  $(this.nodeDescription).hide();
  this.nodeDescription.innerHTML = strDescription;
  $(this.node).insert({bottom: $(this.nodeDescription)});

  var nodeWeather = new Element('p');
  var weatherUrl = wwLang.strWeatherUrlStart + lat + '%2C' + lng + wwLang.strWeatherUrlEnd;
  if (name == "Pete's Pond") {
    weatherUrl = wwLang.strWeatherUrlStart + 'TLD' + wwLang.strWeatherUrlEnd; // Die Koordinaten oben liefern Alldays, obwohl Tuli Block
                                                                              // nähergelegen ist, daher Sonderbehandlung
  }
  nodeWeather.innerHTML = weatherUrl;
  $(this.nodeDescription.firstChild.lastChild).insert({before: nodeWeather});

  var repTitle = species + ' / ' + country + ' / ' + name + ' (' + lat + ',' + lng + ')';
  //repTitle = repTitle.replace(/<b>/, "");
  //repTitle = repTitle.replace(/<\/b>/, "");
  repTitle = encodeURIComponent(repTitle);
  var urlReport = '<p style="font-size:small;margin-bottom:0px;">' + wwParam.strPostErr + repTitle
                + '" style="color:#909090;">' + wwParam.strReportChanges + '</a></p>';
  this.nodeDescription.insert({bottom: urlReport});

  if (mapSource == 'nomap') {
    header = '<div class="cinfowindownomap"><h3>' + name + '</h3></div>';
  } else {
    header = '<div class="cinfowindow"><h3>' + name + '</h3></div>';
  }
  this.nodeDescription.insert({top: header});

  if (parent != null) parent.appendChildFP(this);
}

//===============================================
// FPObject - Basisobjekt für Places und Folders
//   (verwaltet die Eltern-Kind-Beziehungen
//   und die Ids als eindeutiges Kennzeichen)
//===============================================
var arrIdCnt = new Array();
function FPObject() {

  //--------------------------------------------
  // Inititialisierung
  //--------------------------------------------
  this.init = function(parent, ch) {   // ch: Trennzeichen für Id
    this.parentFP = parent;
    this.firstChildFP = null;
    this.lastChildFP = null;
    this.nextSiblingFP = null;

    this.id = "";
    if (this.parentFP) {
      if (arrIdCnt[this.parentFP.id] != null) {
        arrIdCnt[this.parentFP.id]++;
        this.parentFP.lastChildFP.nextSiblingFP = this;
        this.parentFP.lastChildFP = this;
      } else {
        arrIdCnt[this.parentFP.id] = 0;
        this.parentFP.firstChildFP = this;
        this.parentFP.lastChildFP = this;
      }
      // Id setzen:
      this.id = this.parentFP.id + ch + arrIdCnt[this.parentFP.id];
    } else {
      this.id = ch + '0';
    }
  }

  //----------------------------------------
  // Check, ob this in folder enthalten ist
  //----------------------------------------
  this.isInFolder = function(folder) {
  wwLayout.WriteLog('isInFolder: this=' + this.id + ' ' + this.name + ', folder=' + folder.id + ' ' + folder.name, 1);
    var check = this;
    while(check) {
      if (check == folder) return true;
      check = check.parentFP;
    }
    return false;
  }

}

Folder.prototype = new FPObject();
Place.prototype  = new FPObject();


