//---------------------------------------------------------------------------
// TOCNR
//   a toc with no "root" node, if you visually prefer to eliminate the
//   root node and the first column of branch connecting lines
// sample usage:
//   var toc = new TOCNR('LAYERS','unused root caption',true,'swatch_layers.gif');
//---------------------------------------------------------------------------
function TOCNR(title,caption,autoRefreshMap,swatch) {
  var toc = new TOC(title,caption,autoRefreshMap,swatch);
	inherit(this,toc);

	// override GROUP writeHTML for toc.root
	this.root.writeHTML = function(child_shim, sibling_shim) {
		var s = "";
		for (var i=0, n=this.items.length; i<n; i++) {
			s += this.items[i].writeHTML('','');
		}
		return s;
	};

	return this;
}


//---------------------------------------------------------------------------
// LAYERSI
//   a layer with a "swatch" as it's icon.  in other words, the swatch
//   image is drawn where the layer icon would otherwise be drawn, perhaps
//   to save horizontal space in the toc.
//
// usage:
//   toc.addLayer( new LAYERSI('Highways',null,'swatch_highways.gif','legend_streets.gif') );
//---------------------------------------------------------------------------
function LAYERSI(name,caption,swatch,legend,labelField) {
	var lyr = new LAYER(name,caption,swatch,legend,labelField);
	inherit(this,lyr);

	// override LAYER init
	this.init = function() {
		this.zuper.init();
		this.index = this.zuper.index; // primitive hack
		this.icon = this.swatch;
		this.swatch = null;
		this.onIconClick = this.onSwatchClick;
	}

	return this;
}


//---------------------------------------------------------------------------
// LAYERAL
//   a layer whose icon image indicates its active layer status.  when the
//   layer is active a custom icon is used.  makes the most sense if all
//   feature layers share this style (not just one).  you may then wish to
//   remove the highlight of the active layer line.
//
// usage:
//   toc.addLayer( new LAYERAL('Highways',null,'swatch_highways.gif','legend_streets.gif') );
//---------------------------------------------------------------------------
function LAYERAL(name,caption,swatch,legend,labelField) {
	var lyr = new LAYER(name,caption,swatch,legend,labelField);
	inherit(this,lyr);

	// override LAYER init
	this.init = function() {
		this.zuper.init();
		this.index = this.zuper.index; // primitive hack
		this.iconInactive = this.icon;
		this.iconActive = _cache.loadIcon("icon_layer_active.gif");
	}

	this.writeHTML = function(child_shim, sibling_shim) {
		this.zuper.icon = ((this.index == ActiveLayerIndex) ? this.iconActive : this.iconInactive);
		return this.zuper.writeHTML(child_shim, sibling_shim);
	} 

	return this;
}

//---------------------------------------------------------------------------
// LAYERWS
//   a layer with a "shadow" layer.  the "shadow" layer is not shown in the
//   toc, but it's visibility is controlled synchronously with the parent
//   layer's visibility.  only the parent layer may be set active, as with
//   standard layers.  useful for creating a pair of layers, where one
//   contains the real data for query/identify/select, and the other (shadow)
//   is just auxilliary features, in particular it was created with a
//   feature+anno layer pair in mind.  does NOT enforce initial state of
//   all-or-none visible, that's controled by your mapservice.
//   
// usage:
//   create the layer and keep the reference (as done for groups) then use
//   the addShadow() method to add another fully specified layer object:
//
//   var lyrThe = toc.addLayer( new LAYERWS('Theaters',null,'swatch_theaters.gif') );
//     lyrThe.addShadow( new LAYER('Agencies',null,'swatch_agencies.gif') );
//---------------------------------------------------------------------------
function LAYERWS(name,caption,swatch,legend,labelField) {
	var lyr = new LAYER(name,caption,swatch,legend,labelField);
	inherit(this,lyr);
	this.shadow = null;

	// override LAYER init
	this.init = function() {
		this.zuper.init();
		this.index = this.zuper.index; // primitive hack
		if (this.shadow)
			this.shadow.init(); // must manually init shadow since not known in toc
	}

	this.addShadow = function(shadow) {
		this.shadow = shadow;
	}

	this.setVisible = function(value) {
		LayerVisible[this.index] = value;
		if (this.shadow)
			LayerVisible[this.shadow.index] = value;
	}

	this.toggleVisible = function() {
		LayerVisible[this.index] = 1 - LayerVisible[this.index];
		if (this.shadow)
			LayerVisible[this.shadow.index] = 1 - LayerVisible[this.shadow.index];
	}

	return this;
}


