String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); };

function getProductId(name) {
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var tmpURL = window.location.href;
    var results = regex.exec( tmpURL );
    if( results == null )
    return "";
    else
        return results[1];
}

function addHomeDiv() {

var homeDiv = document.createElement('DIV');
    homeDiv.id = "home";

    var homebtn = document.createElement('A');
    homebtn.id   = "homebtn";
    homebtn.href = "/";

    var logoclick = document.createElement('IMG');
    logoclick.src = "/images/transparent.gif";

    homeDiv.appendChild(homebtn);
    //homebtn.appendChild(logoclick);
	
//	var sale 	= document.createElement("IMG");
//	sale.id 	= "sale";
//	sale.alt 	= "Høstsalg";
//	sale.src 	= "/images/salg.gif";

    var docBody = document.getElementsByTagName("BODY")[0];
    docBody.appendChild(homeDiv);
//	docBody.appendChild(sale);

//	theObjects = document.getElementsByTagName("object");
//	for (var i = 0; i < theObjects.length; i++) {
//	    theObjects[i].outerHTML = theObjects[i].outerHTML;
//	}

	//var pur = $$('.prod_purchase_1 a');
	//pur.each(function(link) {
		//link.innerHTML = "Mer";
	//});

//    new golfmenu();
}

Event.observe(window, 'load', addHomeDiv);

String.prototype.replaceAll = function( searchTerm, replaceWith, ignoreCase )   {
  //alert('replace: ' + searchTerm + ' with ' + replaceWith);
  var regex = new RegExp("/"+searchTerm+"/g");
  return this.replace( regex, replaceWith );
}


golfmenu = Class.create();
golfmenu.prototype = {
  gents     : [],
  ladies    : [],
  juniors   : [],
  generic   : [],
  curMenu   : "",
  cookieval : [],
  curCat    : this.generic,
  h         : new Hash(),
  
 initialize : function() {
//    $('switchLadies').observe("click", this.setCategory.bindAsEventListener(this));
//    $('switchGents').observe("click", this.setCategory.bindAsEventListener(this));
//    $('switchJuniors').observe("click", this.setCategory.bindAsEventListener(this));
//    $('homebtn').observe("click", this.setCategory.bindAsEventListener(this));

//    this.load();
  },

  load : function() {
    var G  = this;
    this.h = this.loadStates();

    new Ajax.Request("/files/menu.xml", {
      method: "GET",
      onSuccess : G.setProps.bindAsEventListener(this)
    });

  },

  setCategory : function(evt) {
    resetStates();

    var el = Event.element(evt);
    switch(el.id) {
      case "switchLadies" : {
        this.curCat = this.ladies;
        this.load();
        break;
      }
      case "switchGents" : {
        this.curCat = this.gents;
        this.load();
        break;
      }
      case "switchJuniors" : {
        this.curCat = this.juniors;
        this.load();
        break;
      }
      case "homebtn" : {
        this.curCat = this.generic;
        this.load();
        break;
      }
    }
  },

  setProps : function(transport) {
    var data = eval('(' + xml2json(transport.responseXML, "") + ')');
    this.gents   = data.menu.menu_item[0];
    this.ladies  = data.menu.menu_item[1];
    this.juniors = data.menu.menu_item[2];
    this.generic = data.menu.menu_item[3];
    this.updateMenu();
  },

  updateMenu : function() {
    this.curMenu = "<ul class='menu level0'>\n";
    if(! this.curCat)
      this.curCat = this.generic;

    this.getCategories(this.curCat, 0);
    this.curMenu += "</ul>";
    document.getElementById("menu_toplevel").innerHTML = this.curMenu;
    this._startObserving('menu', 'hidden').bindAsEventListener(this);
  },

  getCategories : function(jel, level) {
    var n = "";
    for (var x=0; x<jel.menu_item.length; x++) {
      var item = jel.menu_item[x];
      this.curMenu += "<li><a href=\"/0golf/product/accategory.aspx?AccId=" + item.id + "\">" + item.name['#cdata'] + "</a>\n";

      if(item.menu_item){
        if(this.h["ul_"+item.id] == "0")
          this.curMenu += "<ul id=\"ul_" + item.id + "\" class='level" + (level +1) + "'>\n";
        else
          this.curMenu += "<ul id=\"ul_" + item.id + "\" class='level" + (level +1) + " hidden'>\n";

          this.getCategories(item, level+1);
          this.curMenu += "</ul></li>\n";
      }
      else
        this.curMenu += "</li>\n";
    }
    //    alert(n);
  },

  _startObserving : function(containerClass, hiddenClass) {
    var ArrMenus = $$("ul.level0 ul");
    var m = this;
    var observing = [];
    ArrMenus.each(function(menu) {
        var oLink    = menu.parentNode.getElementsByTagName("A")[0];
        oLink.onclick = function() {
          menu.toggleClassName(hiddenClass);
          m.saveStates();
          return false;
        }
      });
  },

  saveStates : function() {
    var states   = new Hash();
    var ArrMenus = $$(".menu ul");

    for(var x=0; x<ArrMenus.length; x++) {
      var m = ArrMenus[x];
      states[m.id] = m.hasClassName("hidden") ? 1 : 0;
    }

	var expire_date = new Date((new Date().getTime()) + this.CookieExpire*24*60*60*1000);
	setCookie("menuState", Hash.toQueryString(states), expire_date, '/');
  },

  loadStates : function() {
    var cookie = getCookie("menuState");
    var states = new Hash();
    if(cookie) {
      var c = cookie.split("&");
      for (var i = 0 ; i < c.length; i++) {
        var o = c[i].split('=');
        states[o[0]] = o[1];
      }
    }

    return states;
  }
}


