var calhoun; 

if (typeof(calhoun) == "undefined") calhoun={};
if (typeof(calhoun.util) == "undefined") calhoun.util = {};

// EventSource class
calhoun.util.EventSource = function EventSource(elementId) {
   this.elementId = elementId
};

var domGet = YAHOO.util.Dom.get;

// Utility functions
/* bindMethod returns a function which, when invoked, will call
 * method with obj as this.
 */
calhoun.util.bindMethod = function(obj,method) {
   return function() { return method.apply(obj, arguments) }
};

// don't replace calhoun.util.getLogger if it already exists
if (typeof(calhoun.util.getLogger) == "undefined" ) { 

    calhoun.util.getLogger = function() {
       if(typeof(console)!="undefined") {
    
    	// okay, we have a console object.  Is this firebug's or is it WebKit's?
    	// we need to check for WebKit's logger because using it has the potential
    	// to crash the browser because it uses format strings (%s) and variable numbers of arguments.
    	// and if there is a mismatch, all sorts of mysterious problems can happen.
    	var kitName = "applewebkit/";
    	var tempStr = navigator.userAgent.toLowerCase();
    	var pos = tempStr.indexOf(kitName);
    	var isAppleWebkit = (pos >= 0);
    	if (! isAppleWebkit) {
    		return calhoun.util.bindMethod(console, console.log);
    	}
       }
       // otherwise use yahoo logging
       return function(x,y,z) {
       	 var s = "";
       	 for(var i=0;i<arguments.length;i++) {
    	 	var a = arguments[i];
    		s = s+" "+a;
    	 }
       	 YAHOO.log(s); // May be a no-op but won't break anything
       }
    };
}

(function() {
   var EventSourceClass = calhoun.util.EventSource.prototype

   EventSourceClass.addListener = function addListener(eventType,listenerObj,methodName) {
      var dispatch = function(event) {
	 listenerObj[methodName](event);
      }
      YAHOO.util.Event.addListener(this.elementId,eventType,dispatch)
   }

   EventSourceClass.removeListeners = function(eventType) {
      YAHOO.util.Event.purgeElement(document.getElementById(this.elementId),false,eventType)
   }

   EventSourceClass.getPageX = function getPageX(event) {
      return YAHOO.util.Event.getPageX(event)
   }

   EventSourceClass.getPageY = function getPageY(event) {
      return YAHOO.util.Event.getPageY(event)
   }

   EventSourceClass.getSourceX = function getSourceX(event) {
       return YAHOO.util.Event.getPageX(event) - YAHOO.util.Dom.getX(this.elementId)
   }

   EventSourceClass.getSourceY = function getSourceY(event) {
      return YAHOO.util.Event.getPageY(event) - YAHOO.util.Dom.getY(this.elementId)
   }
})()
// end EventSource class

// Timer class, used for simple code profiling
calhoun.util.Timer = function() {
   this.reset()
};

(function() {
   var TimerClass = calhoun.util.Timer.prototype

   TimerClass.reset = function() {
      this.startTime = new Date().getTime()
      this.timeElapsed = 0
   }

   TimerClass.report = function(msg,doReset) {
      this.timeElapsed += new Date().getTime() - this.startTime

      msg += "; time elapsed == "+this.timeElapsed
      if (doReset) msg += " (will reset)"

      calhoun.util.getLogger()(msg);

      if (doReset) this.reset()
      else this.startTime = new Date().getTime()
   }

})()
// end Timer class

// StringBuilder class for building up strings dynamically
// This is much faster in IE than using string concatenation, and
// is about the same in Firefox
calhoun.util.StringBuilder = function() {
   this.strings = []
};

(function() {
   var StringBuilderClass = calhoun.util.StringBuilder.prototype

   StringBuilderClass.append = function(s) {
      this.strings[this.strings.length] = s
      return this
   }

   StringBuilderClass.toString = function() {
      return this.strings.join("")
   }

   StringBuilderClass.toArray = function() {
      return this.strings
   }
})()

//end StringBuilder class

// Wrapper around a function that retrieves data from the server, which can cache results
// Constructor arguments:
// - retrieveDataFunction -- function to call to get data.  This class assumes that
//   the arguments passed to hasData() or retrieveData() are the same arguments that 
//   are passed to this function, plus a callback function
// - listener -- function to call whenever this object receives and stores data.  This is
//   called with no arguments.
calhoun.util.CachingDataSource = function(retrieveDataFunction,listener) {
   this.retrieveDataFunction = retrieveDataFunction
   this.listener = listener
   this.cache = {}
};

