
  function TCPlaylistTicker(url, containerElementId, tickerOffsetPX, stingMaxCharLength) {
    this.url = url;
    this.requestHandler = null;
    this.nodexml = null;
    this.tickerOffsetPX = tickerOffsetPX;
    this.stingMaxCharLength = stingMaxCharLength;
    this.tickerRunning = false;
    TCPlaylistTicker.instances[containerElementId] = this;
    this.container = document.getElementById(containerElementId);
    this.buffercontainer = document.getElementById(containerElementId+"_buffer"); 
    this.tickercontainer = this.container.offsetParent;
  }

  // ---- Class properties
  
  TCPlaylistTicker.requestList = new Array();
  TCPlaylistTicker.instances = new Array();
  TCPlaylistTicker.timer = null;
  TCPlaylistTicker.tickerSpeedMS = 60; // TODO: IE speed adjustment

  // ---- Class methods
  
  /* Request processing
       Since the XMLHttpRequest object calls this function globally
       in window context, this function processes all registered TCPlaylistTicker 
       objects in the TCPlaylistTicker.requestList array
  */
  TCPlaylistTicker.processReqChange = function() {
    for (var i=0; i<TCPlaylistTicker.requestList.length; ++i) {
      var instance = TCPlaylistTicker.requestList[i];
      if (instance && instance.requestHandler.readyState == 4) {
        if (instance.requestHandler.status == 200) {
          instance.init(instance.requestHandler.responseXML);
          TCPlaylistTicker.requestList[i] = null;
        } else {
          window.status = "Error retrieving node XML: " + instance.requestHandler.statusText;
        }
      }
    }
  }
  
  /* Creates an playlist HTML element entry 
        from given xml node child named "entry"
  */
  TCPlaylistTicker.createEntry = function (entry, name, additionalClass) {
      var content = entry.getElementsByTagName(name)[0].firstChild.nodeValue;
      var e = document.createElement("span");
      e.className = name + " " + additionalClass;
      e.innerHTML = content;
      return e;
  }
  
  /* Ticker move tick
        Moves all instanciated playlist tickers one tick (called by setInterval timer)
  */
  TCPlaylistTicker.oneTick = function () {
    for (var key in TCPlaylistTicker.instances) { 
      var instance = TCPlaylistTicker.instances[key];
      if (instance.tickerRunning) {
        var pos1 = instance.container.offsetLeft - instance.tickerOffsetPX;
        var pos2 = instance.buffercontainer.offsetLeft - instance.tickerOffsetPX;
        if (pos1<-instance.container.offsetWidth) {
          pos1 = instance.buffercontainer.offsetLeft+instance.container.offsetWidth;
        }
        if (pos2<-instance.buffercontainer.offsetWidth) {
          pos2 = instance.container.offsetLeft+instance.buffercontainer.offsetWidth;
        }
        instance.container.style.left = pos1 + "px";
        instance.buffercontainer.style.left = pos2 + "px";
        // window.status = pos1 + ", " + pos2;
      }
    }
  }
  
  
  // ---- Instance methods
  
  /* Starts request handling for given XML URL */
  TCPlaylistTicker.prototype.loadAndStart = function () {
	  this.requestHandler = null;
    if (window.XMLHttpRequest) { // branch for native XMLHttpRequest object
      try {
		    this.requestHandler = new XMLHttpRequest();
      } catch(e) {
        this.requestHandler = null;
      }
    } else if (window.ActiveXObject) { // branch for IE/Windows ActiveX version
      try {
        this.requestHandler = new ActiveXObject("Msxml2.XMLHTTP");
      } catch(e) {
        try {
          this.requestHandler = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e) {
          this.requestHandler = null;
        }
		  }
    }
    if (this.requestHandler) {
      this.registerForRequestHandling();
		  this.requestHandler.onreadystatechange = TCPlaylistTicker.processReqChange;
		  this.requestHandler.open("GET", this.url, true);
		  this.requestHandler.send(null);
		}  
  }

  /* Add this instance to request processing list */
  TCPlaylistTicker.prototype.registerForRequestHandling = function() {
    TCPlaylistTicker.requestList.push(this);
  }
  
  /* Clears container and buffercontainer divisions */
  TCPlaylistTicker.prototype.clearContainers = function() {
    while (this.container.hasChildNodes()) {
      this.container.removeChild(this.container.lastChild);
    }
    while (this.buffercontainer.hasChildNodes()) {
      this.buffercontainer.removeChild(this.buffercontainer.lastChild);
    }
  }
  
  /* Adds one entry to both containers (buffer) */
  TCPlaylistTicker.prototype.addEntry = function(entry, type, additionalClass) {
    var newEntry = TCPlaylistTicker.createEntry(entry, type, additionalClass);
    this.container.appendChild(newEntry);
    
    if (this.stingMaxCharLength!=0 && newEntry.innerHTML.length>this.stingMaxCharLength) {
    	newEntry.innerHTML = newEntry.innerHTML.substring(0,this.stingMaxCharLength-3)+"...";   	
    }
        
    var clone = newEntry.cloneNode(true);
    this.buffercontainer.appendChild(clone);
  }

  /* Inits div content from given xml document and starts tickering if successfull */
  TCPlaylistTicker.prototype.init = function(xml) {
    this.nodexml = xml;
    var playlist = this.nodexml.getElementsByTagName("playlist")[0];
    var entries = playlist.getElementsByTagName("entry"); 
    this.clearContainers();
    for (var i=0;i<entries.length;i++) {
      var entry = entries[i];
      var additionalClass = "no"+i;
      this.addEntry(entry, "time", additionalClass);
      this.addEntry(entry, "artist", additionalClass);      
      this.addEntry(entry, "song", additionalClass);
    }
    this.checkStringLengths();
    this.startTicker();
  }
  
  TCPlaylistTicker.prototype.checkStringLengths = function() {
  	return null;
  }
  
  /* Start tickering for this instance */
  TCPlaylistTicker.prototype.startTicker = function() {
	if (this.container && this.tickerOffsetPX!=0) {
	  this.container.style.left = "-10000px";
	  this.buffercontainer.style.left = "-10000px"; // due to firefox bug(?): offsetwidth is cut outside visible area of containing div
	  if (this.tickercontainer.offsetWidth < this.container.offsetWidth) {
	  	// content is big enough for tickering
	  	if (!TCPlaylistTicker.timer) {
        		TCPlaylistTicker.timer = setInterval("TCPlaylistTicker.oneTick()", TCPlaylistTicker.tickerSpeedMS);
      	}
      	var pos = this.tickercontainer.offsetWidth;
      	this.container.style.left = pos + "px";
      	this.buffercontainer.style.visibility = "visible";
      	this.buffercontainer.style.left = (pos + this.buffercontainer.offsetWidth) + "px";
      	this.tickerRunning = true;
      }
      else {
      	// content doesn't need ticker
      	this.container.style.left = "0px";
      	this.buffercontainer.style.visibility = "hidden";
      	this.tickerRunning = false;
      }
    }

  }
  