function resetStates() {
	// Reset all menu and submenu open/close states  (delete cookie)

	var expire_date = new Date((new Date().getTime()) - 1000);		// set to past time
	setCookie("menuState", '', expire_date, '/');
}

/*
 * Classic Cookie functions
 */

function setCookie(name, value, expires, path, domain, secure) {
	document.cookie	= name + "=" + escape(value) +
	  (expires	? "; expires=" + expires.toGMTString()	: "") +
	  (path		? "; path=" + path			: "") +
	  (domain	? "; domain=" + domain			: "") +
	  (secure	? "; secure"				: "");
}

function getCookie(name) {
	var dc = document.cookie;
	var prefix = name + "=";
	var begin = dc.indexOf("; " + prefix);
	if (begin == -1) {
		begin = dc.indexOf(prefix);
		if (begin != 0) return null;
	}
	else {
		begin += 2;
	}
	var end = document.cookie.indexOf(";", begin);
	if (end == -1) end = dc.length;
	return unescape(dc.substring(begin + prefix.length, end));
}





var imageScroller = Class.create();
imageScroller.prototype = {
    initialize : function() {
        this.currentImage = 0;
        this.viewSize = 3;
        this.imageBox = $('imageBoxInside');
        this.images = this.imageBox.immediateDescendants();
        this.totalImages = this.images.length;
        var imageScroller = this;

        for(i=0; i<this.totalImages; i++) {
            var tmpImage = this.images[i];
            Event.observe(tmpImage, 'mouseover', imageScroller.swapMainImage.bindAsEventListener( this, imageScroller, tmpImage.id), false);
        }

        if(this.totalImages>3) {

            var imgUp = document.createElement('IMG');
                imgUp.id = "imgUp";
                imgUp.src = "/images/arrow_up_2.png";

            var imgDown = document.createElement('IMG');
                imgDown.id = "imgDown";
                imgDown.src = "/images/arrow_down_2.png";

            var controlUp = document.createElement('A');
                controlUp.id = 'moveUp';
                controlUp.appendChild(imgUp);
                Event.observe(controlUp, 'click', imageScroller.moveToNext.bindAsEventListener(this, imageScroller), false);

            var controlDown = document.createElement('A');
                controlDown.id = 'moveDown';
                controlDown.appendChild(imgDown);
                Event.observe(controlDown, 'click', imageScroller.moveToPrevious.bindAsEventListener(this, imageScroller), false);

            //var controls = $('controls');
            var ctrlUp = $('ctrlUp');
            var ctrlDown = $('ctrlDown');

            if($('moveUp'))
                    $('moveUp').remove();

                if($('moveDown'))
                    $('moveDown').remove();

                ctrlUp.appendChild(controlUp);
                ctrlDown.appendChild(controlDown);

            //controls.hide();
        }
    },

    moveToPrevious :function(evt, scroller) {
        if( scroller.currentImage > 0 ) {
			
            new Effect.Move('imageBoxInside', { x: 0, y: 98, transition: Effect.Transitions.sinoidal, afterFinish: this.finishCall, beforeStart: this.startCall });
            scroller.currentImage--;
        }
    },

    moveToNext :function(evt,scroller) {
        if( scroller.currentImage < (scroller.totalImages - scroller.viewSize) ) {
            new Effect.Move('imageBoxInside', { x: 0, y: -98, transition: Effect.Transitions.sinoidal, afterFinish: this.finishCall, beforeStart: this.startCall });
            scroller.currentImage++;
        }
    },
	
	finishCall : function(obj) {
		if ($('moveUp'))
			$('moveUp').show();
		if ($('moveDown'))
			$('moveDown').show();
	},
	
	startCall : function(obj) {
		if ($('moveUp'))
			$('moveUp').hide();
		if ($('moveDown'))
			$('moveDown').hide();
	},

    swapMainImage : function(evt,scroller, imageid ) {
        var firstImageQuery = $(imageid).src.toQueryParams();
        $('product-image').src = '../MakeThumbnail.aspx?width=280&height=280&file='+firstImageQuery['file'];
    }

}