(function() {
   var CachingDataSourceClass = calhoun.util.CachingDataSource.prototype

   CachingDataSourceClass.hasData = function(/* varargs */) {
      var cacheKey = this.constructCacheKey(arguments)
      var data = this.cache[cacheKey]
      return (data != null) && (typeof data != "undefined")
   }

   CachingDataSourceClass.getData = function(/* varargs */) {
      var cacheKey = this.constructCacheKey(arguments)
      return this.cache[cacheKey]
   }

   // Initiate server call to retrieve data, if no call with these arguments
   // is in flight
   CachingDataSourceClass.retrieveData = function(/* varargs */) {
      var log = calhoun.util.getLogger();
   	
      var cacheKey = this.constructCacheKey(arguments)
      var data = this.cache[cacheKey]

      if (typeof data == "undefined") {
	  	
	 var listenerObject = this.listenerObject
	 var listenerFunction = this.listenerFunction
	 var c = this
	 var retrieveCallback = function(data) {
	    c.cache[cacheKey ] = data
	    c.listener()
	 }
	 
	 var args = []
	 for (var i = 0;i<arguments.length;i++) {
	    args.push(arguments[i])
	 }
	 args.push(retrieveCallback)
	 this.retrieveDataFunction.apply(null,args)
      }

   }

   CachingDataSourceClass.constructCacheKey = function(args) {
      var buffer = new calhoun.util.StringBuilder()
      for (var i=0;i<args.length;i++) {
	 if (i>0) buffer.append(":")
	 buffer.append(args[i])
      }
      return buffer.toString()
   }

})()


// PopupHandler class
// Can be associated with an element.  Will catch mouse events
// from that element, then make a callback to a function to get
// the HTML to display in a popup element. element can be supplied
// as an id or as the element itself
// arguments to htmlCallback are (x,y) relative to rootElement.
calhoun.util.PopupHandler = function(rootElement,htmlCallback, config) {
   this.rootElement = rootElement
   this.htmlCallback = htmlCallback
   this.eventSource = new calhoun.util.EventSource(rootElement)

   this.popupDiv = null // Create on demand
   
   this.xOffset = 0;
   this.yOffset = 0;
   
   for (thing in config) {
       this[thing] = config[thing];
   }

   this.showPopupTimerId = -1;

   YAHOO.util.Event.addListener(this.rootElement, "mouseout", this.mouseOut, this, true);
   YAHOO.util.Event.addListener(this.rootElement, "mousemove", this.mouseMoved, this, true); 
   YAHOO.util.Event.addListener(this.rootElement, "mousedown", this.mouseDown, this, true); 
   YAHOO.util.Event.addListener(this.rootElement, "mouseup", this.mouseUp, this, true);
};

(function() {
   var PopupHandlerClass = calhoun.util.PopupHandler.prototype
   var popupDelay = .1;

   PopupHandlerClass.mouseDown = function(evt) {
      this.hidePopup();
      this.mouseIsDown = true;
   }

   PopupHandlerClass.mouseOut = function(evt) {
       this.hidePopup();
   }

   PopupHandlerClass.mouseUp = function(evt) {
       
      this.mouseMoved(evt);
      this.mouseIsDown = false;    
   }

   PopupHandlerClass.mouseMoved = function(evt) {
      this.lastMouseX = this.eventSource.getSourceX(evt);
      this.lastMouseY = this.eventSource.getSourceY(evt);
     
      if(!this.mouseIsDown) {
         this.updatePopupTimer();
      } 
   }
   
   PopupHandlerClass.showPopupTimerId = null;

   PopupHandlerClass.updatePopupTimer = function() {
      var delayId =
         setTimeout(calhoun.util.bindMethod(this,this.showPopupCallback),popupDelay * 1000);

      if (this.showPopupTimerId != null) {
            clearTimeout(this.showPopupTimerId);
        }

      this.showPopupTimerId = delayId; 

      
   };

   PopupHandlerClass.hidePopup = function() {
      if (this.showPopupTimerId != null) {
         clearTimeout(this.showPopupTimerId);
         this.showPopupTimerId = null
      } 
    
      if (this.popupDiv != null) {
         this.popupDiv.style.display = "none";
      }
   }
   
   PopupHandlerClass.showPopupCallback = function() {
      this.showPopupTimerId = null;
      this.hidePopup();

      var x = this.lastMouseX
      var y = this.lastMouseY

      var msg = this.htmlCallback(x,y)
      if (msg != null) this.showPopupText(x, y, msg);
      
   }

   PopupHandlerClass.showPopupText = function(x, y, s) {
      x += YAHOO.util.Dom.getX(this.rootElement)
      y += YAHOO.util.Dom.getY(this.rootElement)

      if (this.popupDiv == null) {
         this.popupDiv = document.createElement('div');
         document.body.appendChild(this.popupDiv)
      }
      var pd = this.popupDiv

      pd.innerHTML = s;
      pd.style.position = 'absolute';
      pd.style.left = x + 1+ this.xOffset + "px";
      pd.style.top = y+ this.yOffset + "px";
      pd.setAttribute('id','popupdiv');
      pd.style.zIndex = 200;
      pd.style.display = "block";
      pd.style.border='1px solid darkgray';
      pd.style.backgroundColor = '#80ABD7';
   }
})()

