
var BaseDataSource = Base.extend({
  constructor: function(control,datasource,overlay_type,opts) { 
    this.items = [];
    this.opts = {"overlay_name":overlay_type,'href':datasource};
    for ( var i in opts ) {
      this.opts[i] = opts[i];
    }
    this.href = datasource;
    this.control = control;
    this.dfcache = "";
    this.lastload = -1;
    this.loadinterval = "600";
    this.children = null;
  },

  getDataFile: function() {
    var me = this;
    GSDownloadUrl(this.href,function(d,c) {
      me.lastLoad = new Date().getTime();
      if ( c !== 200 ) {
        return false;
      } 
      me.dfcache = d;
    });
  }

});

var KMLDataSource = BaseDataSource.extend({
  constructor: function(control,datasource,overlay_type,opts) { 
    if ( arguments.length > 1 ) {
      //this.base(Array.prototype.slice.call(arguments);
      //BaseDataSource.apply(this,Array.prototype.slice.call(arguments,1));
    } else {
      //this.base();
      //BaseDataSource.call(this);
    }
    this.base(control,datasource,overlay_type,opts);
    //BaseDataSource.call(this,control,datasource,overlay_type,opts);
  },

  load: function() {
    if ( typeof(this.dfcache) == "undefined" || this.dfcache == "" || 
         (new Date().getTime() - this.lastload) < this.loadinterval ) {
      this.getDataFile();
    }

    if ( this.dfcache == "" || this.dfcache == null ) {
      GEvent.trigger(this.control,'dsload');
      return;
    }

    if ( typeof(this.dom) == "undefined" ) {
      this.dom = GXml.parse(this.dfcache);
    }

    this.loadcount = 0;
    var icl = GEvent.addListener(this,'blockloaded',function(item) {
      this.loadcount += 1;
      if ( this.loadcount == this.base ) {
        GEvent.trigger(this.control,'dsload');
        GEvent.removeListener(icl);
      }
    });


    var opts = {};

    var bc = 0;
    var parentdoc = null;
    var docname = this.dom.getElementsByTagName("name");
    for ( var i = 0; i < docname.length; i++ ) {
      if ( docname[i].parentNode.tagName == "Document" ) {
        opts["title"] = docname[i].firstChild.nodeValue;
        parentdoc = this.opts.title;
        var parentdocitem = this.control.findBlock(opts["title"]);
        if ( parentdocitem !== null ) {
          parentdocitem.initialize(opts);
          this.generated = false;
        } else {
          if ( typeof(opts["type"]) == "undefined" || opts["type"] == null || opts["type"] == "check") {
            var parentdocitem = new GLegendCheckItem(opts);
          } else if ( opts["type"] == "label" ) {
            var parentdocitem = new GLegendLabelItem(opts);
          }
        }
        bc += 1;
        this.base += 1;
        GEvent.trigger(this,'blockcreated',parentdocitem,null,bc);
        GEvent.trigger(this,'blockloaded',parentdocitem,null,bc);
        
      }
    }

    var styles = {};
    var styledom = this.dom.getElementsByTagName("Style");
    for ( var i = 0; i < styledom.length; i++) {
       var stylename = styledom[i].getAttribute('id'); 
       styles[stylename] = {};
       var lst = styledom[i].getElementsByTagName("listItemType");
       if ( lst.length > 0 ) {
         if ( lst[0].firstChild.nodeValue == "radioFolder" ) {
           styles[stylename]['type'] = 'radio';
         }
         if ( lst[0].firstChild.nodeValue == "check" ) {
           styles[stylename]['type'] = 'check';
         }
       }
    }

    folders = this.dom.getElementsByTagName("Folder");
    this.items = [];

    this.base = folders.length;
    this.opts["generated"] = true;
    for ( var i = 0; i < folders.length; i++,bc++) {
      var names = folders[i].getElementsByTagName("name");
      var descriptions = folders[i].getElementsByTagName("description");
      var expand = folders[i].getElementsByTagName("open");
      var visibility = folders[i].getElementsByTagName("visibility");

      var opts = this.opts;
      if ( opts['overlay_name'] == "BaseMarkerLayer" )
          opts['modal'] = false;

      if ( names.length > 0 && names[0].firstChild != null )
        opts["title"] = names[0].firstChild.nodeValue;
      else
        opts["title"] = "unknown";
      
      if ( descriptions.length > 0 && descriptions[0].firstChild  != null) 
        opts["description"] = descriptions[0].firstChild.nodeValue;

      if ( expand != null ) {
        var el = expand.length;
        if ( el > 0 && expand[0].firstChild != null ) {
          expand = expand[0].firstChild.nodeValue==1;
        } else {
          var expand = true;
        }
      }

      var styleurl = folders[i].getElementsByTagName("styleUrl");
      if ( styleurl.length > 0 ) {
        var su = styleurl[0].firstChild.nodeValue.replace(/^#/,"");
        
        if ( typeof(styles[su]) != "undefined" && 
             typeof(styles[su]['type']) != "undefined" ) {
           opts["type"] = styles[su]['type'];
        }
      }

      var minres = folders[i].getElementsByTagName("minimumResolution");
      var maxres = folders[i].getElementsByTagName("maximumResolution");
   
      if ( minres.length > 0 ) {
         minres = minres[0].firstChild.nodeValue;
      } else {
         minres = null;  
      }

      if ( maxres.length > 0 ) {
         maxres = maxres[0].firstChild.nodeValue;
      } else {
         maxres = null;  
      }


      var lod = folders[i].getElementsByTagName("Lod");
      if ( lod.length > 0 ) {
         minres = null;
         var minlod = lod[0].getElementsByTagName("minLodPixels");
         if ( minlod.length > 0 ) var minres = minlod[0].firstChild.nodeValue;
         if ( minres == -1 ) minres = 0;
         else if ( minres != null ) minres = Math.round(Math.max((Math.log(minres)/Math.log(2) - 8),0));

         maxres = null;
         var maxlod = lod[0].getElementsByTagName("maxLodPixels");
         if ( maxlod.length > 0 ) var maxres = maxlod[0].firstChild.nodeValue;
         if ( maxres == -1 ) maxres = 17;
         else if ( maxres != null ) maxres = Math.round(Math.min((Math.log(maxres)/Math.log(2) - 8),17));
      }

      var bounds_ = null;
      var bounds = folders[i].getElementsByTagName("LatLonBox");
      if ( bounds.length > 0 && bounds[0].firstChild != null ) {
        var north = bounds[0].getElementsByTagName("north");
        var south = bounds[0].getElementsByTagName("south");
        var east = bounds[0].getElementsByTagName("east");
        var west = bounds[0].getElementsByTagName("west");

        if ( north.length > 0 && north[0].firstChild != null &&
             south.length > 0  && south[0].firstChild != null && 
             east.length > 0 && east[0].firstChild != null && 
             west.length > 0 && west[0].firstChild != null ) {
          var sw = new GLatLng(south[0].firstChild.nodeValue,west[0].firstChild.nodeValue);
          var ne = new GLatLng(north[0].firstChild.nodeValue,east[0].firstChild.nodeValue);
          var bounds_ = new GLatLngBounds(sw,ne);
        } else {
          var sw = new GLatLng(-85,-180);
          var ne = new GLatLng(85,180);
          var bounds_ = new GLatLngBounds(sw,ne);
        }
      }


      if ( visibility.length > 0 && visibility[0].firstChild != null ) {
        opts["shown"] = visibility[0].firstChild.nodeValue == 1;
      } else {
        opts["shown"] = false;
      }

      if ( parentdocitem ) {
        opts["parent"] = parentdocitem;
      }

      var item = this.control.findBlock(opts["title"]);
      if ( item !== null ) {
        item.initialize(opts);
        this.generated = false;
      } else {
        if ( typeof(opts["type"]) == "undefined" || opts["type"] == null || opts["type"] == "check") {
          var item = new GLegendCheckItem(opts);
        } else if ( opts["type"] == "label" ) {
          var item = new GLegendLabelItem(opts);
        } else if ( opts["type"] == "dropdown" ) {
          var item = new GLegendDropdownItem(opts);
        } else if ( opts["type"] == "radio" ) {
          var item = new GLegendClickItem(opts);
        }
      }
      if ( opts["shown"] ) item.show();
      if ( bounds_ !== null || minres != null || maxres != null ) 
        item.setBounds(bounds_,minres,maxres);
      
      var parent = item;

      if ( expand ) {
        if ( ! this.children && typeof(parent) != "undefined") {
          var me = this;
          var rl = GEvent.addListener(me,'parentloaded',function(children,opts) {
            if ( children != null ) {
              parent.children = [];
              for ( var j = 0; j < children.length; j++ ) {
                opts["title"] = children[j].name;
                var item;

                var e = me.control.getIndex(opts["title"]);
                if ( e !== null ) {
                  item = me.control.getItemAtIndex(e);
                  item.initialize(opts);
                } else {
                  if ( parent.type == "dropdown" || opts["type"] == "dropdown") {
                    item = new GLegendDropdownOptionItem(opts);
                    //item = new GLegendClickItem(opts);
                  } else if ( opts["type"] == "check") {
                    item = new GLegendClickItem(opts);
                  } else if ( opts["type"] == "check") {
                    item = new GLegendCheckItem(opts);
                  } else {
                    item = new GLegendItem(opts);
                  }
                }

                item.overlay = children[j];
                parent.addChild(item);
                me.items[j] = item;
                
                GEvent.trigger(me,'blockloaded',item,parent.title,bc+j+1);
                GEvent.trigger(me,'blockcreated',item,parent.title,bc+j+1);
              }
            }
            GEvent.removeListener(rl);
          });
          
          // parent overlay does not exist, please add now.
          if (typeof(parent.overlay) == "undefined" ) {
            var pl = GEvent.addListener(parent,'loaded',function() {
              var children = [];
              if ( typeof(this.overlay ) != "undefined" ) {
                if ( typeof(parent.overlay.getChildOverlays) != "undefined" ) {
                  children = parent.overlay.getChildOverlays();
                  childopts = me.opts;
                  childopts["level"] += 1;
                }
              }
              if ( children != null ) me.base += children.length;
              GEvent.trigger(me,'blockloaded',parent,null,i);
              if ( parentdocitem )
                GEvent.trigger(this,'blockloaded',parentdocitem,null,i);
              GEvent.removeListener(pl);
              GEvent.trigger(me,'parentloaded',children,opts);
            });
            if ( typeof(parent.control) == "undefined" ) {
              var al = GEvent.addListener(parent,'added',function () {
                //parent.createOverlay(); //create, but do not add to the map yet.
                parent.addOverlay();
                GEvent.removeListener(al);
              });
            } else {
              parent.createOverlay(); //create, but do not add to the map yet.
            }
          }
        }
        GEvent.trigger(this,'blockcreated',parent,null,bc);
      } else {
        GEvent.trigger(this,'blockcreated',parent,null,bc);
        GEvent.trigger(this,'blockloaded',parent,null,bc);
      }
    }
  }
});

/*
var XMLCharDataSource = BaseDataSource.extend({
  constructor: function(control,datasource,overlay_type,opts) { 
    this.ancestor.constructor(control,datasource,overlay_type,opts);
  },

  load: function() {
    if ( typeof(this.dfcache) == "undefined" || this.dfcache == "" || 
         (new Date().getTime() - this.lastload) < this.loadinterval ) {
      this.getDataFile();
    }

    if ( this.dfcache == "" || this.dfcache == null ) {
      GEvent.trigger(this,'load');
      return;
    }

    if ( typeof(this.dom) == "undefined" ) {
      this.dom = GXml.parse(this.dfcache);
    }

    charts = this.dom.getElementsByTagName("chart");
    this.items = [];

    this.loadcount = 0;
    var icl = GEvent.addListener(this,'blockloaded',function(item) {
      this.loadcount += 1;
      if ( this.loadcount == this.base ) {
        GEvent.trigger(this,'load');
        GEvent.removeListener(icl);
      }
    });

    this.base = charts.length;
    this.opts["generated"] = true;
    for ( var i = 0; i < charts.length; i++ ) {
      var chartid = charts[i].getAttribute("chart_id");
      var panels = charts[i].getElementsByTagName("panel");
      for ( var j = 0,p=panels.length; j < p; j++ ) {
        var titles = panels[j].getElementsByTagName("title");
        if ( titles.length > 0 && titles[0].firstChild != null ) 
          var name = titles[0].firstChild.nodeValue;
        else
          var name = chart_id;
        var polygon = panels[j].getAttribute("encoded_polygon");
        var panelno = panels[j].getAttribute("panel_no");
        var filename = panels[j].getAttribute("file_name");
      }
    }
  }
});
*/


var GLegendControl = Base.extend({
  constructor: function(printable,selectable) {
    /*
     * GLegendControl implements interface GControl()
     */
    this.url = '/~jbowen/sccoos/doc/data/prototype/datasources.xml';

    this.defaultTitle = " -- Options -- ";
    this.defaultTitleTip = null;

    this.container = null;        // Contains a title block and list block
    this.titleContainer = null;   // The section that holds the display text
    this.state = {};
                                  // Assignable as .innerHTML = 'Display text'
    this.map = null;

    this.items = [];
    this.blocks = [];
    this.index = {};
    this.blacklist = [];
    this.defaultItems = [];
    this.defaultItemStorage = [];
    this.overlays = [];
    this.order = [];
    this.controls = [];
    this.qs = {};

    this.scrollWidth = 16;        // Make an estimate until initialized
    this.optLength = 10;          // Show N results before scrolling
    this.vizLength = 0;           // Number of results currently visible.

    this.lineWidth = 140;         // Width of displayed option box (pixels)
    this.lineHeight = 18;         // Line height in any unit (pixels)
    this.topoffset = 30;
    this.stateLoadedFromUrl = false;

    var me = this;
    var bookmarklink = document.getElementById("bookmarklink");
    GEvent.addDomListener(bookmarklink,'click',function() {
      me.writeBookmarkLink(); 
    });
  },

  moveToTop: function(label) { 
    return null; // Needs to be rewritten to encompass block concept

    var highest = 0;
    var current = null;
    var currentidx = null;

    for ( var i = 0; i < this.items.length; i++ ) {
      var l = this.items[i].getLevel();
      if ( this.items[i].title == label ) {
        currentidx = i;
        current = l;
      }
      if ( l !== null ) highest = Math.max(highest,l);
    }

    if ( current === highest ) return true;
    if ( currentidx === null ) return false;

    if ( current != null ) {
      for ( var i = current+1,n=this.order.length; i < n; i++ ) {
        var j = this.items[this.order[i]];
        if ( typeof(j) != "undefined" ) {
          j.setLevel(j.getLevel()-1);
          this.order[i-1] = this.order[i];
          GEvent.trigger(j,'reload');
        }
      }
    } else {
      highest += 1;
    }

    this.items[currentidx].setLevel(highest);
    this.order[this.order.length] = currentidx;
    GEvent.trigger(this.items[currentidx],'reload');
  },

  initialize: function(map) { 
    this.jsloader = new JsFileLoader("/~jbowen/sccoos/doc/js/classes/");
    this.map = map;

    // container for the control object
    var container = this.getContainer();
    container.id = "legendctl";

    var list = document.createElement("ul");
    list.id = "legendctl_list";
    list.style.listStyleType = "none";

    // Append list container to control container
    container.appendChild(list);
    map.getContainer().appendChild(container);

    // we should probably redraw to populate display

    // Reset state once all data sources are loaded.
    /*
    // Hold off on redraw for now, triggers twice
    GEvent.addListener(map,'zoomend',function() {
      LC.redraw();
    });
  */

    var me = this;
    // This listener will only be used to initialize.
    //var ml = GEvent.addListener(this,'load',function() { 
        me.message = new GMessageController(true,true);
        me.message.initialize(map);

        GEvent.addListener(this,'messageshow',function(msg,id) {
          me.message.setMessage(msg,id);
          me.message.show(id);
        });

        GEvent.addListener(this,'messagehide',function(id) {
          me.message.hide(id);
        });

        GEvent.addListener(this,'messageupdate',function(msg,id) {
          me.message.setMessage(msg,id);
        });
        //GEvent.removeListener(ml);
    //});

    // Only on first load
    var ll = GEvent.addListener(this, 'load',function() {
        this.loadState(this.qs);
        GEvent.removeListener(ll);
    });

    this.parseFormValues();

    GEvent.addListener(map,'moveend',function() {
      me.redraw();
    });

    GEvent.addListener(this,'dataretrieved',function() {
      me.reset();
    });


    // Signal to self: done initialization
    GEvent.trigger(this,"initialized");

    return container;
  },

  getContainer: function() { 
    if( !this.container ) {
      this.container = document.createElement("div");
    }
    return this.container;
  },

  /*
   * Unregisters event listeners recursively from a node, 
   *   then removes all child nodes from that node.
   */
  emptyNode: function(node) { 
    //GEvent.clearNode(node);
    //this.clearNode(node);
  },


  getItemAtIndex: function(idx) { 
    if( typeof(this.items[idx]) != "undefined" ) { 
      return this.items[idx];
    }
    return null;
  },

  getIndex: function(label) { 
    for ( var i = 0; i < this.items.length; i++ ) {
       if (this.items[i].title == label ) return i;   
    }
    return null;
  },

  addDefault: function(item) { 
    var label = item.title;
    item.control = this;
    
    this.defaultItems.push(label);
    this.defaultItemStorage.push(item);
    GEvent.trigger(this,"added",item);
    return true;
  },

  addBlock: function(block) { 
    if ( ! block ) return;
    block.control = this;

    var oldblock = this.findBlock(block.title);
    if ( oldblock ) {
  /*
      if ( typeof(oldblock.parent) != "undefined" ) {
        var parent = oldblock.parent;
        parent.removeChild(oldblock); 
        parent.addChild(block);
      } else {
        this.removeBlock(oldblock);
        this.blocks.push(block);
      }
  */
    } else {
      if ( typeof(block.parent) != "undefined" ) {
        var p = this.findBlock(block.parent.title); 
        if ( p ) {
          p.addChild(block);
        } else {
          if ( typeof(this.defaultParent) != null ) {
            var p = this.findBlock(this.defaultParent);
            if ( p ) p.addChild(block);
            else this.blocks.push(block); 
          } else {
            this.blocks.push(block);
          }
        }  
      } else {
        this.blocks.push(block);
      }
    }

    this.index[block.title] = block;

    GEvent.trigger(block,"added",block);
    return true;
  },

  // must be careful: this assumes every object in list is unique.
  removeBlock: function(block) { 
    for(var i in this.blocks) { 
      if(this.blocks[i] == block) { 
        var block = this.blocks.splice(i,1);
        GEvent.trigger(this,"itemremoved",block);
        return block;
      }
    }
    return null;
  },

  reset: function() { 
    this.items = [];
    //this.emptyNode(this.getListContainer());
    this.populateFromDefault();
    this.redraw();
    GEvent.trigger(this,"reset");
    return true;
  },

  getListContainer: function() {
    return document.getElementById("legendctl_list");
  },

  /*
   * Recursively removes dom children from dom node.
   * Leaves original parent node childless.
   */
  clearNode: function(node) {
    if( node.hasChildNodes() ) {
      for(var i=node.childNodes.length; i>0; i--) {
        this.clearNode(node.childNodes[i-1]);
        node.removeChild(node.childNodes[i-1]);
      }
    }
  },

  populateFromDefault: function() { 
    for ( var i = 0; i < this.defaultItems.length; i++ ) {
      if ( this.defaultItemStorage[i] !== null ) {
        this.addBlock(this.defaultItemStorage[i]);
      }
    }
  },

  removeControl: function(control) { 
    this.map.removeControl(control);
    for ( var i = 0; i < this.controls.length; i++ ) {
      if ( this.controls[i]['control'] == control ) {
        this.controls.splice(i,1);   
      }
    }
  },

  addControl: function(control) { 
    var position = this.computeControlPosition(control);
    if ( position ) {
      var x2 = position.offset.width;
      var y2 = position.offset.height;
      var x1 = x2+control.width;
      var y1 = y2+control.height;
      var bounds = new GBounds([new GPoint(x1,y2),new GPoint(x2,y1)]);
      var found = false;
      for ( var i = 0; i < this.controls.length; i++ ) {
        if ( this.controls[i]['control'] == control ) {
          found = true;
          this.controls[i]['bounds'] = bounds;
          this.controls[i]['anchor'] = position.anchor;
        }
      }
      if ( ! found ) {
        this.controls.push({'control':control,'bounds':bounds,'anchor':position.anchor});
      }
      this.map.addControl(control,position);
    }
  },

  computeControlPosition: function(control) { 
    var defaultpos = control.getDefaultPosition();
    var x2 = defaultpos.offset.width;
    var y2 = defaultpos.offset.height;
    var x1 = parseInt(x2)+parseInt(control.width);
    var y1 = parseInt(y2)+parseInt(control.height);
    var p1 = new GPoint(x1,y2);
    var p2 = new GPoint(x2,y1);
    var p3 = new GPoint(x1,y1);
    var p4 = new GPoint(x2,y2);
    var bounds = new GBounds([p1,p2]);
    var ypadding = 3;

    var found = false;
    var attempts = 0;

    while ( ! found && attempts < 10 ) {
      attempts += 1;
      for (var i = 0; i < this.controls.length; i++ ) {
        if ( this.controls[i].bounds.containsPoint(p1) || 
             this.controls[i].bounds.containsPoint(p2) ||
             this.controls[i].bounds.containsPoint(p3) ||
             this.controls[i].bounds.containsPoint(p4) ) {
          y2 = parseInt((this.controls[i]['bounds'].max().y)) + ypadding;
          y1 = parseInt(y2) + parseInt(control.height);
          var p1 = new GPoint(x1,y2);
          var p2 = new GPoint(x2,y1);
          var p3 = new GPoint(x1,y1);
          var p4 = new GPoint(x2,y2);
          break;
        }
      }
      if ( i == this.controls.length ) found = true;
      position = new GControlPosition(defaultpos.anchor,new GSize(x2,y2)); 
    }

    if (! found ) {
      position = null;
      alert("Could not place control!");
    }
    return position;
  },

  redraw: function() { 
    var container = this.getListContainer();

    var bbox = this.map.getBounds();
    var zoom = this.map.getZoom();

    var appendcount = 0;
    this.vizLength = 0;
    for(var i=0,n=this.blocks.length; i<n; i++) {
      if ( typeof(this.blocks[i].filterByBounds ) != "undefined" ) { 
        this.blocks[i].filterByBounds(bbox,zoom)
      }
      
      var ci = this.blocks[i].redraw();
      if ( typeof(ci.added) == "undefined" ) {
        container.appendChild(ci);
        ci.added = true;
      }
    }
    return true;
  },

  getDefaultTitle: function() { 
    return this.defaultTitle;
  },

  setDefaultTitle: function(title,tip) { 
    this.defaultTitle = title;
    if( typeof(tip) != "undefined" ) { 
      return this.setDefaultTitleTip(tip);
    }
    return true;
  },

  getDefaultTitleTip: function() { 
    return this.defaultTitleTip;
  },

  setDefaultTitleTip: function(tip) { 
    this.defaultTitleTip = tip;
    return true;
  },

  isLoaded: function() { 
      return this.loaded;
  },

  getDefaultPosition: function() { 
      return new GControlPosition(G_ANCHOR_TOP_RIGHT,new GSize(0,0));
  },

  printable: function() { 
      return false;
  },

  selectable: function() { 
      return false;
  },

  getDefaultTitle: function() { 
      return "Layers";
  },

  show: function() { 
      for ( var i in this.items ) {
          this.items[i].show();
      }
      this.redraw();
  },

  findBlock: function(name) { 
    var block = null;
    for ( var i = 0, n = this.blocks.length; i < n; i++ ) {
      var block = this.blocks[i].findBlock(name);
      if ( block ) return block;
    }
    return block;
  },

  setOptions: function(opts) {
    if ( ! opts ) return;
    for ( var opt in opts ) {
      this[opt] = opts[opt];
    }
  },

  load: function() {
      var container = this.getListContainer();
      container.style.display = "none";

      var me = this;
      me.datasources = [];
      me.loaded = false;
      GEvent.trigger(this,'messageshow','Loading data, please wait ...','dsloader');
      try {

      GDownloadUrl(me.url,function(data,code) { 
          if( code != 200 ) { 
              me.loaded = true;
              GEvent.trigger(me,"load",false);
              return false;
          }
          GEvent.trigger(me,'dataretrieved');

          var dom = GXml.parse(data);
          var dsopts = {};

          if ( typeof(me.expandChildren) != "undefined" ) dsopts['expandChildren'] = me.expandChildren;
          if ( typeof(me["showInfoBox"]) != "undefined" ) dsopts["showInfoBox"] = me.showInfoBox;


          me.dscount = 0;
          var sources = dom.getElementsByTagName("datasource");

          GEvent.addListener(me,'dsload', function(source) {
              me.dscount += 1;
              if ( me.dscount >= sources.length ) {
                  //alert(sources.length);
                  me.redraw();
                  me.loaded = true;
                  container.style.display = "block";
                  GEvent.trigger(me,'messagehide','dsloader');
                  GEvent.trigger(me,"load",true);
              }
          });

          for (var i=0,n=sources.length; i<n; i++ ) {
              if ( me.blacklist || me.whitelist ) {
                  var titles = sources[i].getElementsByTagName("title");
                  if ( titles.length > 0 ) {
                      var title = titles[0].firstChild.nodeValue;
                      var skip = false;

                      if ( me.whitelist ) {
                          skip = true;
                          for ( var j = 0; j < me.whitelist.length; j++ ) {
                              if ( title == me.whitelist[j] ) {
                                 skip = false;
                                 break;
                              }
                          }
                      }
                      
                      for ( var j = 0; j < me.blacklist.length; j++ ) {
                          if ( title == me.blacklist[j] ) {
                             skip = true;
                             break;
                          }
                      }
                      if ( skip ) {
                          me.dscount += 1;
                          GEvent.trigger(me,'dsload');
                          continue;
                      }
                  }
              }

              var stypes = sources[i].getElementsByTagName("type");
              if ( stypes.length > 0 ) {
                  var stype = stypes[0].firstChild.nodeValue;
              }
              var otype = sources[i].getElementsByTagName("overlay");
              if ( otype.length > 0 ) {
                  otype = otype[0].firstChild.nodeValue;
              }

              var dslocs = sources[i].getElementsByTagName("href");
              if ( dslocs.length<1 ) {
                  me.dscount += 1;
                  continue;
              }
              var dsloc = dslocs[0].firstChild.nodeValue;

              var last = me.datasources.length;
              me.datasources.push(eval("new " + stype + "(me,dsloc,otype,dsopts)"));


              GEvent.addListener(me.datasources[last],'blockcreated',function(block,parent,index) {
                  me.addBlock(block);

                  if ( typeof(me.state[block.title]) != "undefined"  &&
                       me.state[block.title].selected ) {
                    GEvent.trigger(block,'blockselected');
                  }
              });

              me.datasources[last].load();
          }
      });
     } catch (error) {
      GEvent.trigger(this,'messageshow','Data could not load, please try again later.','dsloader');
     
     }
  },

  parseFormValues: function() { 
    var qs = location.href.match(/\?.*$/);
    if ( ! qs ) return false;
    qs = qs[0].substring(1);
    this.qs = {};
    var formvals = qs.split("&");
    for ( var i = 0; i < formvals.length; i++  ) {
      var parts = formvals[i].split("=");
      if ( parts.length < 2 ) continue;
      if ( parts[0].indexOf("[]") != -1 ) {
         parts[0] = rawurldecode(parts[0].replace(/\[\]/,""));
         if ( typeof(this.qs[parts[0]]) == "undefined" ) this.qs[parts[0]] = [];
         this.qs[parts[0]].push(rawurldecode(parts[1]));
      } else {
         this.qs[rawurldecode(parts[0])] = rawurldecode(parts[1]);
      }
    }

    this.stateLoadedFromUrl = true;
    return true;
  },

  loadState: function(qs) { 
    this.qs = qs;
    // load global state information
    if ( typeof(qs.lat) != "undefined" && typeof(qs.lon) != "undefined" ) {
      this.map.setCenter(new GLatLng(parseFloat(qs.lat),parseFloat(qs.lon)));
    }

    if ( typeof(qs.zoom) != "undefined" ) {
      this.map.setZoom(parseInt(qs.zoom));
    }

    var bbox = this.map.getBounds();
    var zoom = this.map.getZoom();

    if ( typeof(qs.maptype) != "undefined" ) {
      var maptype = G_SATELLITE_MAP;
      if ( qs.maptype == "p" ) maptype = G_PHYSICAL_MAP;
      if ( qs.maptype == "h" ) maptype = G_HYBRID_MAP;
      if ( qs.maptype == "m" ) maptype = G_NORMAL_MAP;
      this.map.setMapType(maptype);
    }

    for ( var i = 0; i < this.index.length; i++ ) {
       if ( this.index[i].isLoadable() ) {
         this.index[i].hide();
       }
    }

    // load layer-specific state
    for ( var i = 0; i < qs.visibleLayers.length; i++ ) {
      var block = this.findBlock(qs.visibleLayers[i]);
      if ( block ) {
        if ( block.isInView(bbox,zoom) ) {
          block.show();
          GEvent.trigger(block,'itemselected');
        }
        if ( block.title == qs.selectedLayer ) {
          block.loadState(qs);
        } else {
          while ( typeof(block.parent) != "undefined" && block.parent != null ) {
            if ( block.isInView(bbox,zoom) ) {
              block.show();
              GEvent.trigger(block,'itemselected');
            }
            block = block.parent;
            if ( block.title == qs.selectedLayer ) {
              block.loadState(qs);
            }
          }
        }
      }
    }
    this.redraw();
  },

  saveState: function() { 
    this.qs = {};
    this.qs.visibleLayers = [];
    //for ( var i = 0; i < this.index.length; i++ ) { 
    for ( var i in this.index ) { 
      if ( typeof(this.index[i].isLoadable) != "undefined" ) {
        if ( this.index[i].isLoadable() && this.index[i].isDisplayed() )
          this.qs.visibleLayers.push(this.index[i].title);
      }
    }

    if ( typeof(this.lastMarker) != "undefined" && typeof(this.lastOverlay) != "undefined" ) {
      this.qs.selectedLayer = this.lastOverlay.title;
      this.qs.selectedMarker = this.lastMarker.name;
    }

    var iw = this.map.getInfoWindow();
    this.qs.iwopen = ! iw.isHidden();
    if ( this.qs.iwopen ) {
      this.qs.visibleTab = iw.getSelectedTab();
    }
    this.qs.zoom = this.map.getZoom();
    var latlng = this.map.getCenter();
    this.qs.lat = latlng.lat();
    this.qs.lon = latlng.lng();
    this.qs.maptype = this.map.getCurrentMapType().getUrlArg();
  },

  writeBookmarkLink: function() {
    var url = "?";
    this.saveState();
    if ( typeof(this.qs.visibleLayers) != "undefined" ) {
      for ( var i = 0; i < this.qs.visibleLayers.length; i++ ) {
        url += "&visibleLayers[]=" + this.qs.visibleLayers[i];
      }
    }

    if ( typeof(this.qs.selectedLayer) != "undefined" ) {
      url += "&selectedLayer=" + this.qs.selectedLayer;
    }

    if ( typeof(this.qs.selectedMarker) != "undefined" ) {
      url += "&selectedMarker=" + this.qs.selectedMarker;
    }

    if ( typeof(this.qs.iwopen) != "undefined" ) {
      url += "&iwopen=" + (this.qs.iwopen?1:0);
    }

    if ( typeof(this.qs.visibleTab) != "undefined" ) {
      url += "&visibleTab=" + this.qs.visibleTab;
    }

    if ( typeof(this.qs.zoom) != "undefined" ) {
      url += "&zoom=" + this.qs.zoom;
    }

    if ( typeof(this.qs.lat) != "undefined" ) {
      url += "&lat=" + this.qs.lat;
    }

    if ( typeof(this.qs.lon) != "undefined" ) {
      url += "&lon=" + this.qs.lon;
    }

    if ( typeof(this.qs.maptype) != "undefined" ) {
      url += "&maptype=" + this.qs.maptype;
    }


    window.location = url;
  },

  setDefaultState: function(state) { 
    if ( this.stateLoadedFromUrl == false ) {
      this.qs = {};
      for ( var i in state ) {
        if ( typeof(this.qs[i]) == "undefined" ) {
          this.qs[i] = state[i];
        }
      }
    }
  }
});