var Product = Class.create();
Product.prototype = {
  initialize :function(sProduct, itemID) {

    this.productType  = sProduct;
    this.productID    = itemID;
    this.productName  = "";
    this.productPrice = "";
    this.productStock  = "";
	this.productShipping = 0;
	this.productDiscount = "";

    this.attributes   = [];
  }
}

var ProductList = Class.create();
ProductList.prototype = {

/**
  initialize.   Constructor
                Retrieve product list from file
                Populate product objects
                Display default variant
*/

    initialize :function(productType, args){
        this.products       = [];
        this.tmpProducts    = [];
        this.curProductID   = $('tbAcpiId').value;
        this.selectFields   = args;
        this.customize      = $('customize');
        this.manufacturer   = "";
        //this.manufacturer   = $$('produsent').innerHTML;
        var Page            = this;

        // Create product objects
        var tmpObj;

        var tmpvareliste = $F('ProductInfo').split('varenummer').compact();

        for (var index = 0; index < tmpvareliste.length; ++index) {
          var vare = tmpvareliste[index];
          if(vare.length != 0) {
              vare = 'varenummer' + vare;
              var item = vare.split('&').compact();
              item.each(function(str) {
                  if(str.length > 0) {
                      strAttr = str.split("=");
                      switch(encodeURI(strAttr[0])) {
                          case 'varenummer' : {
							tmpObj = new Product(productType, strAttr[1]);
							Page.products.push(tmpObj);
							break;
                          }
                          case 'varenavn' : {
                              tmpObj.productName = strAttr[1];
							  break;
                          }
                          case 'pris' : {
                              tmpObj.productPrice = strAttr[1];
							  break;
                          }
                          case 'beholdning' : {
                              tmpObj.productStock = strAttr[1];
							  break;
                          }
                          case 'levering' : {
                              tmpObj.productShipping = strAttr[1];								  
							  break;
                          }	
						  case 'rabatt' : {
							tmpObj.productDiscount = strAttr[1];
							break;
						  }
                      }

                      tmpObj.attributes.push([strAttr[0],strAttr[1]]);
                  }
              });
          }
        }

        this.updateSelect(this, this.selectFields[0], []);		
        this.displayProduct();
    },

/**
    getCurProduct.  Retrieve product list from file
                    Populate product objects
                    Display default variant
*/
    getCurProduct : function() {
        var Page = this;
        var tmpObj;

        this.products.each(function(product) {
            if(product.productID == Page.curProductID) {
                tmpObj = product;
            }
        });
        return tmpObj;
    },


/**
    displayProduct: Present details of selected product to user
    Initialize product selection feature
*/
    displayProduct :function() {

      var Page = this;
      var curObj = Page.getCurProduct();
      var table = Page.showCurrentAttributes();
      $('current-attributes').innerHTML = table;
      $('tbAcpiId').value = curObj.productID;
      $('tbAcpiStock').value = curObj.productStock;
      $('product-name').innerHTML = Page.manufacturer + " " + curObj.productName;
      $('product-price').innerHTML = Math.round(parseFloat(curObj.productPrice)) + ',-';
		if ((curObj.productDiscount != "999999") && (curObj.productDiscount != curObj.productPrice))
		{
			var discount = (curObj.productDiscount - curObj.productPrice) / curObj.productDiscount * 100;
			$('product-discount').innerHTML = 'Veil. pris: ' + Math.round(parseFloat(curObj.productDiscount)) + ',- (<span style="color: red">-' + Math.floor(parseFloat(discount)) + '%</span>)';
		}
	  if (curObj.productShipping != 0)
        $('product-shipping').innerHTML = 'Ekstra frakt på dette produktet: ' + Math.round(parseFloat(curObj.productShipping)) + ',-';
	  else
        $('product-shipping').innerHTML = '';	  
      this.getImages(curObj.productID);
    },

    getImages : function(productID) {
      var Page = this;
      var url = '../ImageList.aspx';
      var pars = 'id=' + productID;
      var myAjax = new Ajax.Request( url,
        {
          method: 'get',
          parameters: pars,
          onSuccess: Page.showResponse
        }
      );
    },

    showResponse :function(originalRequest) {
      var Page = this;
      var tmp = originalRequest.responseText;
      var thumbs = $('imageBoxInside');
      var myElement = document.createElement('DIV');

      while(tmp.indexOf("MakeThumbnail.aspx?file") != -1) {
        tmp = tmp.replace(".aspx?file", ".aspx?width=80&height=80&file")
      }
      thumbs.replace(tmp);

      var firstImageQuery = $('imageBoxInside').firstChild.src.toQueryParams();
      $('product-image').src = '../MakeThumbnail.aspx?width=280&height=280&file='+firstImageQuery['file'];
	 

      var ImageScroller = new imageScroller();

/*

      var thumbs2 = $('imageBoxInside');
      for(var i=0;i<thumbs2.childNodes.length; i++) {
        var img = $(thumbs2.childNodes[i]);
            img.swapMainImage = Page.swapMainImage;
        var tmpSrc = img.src.toQueryParams();
        Event.observe(img, "mouseover", Page.swapMainImage.bindAsEventListener(this, img.id, tmpSrc), false);
      }
*/
      //$('product-image').onmouseover = function(){
//        alert('mousing over');
        //}

    },

    updateSelect : function(from, whichBox, existingValues) {
		var remaining;
        var Page = this;
        var currentField = 0;
        if(from != this) {
            // If initiated from a selectbox, get the appropriate field
            for(var idx=0; idx<Page.selectFields.length; idx++) {
            // Locate currentfield, leaving any fields leading up to currentfield untouched
                if(Page.selectFields[idx] == whichBox) {

                  /**
                    If user changes earlier selections, remove all existing values from that point
                  **/
                  if(idx < existingValues.length) {
                    existingValues.splice(idx,(existingValues.length - idx));
                  }
                  // Push the selected field value to existing values
                  existingValues.push($F(whichBox));
                  currentField = idx;
                }
            }

            // Reset all values after currently selected
            for(x=currentField +1; x<Page.selectFields.length; x++) {
                if($(Page.selectFields[x]))
                  Element.remove($(Page.selectFields[x]));
            }

            remaining = Page.getRemaining(existingValues);
        }
        else {
            // Generate initial field
            remaining = Page.products;
        }

        if(existingValues.length < Page.selectFields.length) {
            Page.createOptions(remaining, existingValues);
	     }

       if(existingValues.length == Page.selectFields.length) {
            if(remaining.length == 1) {
                this.curProductID = remaining[0].productID;
                this.displayProduct();
            }
            //else {
                //document.location.href = "/error.aspx?error=1";
            //}
        }
    },

    createOptions : function(remaining, existingValues) {
        var Page = this;
        var optArray = [];
        var curProduct = Page.getCurProduct();
        var useAttribute = 0;
        var selectName = Page.selectFields[existingValues.length];

        // Create select box
        var box   = document.createElement('SELECT');
        box.id    = selectName;
        box.name  = box.id;
        $('product-attributes').appendChild(box);
        //box.title = "Usikker p&#229; hva som passer for deg?\n Ring oss p�0GOLF (04653) og la oss hjelpe deg &#229; velge riktig."
        // Create initial value
        var initOpt = document.createElement('OPTION');
        var initTxt = document.createTextNode('Velg ' + box.id);
            initOpt.appendChild(initTxt);
        box.appendChild(initOpt);
        Event.observe(box, "change", Page.updateSelect.bindAsEventListener(this, selectName, existingValues), false);

        // Look up attribute position in product object using existing value length
        for(var x = 0; x < curProduct.attributes.length; x++) {
			if(curProduct.attributes[x][0] == Page.selectFields[existingValues.length])
                useAttribute = x;
        }

        for (var index = 0; index < remaining.length; ++index) {
            var product = remaining[index];
            if(product.attributes[useAttribute])
              optArray.push(product.attributes[useAttribute][1]);
        }

        var unique = optArray.uniq();
        for(var u=0; u<unique.length; u++) {
          tmpOpt = unique[u];
          var opt = document.createElement('OPTION');
          var txt = document.createTextNode(tmpOpt);
          opt.appendChild(txt);
          box.appendChild(opt);

          if(unique.length == 1) {
              $(initOpt).replace();
              opt.setAttribute('selected', 'selected');
              box.hide();
              Page.updateSelect(box, selectName, existingValues);
          }
        }
//        $('product-attributes').appendChild(box);
    },

    getRemaining : function(existingValues) {
        var Page = this;
        var tmpObjects = [];
        var checkAttributes = [];
        var counter = 0;

        if(existingValues.length == 0) {
            return Page.products;
        }
        else {
            var curProduct = Page.getCurProduct();
            for(var i = 0; i < existingValues.length; i++) {
                for(var x = 0; x < curProduct.attributes.length; x++) {
                    if(curProduct.attributes[x][0] == Page.selectFields[i])
                        checkAttributes.push(x);
                }
            }
        }

        for(var p = 0; p<Page.products.length; p++) {
            var product = Page.products[p];
            var addObject = true;
            var y = 0;
            checkAttributes.each(
                function(val) {
                  if(product.attributes[val]) {
                    if(product.attributes[val][1] != existingValues[y])
                    addObject = false;
                    y = y + 1;
                  }
                }
            );
            if(addObject == true)
                tmpObjects.push(product);
        }

        return tmpObjects;
    },

    displayRemaining :function(remaining) {
        var tmp = "";
        var Page = this;

        remaining.each(
            function(product) {
                var i = 0;
                product.attributes.each(
                    function(att) {
                            tmp += att[0] + ": " + att[1] + " ";
                        i++;
                    }
                );
                tmp += "\n\n";
            }
        );

        //alert(tmp);
    },

    // Create table of attributes from selectFields
    showCurrentAttributes : function() {
      var Page = this;
      var curObj = Page.getCurProduct();

      var th = "";
      var td = "";

      var i = 1;
      for(var idx=0; idx<Page.selectFields.length; idx++) {
        curObj.attributes.each(
          function(att) {
            if(Page.selectFields[idx] == att[0] && att[1] != "") {
              th+="<th>"+ att[0] + "</th>";
              td+="<td>"+ att[1] + "</td>";
            }
          }
        )
      }

      var tmp = "<table id='prod-atts'>";
          tmp+= "<tr>" + th + "</tr>";
          tmp+= "<tr>" + td + "</tr>";
          tmp+="</table>";

      return tmp;
    }
}