// RectSelector 
// Associated with a root element, allows dragging out of a rectangular selection
// on that element. 
// selectionCallback has the signature: function(startPoint,bounds,isMouseUp)
//    startPoint has properties (x,y)
//    bounds has properties (x,y,width,height) which the callback function can modify
//                           or zero out
//    If isMouseUp is true, the user is done dragging out the selection
// 
calhoun.util.RectSelector = function(rootElement,selectionCallback) {
   this.rootElement = rootElement
   this.selectionCallback = selectionCallback
   this.eventSource = new calhoun.util.EventSource(this.rootElement)
   this.selectionDiv = null

   YAHOO.util.Event.addListener(this.rootElement, "mousemove", this.mouseMoved, this, true); 
   YAHOO.util.Event.addListener(this.rootElement, "mousedown", this.mouseDown, this, true); 
   YAHOO.util.Event.addListener(this.rootElement, "mouseup", this.mouseUp, this, true);
   YAHOO.util.Event.addListener(this.rootElement, "mouseout", this.mouseOut, this, true);
   
   // IE specific hack: prevent the vml from being selected because
   // it makes the drag selection look ugly.

   YAHOO.util.Dom.get(this.rootElement).onselectstart = function() { return false; };

   this.lastEvent = null

};

(function() {
   var RectSelectorClass = calhoun.util.RectSelector.prototype

   RectSelectorClass.mouseDown = function(evt) {
//       if ( calhoun.util.isLeftClick(evt)){
      this.mouseIsLeft = calhoun.util.isLeftClick(evt);
      this.mouseIsDown = true;
      this.startPoint = { x: this.eventSource.getSourceX(evt), y: this.eventSource.getSourceY(evt) }
      this.lastEvent = evt
      this.updateSelection(evt)
      this.region = YAHOO.util.Region.getRegion(this.rootElement)
  // }
   }

   RectSelectorClass.mouseUp = function(evt) {
      if (this.mouseIsDown) {
	 this.mouseIsDown = false
	 this.updateSelection(evt)
      }
   }

   RectSelectorClass.mouseMoved = function(evt) {
      if (this.mouseIsDown) {
         this.updateSelection(evt)
         this.lastEvent = evt
      }
   }

   RectSelectorClass.mouseOut = function(evt) {
      if (this.mouseIsDown) {
	 var sourceX = this.eventSource.getSourceX(evt)
	 var sourceY = this.eventSource.getSourceY(evt)

	 if (sourceX < 0 || sourceY < 0 || sourceX > this.region.width || sourceY > this.region.height) {
	    this.mouseUp(this.lastEvent)	 
	 }
      }
   }

   RectSelectorClass.updateSelection = function(evt) {

      var mousePoint = { x: this.eventSource.getSourceX(evt), y: this.eventSource.getSourceY(evt) }
      
      var bounds = calhoun.util.makeRect(this.startPoint,mousePoint)
      
      this.selectionCallback(this.startPoint,bounds,!this.mouseIsDown,evt);
      
      if (bounds.width > 0 && bounds.height > 0) {
         this.showSelectionRect(bounds)
      }
      else {
         if (this.selectionDiv != null) {
            this.selectionDiv.style.display='none'
         }
      }
   }

   RectSelectorClass.showSelectionRect = function(bounds)
   {
      if (this.selectionDiv == null) {
         this.selectionDiv = document.createElement('div');
         YAHOO.util.Dom.get(this.rootElement).appendChild(this.selectionDiv);
      }
      bounds.width--;
      var pd = this.selectionDiv;
      // IE HACK: IE treats "height" like "min-height".  Use overflow to force height.
      pd.style.overflow = 'hidden';
      pd.style.display = 'block';
      pd.style.position = 'absolute';
      pd.style.left = bounds.x+"px";
      pd.style.top = bounds.y+"px" ;
      pd.style.height = bounds.height+"px";
      pd.style.width = bounds.width+"px";
      pd.style.border = '1px solid red';
      //if (!this.mouseIsDown) pd.style.background='green';
   	//else 
   	  pd.style.background='none';
   }
})()