/******* TCPlaylist Search (requires Prototype API) *******/

var TCPlaylistSearch = (TCPlaylistSearch)?TCPlaylistSearch:{
	search: function(form) {
		try {
			var serviceURL = form.action;
			serviceURL += TCPlaylistSearch.addElementValue(form,"day","day");
			serviceURL += TCPlaylistSearch.addElementValue(form,"time","from");
			serviceURL += TCPlaylistSearch.addElementValue(form,"artist","performer");
			serviceURL += TCPlaylistSearch.addElementValue(form,"title","title");
			TCPlaylistSearch.request(serviceURL);
		}
		catch(e) {
			window.status = e;
		}
	},
	addElementValue: function(form, elname, key) {
		var el = form.elements[elname];
		var result = "";
		switch (el.type) {
			case "select-one":
				var selectedIndex = form.elements[elname].selectedIndex;
				result = form.elements[elname].options[selectedIndex].text;
				break;
			case "text":
			default:
				result = form.elements[elname].value;
				break;
		}
		result = result.strip();
		if (result!="")
			return "&"+key+"="+encodeURI(result);
		return "";
	},
	request: function(uri) {
		//alert(uri);
		new Ajax.Request(uri, {
			method: "get",
			onSuccess: TCPlaylistSearch.processXML
		});
	},
	processXML: function(transport) {
		var newhtml = "<table cellspacing='0'><tr><th>Zeit</th><th>Titel</th><th>Interpret</th><th>kaufen</th></tr>";
		var nodexml = transport.responseXML;
	    var playlist = nodexml.getElementsByTagName("playlist")[0];
	    var entries = playlist.getElementsByTagName("entry");
	    for (var i=0;i<entries.length;i++) {
	      var entry = entries[i];
	      var time = entry.getElementsByTagName("time")[0].firstChild.nodeValue;
	      var artist = entry.getElementsByTagName("artist")[0].firstChild.nodeValue;
	      var song = entry.getElementsByTagName("song")[0].firstChild.nodeValue;
	      var shoplink = entry.getElementsByTagName("shoplink")[0].firstChild.nodeValue;
	      var rowclass = "even";
	      if (i%2==1) rowclass = "odd";
	      newhtml += "<tr class='"+rowclass+"'><td>"+time+"</td><td>"+song+"</td><td>"+artist+"</td><td><a href="+shoplink+" target='_blank'><img src='"+TCPlaylistSearch.imageBuySrc+"' border='0'></a></td></tr>";
	    }
	    if (entries.length==0) {
	      newhtml += "<tr><td colspan='4' style='text-align:center;'><i>Keine Suchergebnisse gefunden!</i></td></tr>";
	      
	    }
	    newhtml += "</table><div class='back2SearchForm'><a href='javascript:TCPlaylistSearch.showForm();'>neue Suche</a></div>";	    
	    TCPlaylistSearch.showResults(newhtml);
	},
	handleException: function(transport, exc) {
		// display error message
	},
	imageBuySrc: null,
	showForm: function() {
		var formContainer = $("LRTSForm");
		formContainer.style.display = "block";
		var resultContainer = $("LRTSResults");
		resultContainer.style.display = "none";
	},
	showResults: function(myhtml) {
		var formContainer = $("LRTSForm");
		formContainer.style.display = "none";
		var resultContainer = $("LRTSResults");
		resultContainer.innerHTML = myhtml;
		resultContainer.style.display = "block";
	}
}
  