//---------------------------------------------------------------------------
// GROUPVL
//   a group that acts like a virtual layer - it can't be opened
//   and all layer visiblity is synchronized, either all
//   visible or all invisible.  no active layer control provided.
//   most useful with imagery since active layer control is absent
//   (or with feature layers that aren't intended to ever be
//   selected as the active layer).  for instance, individual tiles
//   of aerial photographs to be treated as a single aggregate
//   layer, a set of feature layers containing only label renderers
//   grouped in a single "annotation" virtual layer, etc.  assumes
//   that all items in the group are LAYERS, doesn't support nested
//   groups.  does NOT enforce initial state of all-or-none visible,
//   that's controled by your mapservice.
// sample usage:
//     var grpPri = grpLoc.addGroup( new GROUPVL('Private',true,'swatch_theaters_agencies.gif') );
//---------------------------------------------------------------------------

function GROUPVL(caption,opened,swatch) {
  var group = new GROUP(caption,opened,swatch);
	inherit(this,group);

	this.opened = false;

	// override GROUP toggleOpened
	//
	this.toggleOpened = function() {
		this.opened = false;
	};

	// use a custom icon (since the folder icon would be
	// confusing if you can't actually open it)
	//
	this.iconOpened = _cache.loadIcon("icon_groupvl.gif");
	this.iconClosed = this.iconOpened;

	return this;
}



//---------------------------------------------------------------------------
// GROUP1
//   a group that only allows (and forces) exactly one layer to be visible.
//   for instance, within a thematic group of layers that the user cannot
//   turn off but are only logically viewed one at a time, either because
//   they obscure each other or cause other map interpretation problems.
//   such as historical aerial photography layers, fire districts vs school
//   districts vs police districts all drawn as filled polygons and
//   completely covering aoi, etc.  assumes that all items in the group
//   are LAYERS, doesn't support nested groups.  does NOT enforce initial
//   state of all-or-none visible, that's controled by your mapservice.
// sample usage:
// 	   var grpBas = toc.addGroup( new GROUP1('Base Map',true) );
//---------------------------------------------------------------------------

function GROUP1(caption,opened,swatch) {
  var group = new GROUP(caption,opened,swatch);
	inherit(this,group);

	// override GROUP getVisible
	//
	
	this.getVisible = function() {
		return 1;  // always indicate visible
	};

	
	// override GROUP setVisible
	//
	this.setVisible = function(value) {
		// nop
	};
	
	// override GROUP init
	//
	this.init = function() {
		this.zuper.init();
		// override LAYER toggleVisible
		//
		var ltv = function() {
		  this.parent.zuper.setVisible(0); // hide all layers in this group
			this.setVisible(1); // show just the one clicked, thus exclusive
		}
		for (var i=0, n=this.items.length; i<n; i++) {
			this.items[i].toggleVisible = ltv;
		}
	}

  return this;
}


//---------------------------------------------------------------------------
// GROUP01
//   a group that only allows zero or one layers to be visible.
//   similar to GROUP1 as describe above, except that it supports the
//   all-layers-are-hidden state.  a bit trickier than GROUP1 due to
//   special handling necessary to overcome tristate conditions.
// sample usage:
// 	   var grpBas = toc.addGroup( new GROUP01('Base Map',true) );
//---------------------------------------------------------------------------