calhoun.util.RegionTracker = function() {
    this.regions = [];
};

(function(){
	var regionTrackerClass = calhoun.util.RegionTracker.prototype;
	
	// region should have bounds:{x,y,widht,height}, target, and optionally hitsTarget callback
	regionTrackerClass.addRegion = function(region) {
		this.regions.push(region);
	};
	
	regionTrackerClass.getRegion = function(x, y) {
		var i;
		for(i=0;i<this.regions.length;i++) {
			var r = this.regions[i];
			var rb = r.bounds;
			// make sure point is within bounding box
			if(x >= rb.x && x < (rb.x + rb.width) && y >= rb.y && y < (rb.y + rb.height)) {
				// make sure point hits on actual object
				if(r.hitsTarget == null)
				return r;
				if(r.hitsTarget(r.target, x, y))
				return r;
			}
		}
		return null;
	};

	regionTrackerClass.clear = function() {
		this.regions = []
	}

}
)();


/* calcTextSize returns the width and height of a box large enough
 * to contain the specified text.  maxWidth is advisory--the actual
 * width may be greater if the text contains a long word.
 */
calhoun.util.calcTextSize = function(htmlText,maxWidth) {

   var div = document.createElement("div")
   if (typeof maxWidth != "undefined") {
      div.style.width=""+maxWidth+"px"
   }
   document.body.appendChild(div)
   YAHOO.util.Dom.setXY(div,[-1000000,-1000000])

   var span = document.createElement("span")
   span.innerHTML = htmlText
   div.appendChild(span)
   var region = YAHOO.util.Region.getRegion(span)
   document.body.removeChild(div)

   return { width:region.right-region.left, height:region.bottom-region.top }
}

calhoun.util.setElementContent = function(element,htmlText) {
   element = YAHOO.util.Dom.get(element)
   element.innerHTML=htmlText
}

// Creates an element with the specified tag name.  Attributes is an
// object whose properties will be added as attributes on the element.
// style is an object whose properties will be used to construct the style attribute
// children is an array of nodes that will be added to the element
// using appendChild()
calhoun.util.createElement = function(name,attributes,style,children) {
   var result = document.createElement(name)

   if (attributes != null && typeof attributes == "object") {
      for (var key in attributes) {
    	 result.setAttribute(key,attributes[key])
      }
   }

   if (style != null && typeof style == "object") {
      for (var key in style) {
        YAHOO.util.Dom.setStyle(result, key, style[key]);
      }
   }

   if (children != null && typeof children == "object" && children.length) {
      for (var i=0;i<children.length;i++) {
	 result.appendChild(children[i])
      }
   }

   return result
}

// Copied from the internets, why is this so complicated?
calhoun.util.getSelectedRadioValue = function(radioObj) {
   if(!radioObj)
      return "";
   var radioLength = radioObj.length;
   if(typeof radioLength == "undefined")
      if(radioObj.checked)
	 return radioObj.value;
   else
      return "";
   for(var i = 0; i < radioLength; i++) {
      if(radioObj[i].checked) {
	 return radioObj[i].value;
      }
   }
   return "";
}

calhoun.util.log = calhoun.util.getLogger();

// Takes two point objects with properties (x,y), returns a rect
// object with properties (x,y,width,height)
calhoun.util.makeRect = function(p1,p2) {
   return {
      x: Math.min(p1.x,p2.x),
      y: Math.min(p1.y,p2.y),
      width: Math.abs(p1.x-p2.x),
      height: Math.abs(p1.y-p2.y)
   }
}

