function in_array(needle, haystack)
{
  for (var i = 0; i < haystack.length; i++)
  {
    if (haystack[i] === needle) return true;
  }
  return false;
}

function array_key_exists(needle, haystack)
{
  for (keyVar in haystack)
  {
    if (keyVar === needle) return true;
  }
  return false;
}

function trim(string)
{
  return string.replace(/^\s+|\s+$/g,"");
};

function getUrlValue( key )
{
  key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+key+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}


var xmlFetcher = function()
{
  this.newHTML         = '';
  this.displayTags     = new Array();
  this.displayTagsPre  = new Array();
  this.displayTagsPost = new Array();
  this.itemUrlTags     = new Array();
  this.items           = new Array();
  this.itemRoot        = '';

  this.queryString     = new Array();

  this.scroll          = true;
  this.scrollSpeed     = 5;
  this.outputElement   = '';

  this.init = function(xmlFile)
  {
  	if (document.implementation && document.implementation.createDocument)
  	{
  		this.xmlDoc = document.implementation.createDocument("", "", null);
  		this.xmlDoc.onload = this.doOutput;
  		this.xmlDoc.xmlFetcherInstance = this;
  	}
  	else if (window.ActiveXObject)
  	{
  		this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
  		var xmlFetcherInstance = this;
  		this.xmlDoc.onreadystatechange = function() { xmlFetcherInstance.doOutput(xmlFetcherInstance) };
   	}
  	else
  	{
  		alert('Your browser can\'t handle this script');
  		return;
  	}

	  for(i=0;i<this.queryString.length;i++)
	  {
	  alert (this.queryString[i]);
      value = getUrlValue(this.queryString[i]);

      if(value != "") xmlFile += '&' + this.queryString[i+1] +'=' + value;

      i++;

  	}

  	this.xmlDoc.load(xmlFile);
  };

  this.initFromString = function(xmlString)
  {
    if (window.ActiveXObject)
    {
      this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
      this.xmlDoc.async="false";
      this.xmlDoc.loadXML(xmlString);
    }
    else
    {
      var parser=new DOMParser();
      this.xmlDoc=parser.parseFromString(xmlString,"text/xml");
    }

    this.doOutput(this);
  };

  this.initScroll = function()
  {
    this.scroller = new scroller();
    this.scroller.init(this.outputElementId, this.scrollSpeed);

    this.scroller.startScroll();
  };

  this.doOutput = function(ieHack)
  {
    if(window.ActiveXObject && this.xmlDoc.readyState != 4) return;

    if(this.xmlFetcherInstance == undefined) {
      var xmlFetcherInstance = ieHack;
    } else {
      var xmlFetcherInstance = this.xmlFetcherInstance;
    }

    if(xmlFetcherInstance.outputFormat == 'readableXML')
    {
      xmlFetcherInstance.openTags = 0;
      xmlFetcherInstance.writeReadableXML(xmlFetcherInstance.xmlDoc.documentElement, document.getElementById('writeroot'));
    }
    else if(xmlFetcherInstance.outputFormat == 'customHTML')
    {
      xmlFetcherInstance.buildCustomHTML(xmlFetcherInstance.xmlDoc.documentElement, document.getElementById('writeroot'));
      xmlFetcherInstance.writeCustomHTML();
    }

    xmlFetcherInstance.outputElement.innerHTML = xmlFetcherInstance.newHTML;

    if(xmlFetcherInstance.scroll)
    {
      window.onLoad += xmlFetcherInstance.initScroll();
    }
  };

  this.buildCustomHTML = function(tree)
  {
    if(array_key_exists(tree.tagName, this.displayTags))
    {
      if(tree.childNodes[0] && trim(tree.childNodes[0].nodeValue)) {
        this.displayTags[tree.tagName][this.displayTags[tree.tagName].length] = tree.childNodes[0].nodeValue;
      }
      else
      {
        this.displayTags[tree.tagName][this.displayTags.length] = '';
      }
    }
    else if(tree.tagName == this.itemRoot)
    {
      this.items[this.items.length] = tree.tagName;
    }
    else if(tree.tagName == this.itemUrlTag)
    {
      this.itemUrlTags[this.itemUrlTags.length] = tree.childNodes[0].nodeValue;
    }

    for(var i=0;i<tree.childNodes.length; i++)
    {
      this.buildCustomHTML(tree.childNodes[i])
    }
  }

  this.writeCustomHTML = function()
  {
    if(this.rootHTMLPre != undefined) this.newHTML += this.rootHTMLPre;

    this.openTags = 0;
    for(i=0;i<this.items.length;i++)
    {
      this.newHTML += this.itemRootPre;

      for(keyVar in this.displayTags)
      {
        if(this.displayTags[keyVar][i] != undefined) {
          this.newHTML = this.newHTML.replace(/itemUrlTagValue/, this.itemUrlTags[i]);
          this.newHTML += this.displayTagsPre[keyVar] + this.displayTags[keyVar][i] + this.displayTagsPost[keyVar];
        }
      }

      this.newHTML += this.itemRootPost;
    }

    if(this.itemRootOpen) this.newHTML += this.itemRootPost;

    if(this.rootHTMLPost != undefined) this.newHTML += this.rootHTMLPost;
  }

  this.writeReadableXML = function(tree)
  {
    if(in_array(tree.tagName, this.displayTags))
    {
      this.newHTML += '<ul><li>' + tree.tagName + '</li>';
      this.openTags++;

      if(tree.childNodes[0] && trim(tree.childNodes[0].nodeValue)) {
        this.newHTML += '<ul><li>' + tree.childNodes[0].nodeValue + '</li>';
        this.openTags++;
      }
    }
    else if(tree.tagName == this.itemRoot)
    {
      if(this.itemRootOpen)
      {
        this.newHTML += '</ul><ul><li>' + tree.tagName + '</li>';
      }
      else
      {
        this.newHTML += '<ul><li>' + tree.tagName + '</li>';
        this.itemRootOpen = true;
      }
    }

    if(this.openTags > 0)
    {
      this.newHTML += '</ul>';
      this.openTags--;
    }

    for(var i=0;i<tree.childNodes.length; i++)
    {
      this.writeReadableXML(tree.childNodes[i])
    }

  };

  this.setOutPutElement = function(element)
  {
    this.outputElement = document.getElementById(element);
    this.outputElementId = element;
  };

  this.setOutputFormat = function(format)
  {
    this.outputFormat = format;
  };

  this.addOutputTag = function(tag, pre, post)
  {
    this.displayTags[tag]     = new Array();
    this.displayTagsPre[tag]  = pre;
    this.displayTagsPost[tag] = post;
  };

  this.setItemRoot = function(root, pre, post)
  {
    this.itemRoot     = root;
    this.itemRootPre  = pre;
    this.itemRootPost = post;
  };

  this.setItemUrlTag = function(tag)
  {
    this.itemUrlTag = tag;
  };

  this.setRootHTML = function(pre, post)
  {
    this.rootHTMLPre  = pre;
    this.rootHTMLPost = post;
  };

  this.setScrollType = function(type)
  {
    this.scrollType = type;
  }

  this.setScrollSpeed = function(speed)
  {
    this.scrollSpeed = speed;
  };

  this.disableScroll = function()
  {
    this.scroll = false;
  };

  this.addQueryStringMap = function(key, map)
  {
    // Done like this for a bug in prototype js framework
    this.queryString[this.queryString.length] = key;
    this.queryString[this.queryString.length] = map;
  };

};

var scroller = function()
{
  this.init = function(elementId, speed)
  {
    this.elementId = elementId;

    this.speed     = speed;

    this.interval  = null;
  };

  this.startScroll = function()
  {
    elementId = this.elementId;

    this.interval = window.setInterval("scrollTheFrame(elementId)", this.speed);
  };

  this.stopScroll = function()
  {
    clearInterval(this.interval);
  };
};


function scrollTheFrame(div)
{
  d = document.getElementById(div);

  if(d.scrollTop >= d.scrollHeight - parseInt(d.style.height))
  {
    d.scrollTop = 0;
  }
  else
  {
    d.scrollTop = d.scrollTop + 1;
  }
}