var catArr = {
    items : [
        {
            varegruppe: "01",
            gruppenavn:"Driver",
            attributter: ["Hånd","Flex","Loft","Skaft","Vekting"]
        },
        {
            varegruppe: "02",
            gruppenavn:"Woods",
            attributter: ["Hånd","Flex", "Køllenummer","Loft","Skaft","Vekting"]
        },
        {
            varegruppe: "03",
            gruppenavn:"Hybrider",
            attributter: ["Hånd","Skaft","Flex", "Køllenummer","Loft","Vekting"]
        },
        {
            varegruppe: "04",
            gruppenavn:"Jern",
            attributter: ["Hånd","Skaft","Flex","Køllenummer", "Design"]
        },
        {
            varegruppe: "05",
            gruppenavn:"Wedger",
            attributter: ["Spiller","Hånd","Loft","Bounce","Skaft","Finish"]
        },
        {
            varegruppe: "06",
            gruppenavn:"Puttere",
            attributter: ["Hånd","Modell","Lengde"]
        },
        {
            varegruppe: "07",
            gruppenavn:"Halvsett",
            attributter: ["Flex","Hånd","Innhold","Skaft"]
        },
        {
            varegruppe: "08",
            gruppenavn:"Helsett",
            attributter: ["Flex","Hånd","Innhold","Skaft"]
        },
        {
            varegruppe: "09",
            gruppenavn:"Hybridsett",
            attributter: ["Hånd","Skaft","Flex","Innhold"]
        },
        {
            varegruppe: "10",
            gruppenavn:"Baller",
            attributter: ["Farge","Antall"]
        },
{
            varegruppe: "11",
            gruppenavn:"Logoballer",
            attributter: ["Modell","Farge","Antall"]
        },

        {
            varegruppe: "16",
            gruppenavn:"Trallebag",
            attributter: ["Farge"]
        },
        {
            varegruppe: "17",
            gruppenavn:"Bærebag",
            attributter: ["Farge"]
        },
        {
            varegruppe: "18",
            gruppenavn:"Reisetrekk",
            attributter: ["Farge"]
        },
        {
            varegruppe: "33",
            gruppenavn:"Golfsko",
            attributter: ["Bredde","Farge","Skostørrelse"]
        },
        {
            varegruppe: "34",
            gruppenavn:"Sokker",
            attributter: ["Sokker_antall","Farge","Størrelse"]
        },
        {
            varegruppe: "35",
            gruppenavn:"Dressko",
            attributter: []
        },
        {
            varegruppe: "36",
            gruppenavn:"Golfsko",
            attributter: ["Bredde","Farge","Skostørrelse"]
        },
        {
            varegruppe: "38",
            gruppenavn:"Juniorsko",
            attributter: []
        },
        {
            varegruppe: "42",
            gruppenavn:"Pegger",
            attributter: []
        },
        {
            varegruppe: "43",
            gruppenavn:"Håndklær",
            attributter: []
        },
        {
            varegruppe: "44",
            gruppenavn:"Paraplyer",
            attributter: []
        },
        {
            varegruppe: "45",
            gruppenavn:"Hansker",
            attributter: ["Hånd","Spiller","Størrelse","Materiale","Farge"]
        },
        {
            varegruppe: "46",
            gruppenavn:"Hodeplagg",
            attributter: ["Farge", "Størrelse"]
        },

        {
            varegruppe: "47",
            gruppenavn:"Tilbehør",
            attributter: ["Lengde", "Farge", "Antall"]
        },
        {
            varegruppe: "48",
            gruppenavn:"Traller",
            attributter: ["Farge"]
        },
        {
            varegruppe: "53",
            gruppenavn:"Teknisk1",
            attributter: ["Spiller", "Farge", "Størrelse"]
        },
        {
            varegruppe: "54",
            gruppenavn:"Teknisk2",
            attributter: ["Spiller","Farge", "Størrelse", "Bukselengde"]
        },
        {
            varegruppe: "55",
            gruppenavn:"ITOppe",
            attributter: ["Spiller", "Størrelse", "Farge"]
        },
        {
            varegruppe: "56",
            gruppenavn:"ITNede",
            attributter: ["Størrelse","Farge","Materiale"]
        },
		{
            varegruppe: "60",
            gruppenavn:"Tilbehør",
            attributter: ["Beløp"]
        },		
		{
            varegruppe: "70",
            gruppenavn:"Multimedia",
            attributter: []
        },
		{
            varegruppe: "80",
            gruppenavn:"Køllemaker",
            attributter: ["Farge","Størrelse", "Antall"]
        }
    ]
}