function GROUP01(caption,opened,swatch) {
  var group = new GROUP(caption,opened,swatch);
	inherit(this,group);

	// override GROUP getVisible
	//
	this.getVisible = function() {
	  var gvr = this.zuper.getVisible();
		return (gvr==0) ? 0 : 1;  // never return tri-state condition
	};

	// override GROUP setVisible
	//
	this.setVisible = function(value) {
		if (value==0) { // hide, simple case
			this.zuper.setVisible(0);
		} else { // show, tricky case
		  var gvr = this.zuper.getVisible();
			if (gvr==0) { // currently all layers hidden, so show only first one
				this.getItem(0).toggleVisible();
			} // else some number of layers already visible (hopefully only one), so do nothing
		}
	};

	// override GROUP init
	//
	this.init = function() {
		this.zuper.init();
		// override LAYER toggleVisible
		//
		var ltv = function() {
  		var wasVisible = (this.getVisible() == 1); // current visible state of layer
  		this.parent.setVisible(0); // hide all layers in this group
  		if (!wasVisible) this.setVisible(1); // show this layer *IFF* it wasn't visible before
		}
		for (var i=0, n=this.items.length; i<n; i++) {
			this.items[i].toggleVisible = ltv;
		}
	}

  return this;
}


//---------------------------------------------------------------------------
// GROUPNV
//   a group with no visibility checkbox - all visibility toggling
//   must be done at the LAYER level.
// sample usage:
//     var grpPri = grpLoc.addGroup( new GROUPNV('Private',true,'swatch_theaters_agencies.gif') );
//---------------------------------------------------------------------------

function GROUPNV(caption,opened,swatch) {
  var group = new GROUP(caption,opened,swatch);
	inherit(this,group);

	this.writeHTML = function(child_shim, sibling_shim) {
		var s = "";
		// START OF GROUP ROW
		s += '<TR><TD NOWRAP VALIGN="TOP">';
		// FOLDER ICON
		s += child_shim;
		if (this.opened) {
			s += '<IMG SRC="' + this.iconOpened.src + '"' + _cache.strIconSize + ' onmousedown="t.toc.onIconClick(' + this.tocid + ');" alt="Click to close">';
		} else {
			s += '<IMG SRC="' + this.iconClosed.src + '"' + _cache.strIconSize + ' onmousedown="t.toc.onIconClick(' + this.tocid + ');" alt="Click to open">';
		}
		// SWATCH IMAGE
		if (this.swatch != null) {
			s += '<IMG SRC="' + this.swatch.src + '"' + _cache.strIconSize + ' onmousedown="t.toc.onSwatchClick(' + this.tocid + ');" alt="">';
		}
		// GROUP CAPTION
		s += '<A HREF="javascript:t.toc.onCaptionClick(' + this.tocid + ')">' + this.caption + '</A>';
		// END OF GROUP ROW
		s += '</TD></TR>';
		// CASCADE
		if (this.opened) {
			for (var i=0, n=this.items.length; i<n; i++) {
				var new_child_shim = sibling_shim + '<img src="' +
					((i==n-1) ? _cache.iconChildLast.src : _cache.iconChild.src) + '"' + _cache.strIconSize + '>';
				var new_sibling_shim = sibling_shim + '<img src="' + 
					((i==n-1) ? _cache.iconBlank.src : _cache.iconSibling.src) + '"' + _cache.strIconSize + '>';
				s += this.items[i].writeHTML( new_child_shim, new_sibling_shim );
			}
		}
		return s;
	}

	return this;
}


//---------------------------------------------------------------------------
// UTILITY
//---------------------------------------------------------------------------

function inherit(sub,zuper) {
	sub.zuper = zuper;
	for (var i in zuper) {
		sub[i] = zuper[i];
	}
	return sub;
}

//-----------------
// eof
//-----------------