calhoun.util.setElementBounds = function(e,bounds) {
   e = YAHOO.util.Dom.get(e)

   e.style.left = "" + bounds.x + "px"
   e.style.top = "" + bounds.y + "px"
   e.style.width = "" + bounds.width + "px"
   e.style.height = "" + bounds.height + "px"
   e.style.overflow="hidden"
}

calhoun.util.pointInRect = function(point,rect) {
   return point.x > rect.x && point.y > rect.y && point.x < rect.x + rect.width && point.y < rect.y + rect.height
}

calhoun.util.distanceFromPointToLine = function(px, py, lx1, ly1, lx2, ly2) {
	return Math.abs((lx2-lx1)*(ly1-py)-(lx1-px)*(ly2-ly1))/Math.sqrt(Math.pow(lx2-lx1,2)+Math.pow(ly2-ly1,2));
}

calhoun.util.intersectBoxes = function(a,b) {
	var ax0 = a.x;
	var ax1 = ax0+a.width;
	var ay0 = a.y;
	var ay1 = ay0+a.height;
	var bx0 = b.x;
	var bx1 = bx0+b.width;
	var by0 = b.y;
	var by1 = by0+b.height;
	
	var x0 = Math.max(ax0, bx0);
	var x1 = Math.min(ax1, bx1);
	var y0 = Math.max(ay0, by0);
	var y1 = Math.min(ay1, by1);
	
	var w = x1-x0;
	var h = y1-y0;
	
	if(w <= 0 || h <= 0)
		return null;
	
	return {x: x0, y: y0, width: w, height: h};
	
};

// takes two objects with a pair of points
// modifies the line object. 
calhoun.util.clipLineWithBox = function (line, bounds) {
	var lx0 = line.x0;
	var ly0 = line.y0;
	var lx1 = line.x1;
	var ly1 = line.y1;
	var bx0 = bounds.x0;
	var by0 = bounds.y0;
	var bx1 = bounds.x1;
	var by1 = bounds.y1;

	// simplify the number of cases by making sure x0 < x1
	// swapping end points if necessary
	if(lx0 > lx1) {
		var t = ly0;
		ly0 = ly1;
		ly1 = t;
		
		t = lx0;
		lx0 = lx1;
		lx1 = t;
	}
	
	var dx = (lx1-lx0);
	var dy = (ly1-ly0);

	var xy = null;
	if(dy != 0)
		xy = dx/dy;
	var xyc = lx0-xy*ly0;

	var yx = null;
	if(dx != 0)
		yx = dy/dx;
	var yxc = ly0-yx*lx0;

//	if(xy != null) {		
//		console.log("a");
//		assertEquals(lx0, xy*ly0+xyc)
//		console.log("b", xy, ly1, xyc, xy*ly1+xyc);
//		assertEquals(lx1, xy*ly1+xyc)
//	} 
//	
//	if(yx != null) {
//		console.log("c");
//		assertEquals(ly0, yx*lx0+yxc)
//		console.log("d");
//		assertEquals(ly1, yx*lx1+yxc)
//	}
//	console.log("e");
	
	if(lx0 < bx0) {
		if(lx1 < bx0) 
			return null;
			
		lx0 = bx0;
		var y = yx*bx0+yxc;
		if(yx > 0) {
			ly0 = Math.max(ly0, y);
		} else if (yx < 0) { 
			ly0 = Math.min(ly0, y);
		}
	}	
	
	if(lx1 > bx1) {
		if(lx0 > bx1) 
			return null;
			
		lx1 = bx1;
		var y = yx*bx1+yxc;
		if(yx > 0) {
			ly1 = Math.min(ly1, y);
		} else if (yx < 0) { 
			ly1 = Math.max(ly1, y);
		}
	}

	if(ly0 < by0) {
		if(ly1 < by0) // if both are outside, then there's no intersection
			return null;
			
		ly0 = by0;
		var x = xy*by0+xyc;
		if(xy > 0) {
			lx0 = Math.max(lx0, x);
		} else if (xy < 0) { 
			lx0 = Math.min(lx0, x);
		}
	}
	
	if(ly1 > by1) {
		if(ly0 > by1) 
			return null;
			
		ly1 = by1;
		var x = xy*by1+xyc;
		if(xy > 0) {
			lx1 = Math.min(lx1, x);
		} else if (xy < 0) { 
			lx1 = Math.max(lx1, x);
		}
	}

	// duplicated for cases where y1 < y0

	if(ly1 < by0) {
		ly1 = by0;
		var x = xy*by0+xyc;
		if(xy > 0) {
			lx1 = Math.max(lx1, x);
		} else if (xy < 0) { 
			lx1 = Math.min(lx1, x);
		}
	}
	
	if(ly0 > by1) {
		ly0 = by1;
		var x = xy*by1+xyc;
		if(xy > 0) {
			lx0 = Math.min(lx0, x);
		} else if (xy < 0) { 
			lx0 = Math.max(lx0, x);
		}
	}

	// if the total length of the segment has colapsed to a point,
	// (which happens when it was completely out of bounding box) 
	// return null.  (Espilon was chosen assuming integer coordinates)
	if(Math.abs(lx0 - lx1) + Math.abs(ly0 - ly1) < 0.001 )
		return null;

	line.x0 = lx0;
	line.y0 = ly0;
	line.x1 = lx1;
	line.y1 = ly1;
	
	return line;
}