/*	This work is licensed under Creative Commons GNU LGPL License.

	License: http://creativecommons.org/licenses/LGPL/2.1/
   Version: 0.9
	Author:  Stefan Goessner/2006
	Web:     http://goessner.net/ 
*/
function xml2json(xml, tab) {
   var X = {
      toObj: function(xml) {
         var o = {};
         if (xml.nodeType==1) {   // element node ..
            if (xml.attributes.length)   // element with attributes  ..
               for (var i=0; i<xml.attributes.length; i++)
                  o["@"+xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
            if (xml.firstChild) { // element has child nodes ..
               var textChild=0, cdataChild=0, hasElementChild=false;
               for (var n=xml.firstChild; n; n=n.nextSibling) {
                  if (n.nodeType==1) hasElementChild = true;
                  else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
                  else if (n.nodeType==4) cdataChild++; // cdata section node
               }
               if (hasElementChild) {
                  if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
                     X.removeWhite(xml);
                     for (var n=xml.firstChild; n; n=n.nextSibling) {
                        if (n.nodeType == 3)  // text node
                           o["#text"] = X.escape(n.nodeValue);
                        else if (n.nodeType == 4)  // cdata node
                           o["#cdata"] = X.escape(n.nodeValue);
                        else if (o[n.nodeName]) {  // multiple occurence of element ..
                           if (o[n.nodeName] instanceof Array)
                              o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
                           else
                              o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
                        }
                        else  // first occurence of element..
                           o[n.nodeName] = X.toObj(n);
                     }
                  }
                  else { // mixed content
                     if (!xml.attributes.length)
                        o = X.escape(X.innerXml(xml));
                     else
                        o["#text"] = X.escape(X.innerXml(xml));
                  }
               }
               else if (textChild) { // pure text
                  if (!xml.attributes.length)
                     o = X.escape(X.innerXml(xml));
                  else
                     o["#text"] = X.escape(X.innerXml(xml));
               }
               else if (cdataChild) { // cdata
                  if (cdataChild > 1)
                     o = X.escape(X.innerXml(xml));
                  else
                     for (var n=xml.firstChild; n; n=n.nextSibling)
                        o["#cdata"] = X.escape(n.nodeValue);
               }
            }
            if (!xml.attributes.length && !xml.firstChild) o = null;
         }
         else if (xml.nodeType==9) { // document.node
            o = X.toObj(xml.documentElement);
         }
         else
            alert("unhandled node type: " + xml.nodeType);
         return o;
      },
      toJson: function(o, name, ind) {
         var json = name ? ("\""+name+"\"") : "";
         if (o instanceof Array) {
            for (var i=0,n=o.length; i<n; i++)
               o[i] = X.toJson(o[i], "", ind+"\t");
            json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
         }
         else if (o == null)
            json += (name&&":") + "null";
         else if (typeof(o) == "object") {
            var arr = [];
            for (var m in o)
               arr[arr.length] = X.toJson(o[m], m, ind+"\t");
            json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
         }
         else if (typeof(o) == "string")
            json += (name&&":") + "\"" + o.toString() + "\"";
         else
            json += (name&&":") + o.toString();
         return json;
      },
      innerXml: function(node) {
         var s = ""
         if ("innerHTML" in node)
            s = node.innerHTML;
         else {
            var asXml = function(n) {
               var s = "";
               if (n.nodeType == 1) {
                  s += "<" + n.nodeName;
                  for (var i=0; i<n.attributes.length;i++)
                     s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
                  if (n.firstChild) {
                     s += ">";
                     for (var c=n.firstChild; c; c=c.nextSibling)
                        s += asXml(c);
                     s += "</"+n.nodeName+">";
                  }
                  else
                     s += "/>";
               }
               else if (n.nodeType == 3)
                  s += n.nodeValue;
               else if (n.nodeType == 4)
                  s += "<![CDATA[" + n.nodeValue + "]]>";
               return s;
            };
            for (var c=node.firstChild; c; c=c.nextSibling)
               s += asXml(c);
         }
         return s;
      },
      escape: function(txt) {
         return txt.replace(/[\\]/g, "\\\\")
                   .replace(/[\"]/g, '\\"')
                   .replace(/[\n]/g, '\\n')
                   .replace(/[\r]/g, '\\r');
      },
      removeWhite: function(e) {
         e.normalize();
         for (var n = e.firstChild; n; ) {
            if (n.nodeType == 3) {  // text node
               if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
                  var nxt = n.nextSibling;
                  e.removeChild(n);
                  n = nxt;
               }
               else
                  n = n.nextSibling;
            }
            else if (n.nodeType == 1) {  // element node
               X.removeWhite(n);
               n = n.nextSibling;
            }
            else                      // any other node
               n = n.nextSibling;
         }
         return e;
      }
   };
   if (xml.nodeType == 9) // document node
      xml = xml.documentElement;
   var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
   return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
}


function parseXml(xml) {
    var dom = null;
    if (window.DOMParser) {
        try { 
            dom = (new DOMParser()).parseFromString(xml, "text/xml"); 
        } 
        catch (e) { dom = null; }
    }
    else if (window.ActiveXObject) {
        try {
            dom = new ActiveXObject('Microsoft.XMLDOM');
            dom.async = false;
            if (!dom.loadXML(xml)) // parse error ..
                window.alert(dom.parseError.reason + dom.parseError.srcText);
        } 
        catch (e) { dom = null; }
    }
    else
        alert("cannot parse xml string!");
    return dom;
}