calhoun.util.canvasInit = function() {
   YAHOO.log("canvasInit")
   if (typeof G_vmlCanvasManager != "undefined") {
      for (var i=0;i<arguments.length;i++) {
          YAHOO.log("initializing canvas: " + arguments[i])
         G_vmlCanvasManager.initElement(domGet(arguments[i]))
      }
   }
}

calhoun.util.setCanvasDimensions = function(c,bounds) {
   if (typeof G_vmlCanvasManager != "undefined") {
      c.style.width=""+bounds.width+"px"
      c.style.height=""+bounds.height+"px"
      c.width=bounds.width
      c.height=bounds.height
   }
   else {
      c.width = bounds.width
      c.height = bounds.height
   }
}


calhoun.util.cloneArray = function(dataArray, dimension) {
    var retVal = [];
    // clone the array at each level
    for (var i=0; i < dataArray.length; i++) {
       if (dimension > 1)
             retVal[i] = calhoun.util.cloneArray(dataArray[i], dimension-1);
       else
             retVal[i] = dataArray[i];
    }
    return retVal;
}

String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

if(!Array.indexOf){
    Array.prototype.indexOf = function(obj){
        for(var i=0; i<this.length; i++){
            if(this[i]==obj){
                return i;
            }
        }
    }
}

Array.prototype.subList = function(start, stop) {
    var returnArray = [];
    var j=0;
    for (var i=start; i < stop; i++) {
        returnArray[j] = this[i];
        j++;
    }
    return returnArray;
}

Array.prototype.addAll = function(obj) {
    for (var i=0; i < obj.length; i++) {
        this[this.length] = obj[i];
    }
}

if (window.HTMLElement != null) {
    HTMLElement.prototype.show = function() {
         YAHOO.util.Dom.setStyle(this, 'display', '');
    }
    
    HTMLElement.prototype.hide = function() {
         YAHOO.util.Dom.setStyle(this, 'display', 'none');
    }
}

// TODO: replace these with yui-ext xpath when it's available
calhoun.util.findClosestNode = function(curNodeName, targetNodeName) {
	var currentNode = domGet(curNodeName);
	if (currentNode.nodeName == targetNodeName) {
		return currentNode;
	} else {
		if (currentNode.parentNode == null) return null;
		else return findClosestNode(currentNode.parentNode, targetNodeName);
	} 
}

calhoun.util.getChildByTagName = function(parentNode, tagName) {
	children = parentNode.getElementsByTagName(tagName);
	if (children.length == 1)
		return children[0];
	return null;
}

// solution to IE borders around radio boxes, found on lloydi.com
calhoun.util.removeCheckBoxBorders = function() {
    if (navigator.userAgent.toLowerCase().indexOf("msie") > -1) {
        var el = document.getElementsByTagName("input");
        for (i=0; i < el.length; i++) {
            var type = el[i].getAttribute("type");
            if(type=="checkbox" || type=="radio") {
                YAHOO.util.Dom.setStyle(el[i], 'border', 'none');
            }
        }
    }
}

calhoun.util.toString = function(obj) {
   var append = function(obj,buf) {
      if (obj == null) {
	 buf.append("null")
      }
      else if (YAHOO.lang.isArray(obj)) {
	 buf.append("[")
	 for (var i=0;i<obj.length;i++) {
	    append(obj[i],buf)
	 }
      }
      else if (YAHOO.lang.isObject(obj)) {
	 buf.append("{")
	 for (var i in obj) {
	    append(i,buf)
	    buf.append("=")
	    append(obj[i],buf)
	    buf.append("; ")
	 }
	 buf.append("}")
      }
      else {
	 buf.append(obj)
      }
   }

   var buffer = new calhoun.util.StringBuilder()
   append(obj,buffer)
   return buffer.toString()
}

calhoun.util.toggleVisibility = function(elmId) {
	var element = domGet(elmId);
	element.style.display = element.style.display == 'none' ? '' : 'none';
}

// used to pass object references between between different components. 
calhoun.util.objectRegistry = {};

calhoun.util.constructMenu = function(container,menuId,menuItems,menuItemCallback,cfg) {
    var menuCfg = {constraintoviewport: true };
    for (key in cfg)
        menuCfg[key] = cfg[key];
    var menu = new YAHOO.widget.Menu(menuId, menuCfg);
    menu.setHeader("invisible title");	  
    for(var i=0;i<menuItems.length;i++) {
        var menuItem = menuItems[i];
        menuItem.parent = menu;
        var eventHandler = calhoun.util.bindMethod(container, menuItemCallback, menuItem);		  
        menu.addItem({text: menuItem.text,  onclick: {
            fn:menuItemCallback,
            scope:container,
            obj: menuItem}});
    }
    return menu;
}

calhoun.util.isTinyBounds = function(bounds) {
    return (bounds.width+bounds.height) <= 3;
}

calhoun.util.isLeftClick = function(evt){
       if (evt.which == null){
            return evt.button < 2;
       } 
       return evt.which < 2;
}


calhoun.util.getColors = function(){
    // todo -- make some more color choices
    // Note: IE can only understand colors in this triple format
return [ "#3333CC","#FF6600","#66CC00","#CC00CC","#CC9900","#CC0000","#0099CC","#FF66FF","#996633","#009933","#FFCC00","#6666CC" ];
}

calhoun.util.assignColors = function(objects){
    var colorChoices = calhoun.util.getColors();
    for (var i=0;i<objects.length;i++) {
       objects[i].color = colorChoices[i%colorChoices.length]
    }
}

calhoun.util.BLACK  = "#000000";
calhoun.util.GRAY   = "#CCCCCC";
calhoun.util.LIGHT_GRAY = "#666666";
calhoun.util.RED    = "#FF0000";
calhoun.util.ORANGE = "#FFA500";

calhoun.util.colorBox = function(color,size){
    return "<div class=\"clear\" style=\"background:" + color + "; height:" + size + "px; width:" + size + "px; margin-top:1px; margin-left:2px; margin-right:2px;\" ></div>";
}

calhoun.util.getCursor = function(evt){
    var target = evt.target != null ? evt.target : evt.srcElement;
    return target.style.cursor;
}

calhoun.util.setCursor = function (target,cursor){
    //'-moz-grabbing'
    //var target = evt.target != null ? evt.target : evt.srcElement;
    target.style.cursor=cursor;
}


calhoun.util.addFeatureGlyph = function(g,bounds,strand,orientation) {
    var shaft = 4;
    if ( orientation == 'x' && strand == '+' ) {
      g.moveTo(bounds.x,bounds.y);
      g.lineTo(bounds.x+bounds.width-shaft,bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y+(bounds.height/2));
      g.lineTo(bounds.x+bounds.width-shaft,bounds.y+bounds.height);
      g.lineTo(bounds.x,bounds.y+bounds.height);
    } else if ( orientation == 'x' && strand == '-' ) {
      g.moveTo(bounds.x,bounds.y+(bounds.height/2));
      g.lineTo(bounds.x+shaft,bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y+bounds.height);
      g.lineTo(bounds.x+shaft,bounds.y+bounds.height);
    } else if ( orientation == 'y' && strand == '+' ) {
      g.moveTo(bounds.x,bounds.y+shaft);
      g.lineTo(bounds.x+(bounds.width/2),bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y+shaft);
      g.lineTo(bounds.x+bounds.width,bounds.y+bounds.height);
      g.lineTo(bounds.x,bounds.y+bounds.height);
    } else if ( orientation == 'y' && strand == '-' ) {
      g.moveTo(bounds.x,bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y);
      g.lineTo(bounds.x+bounds.width,bounds.y+bounds.height-shaft);
      g.lineTo(bounds.x+(bounds.width/2),bounds.y+bounds.height);
      g.lineTo(bounds.x,bounds.y+bounds.height-shaft);
    }
    g.closePath()
}


calhoun.util.addSubpathForBounds = function(g,bounds) {
		g.moveTo(bounds.x,bounds.y)
		g.lineTo(bounds.x+bounds.width,bounds.y)
		g.lineTo(bounds.x+bounds.width,bounds.y+bounds.height)
		g.lineTo(bounds.x,bounds.y+bounds.height)
		g.closePath()
	}


calhoun.util.assemblyLabelFromId = function(id) {
    var name = id;
    name = name.replace(/\..+/,"");
    name = name.replace(/\_/g,"");
    if ( name.length > 5){
        name = name.substring(0,5);
    }
    return name.toUpperCase();
}


calhoun.util.verticalizeText = function(horizontalString){
    return horizontalString.replace(/(\w)/g,"$1<br />");
}


calhoun.util.popup = function(url,width,height){
    var w = width;
    var h = height;
    var left = (screen.width) ? (screen.width-w)/2 : 0;
    var top  = (screen.height) ? (screen.height-h)/2 : 0;
    var newwindow=window.open(url,'name','scrollbars=1,resizable=1,height=' + h + ',width=' + w + ',left=' + left + ',top=' + top);
    if (window.focus) {
        newwindow.focus();
     }
     return false;
}

// The idea was to use this to go to a particular page of documentation in a site using frames.
// But it doesn't actually work on external URLs due to browser security constraints.
calhoun.util.newFramedWindow = function(url,pageFrames){

    var newwindow=window.open(url,'name2', "location=1,status=1,scrollbars=1,resizable=1,width=800,height=600");
    if (window.focus) {
        newwindow.focus();
     }
     for (frameName in pageFrames) {
          newwindow[frameName].location = pageFrames[frameName];
     }
     return false;
}

calhoun.util.attachSearchFormContainer = function(controller,searchFormContainerId,helpHyperText, helpUrl){
        var htmlBuf = new calhoun.util.StringBuilder();
	var searchBoxId    = YAHOO.util.Dom.generateId();
	var searchButtonId = YAHOO.util.Dom.generateId();
        var searchFormId   = YAHOO.util.Dom.generateId();      
  	htmlBuf.append("<form  name='" + searchFormId +"' id='" + searchFormId + "' >");
        htmlBuf.append("<input style=\"font-size:10px;\" type='text' size='40' name='"+ searchBoxId + "' id='"+ searchBoxId + "' value='' />");
	htmlBuf.append("<input style=\"font-size:10px;\" type='submit' name='"+ searchButtonId + "' id='"+ searchButtonId + "' value='search' />&nbsp;&nbsp;<a target=\"new\" href=\"");
        htmlBuf.append(helpUrl);
        htmlBuf.append("\" onClick=\"");
        htmlBuf.append("return calhoun.util.popup('");
        htmlBuf.append(helpUrl);
        htmlBuf.append("',700,700)\" >");
        htmlBuf.append(helpHyperText);
        htmlBuf.append("</a></form>");
        controller.searchFormContainer =  YAHOO.util.Dom.get(searchFormContainerId);
        controller.searchFormContainer.innerHTML=htmlBuf.toString()
        controller.searchForm   =  YAHOO.util.Dom.get(searchFormId);
        controller.searchBox    =  YAHOO.util.Dom.get(searchBoxId);
        controller.searchButton =  YAHOO.util.Dom.get(searchButtonId); 
        YAHOO.util.Event.on(controller.searchForm,"submit",controller.performSearch,controller,true);
}



calhoun.util.Range = function(start, stop) {
    this.start = start;
    this.stop = stop;
};

(function() {
    var RangeClass = calhoun.util.Range.prototype
     
    RangeClass.setStart = function(start) {
        this.start = start;
    }
    RangeClass.setStop = function(stop) {
        this.stop = stop;
    }
    RangeClass.isSet = function() {
        return this.start != null && this.stop != null;
    }
    RangeClass.equals = function(other) {
        return this.start == other.start && this.stop == other.stop;
    }
    
})()

// end Utility functions
