text: define(["dojo/_base/kernel","dojo/_base/lang","dojo/_base/connect","dojo/_base/array","dojo/_base/event",
  	"dojo/_base/fx","dojo/_base/window","dojo/fx","dojo/dom","dojo/dom-class",
  	"dojo/dom-geometry","dojo/dom-style","dijit/_base/manager","dijit/_Widget","dijit/_TemplatedMixin",
  	"dojo/_base/declare"], function (
  	kernel, lang, connect, arrayUtil, eventUtil, fxBase, windowBase, fxUtil, 
  	domUtil, domClass, domGeometry, domStyle, manager, Widget, TemplatedMixin, declare) {
  
  kernel.experimental("dojox.layout.ResizeHandle");
  
  var _ResizeHelper = declare("dojox.layout._ResizeHelper", Widget, {
  	// summary:
  	//		A global private resize helper shared between any
  	//		`dojox.layout.ResizeHandle` with activeSizing off.
  	
  	show: function(){
  		// summary:
  		//		show helper to start resizing
  		domStyle.set(this.domNode, "display", "");
  	},
  	
  	hide: function(){
  		// summary:
  		//		hide helper after resizing is complete
  		domStyle.set(this.domNode, "display", "none");
  	},
  	
  	resize: function(/* Object */dim){
  		// summary:
  		//		size the widget and place accordingly
  		domGeometry.setMarginBox(this.domNode, dim);
  	}
  	
  });
  
  var ResizeHandle = declare("dojox.layout.ResizeHandle",[Widget, TemplatedMixin],
  	{
  	// summary:
  	//		A draggable handle used to resize an attached node.
  	//
  	// description:
  	//		The handle on the bottom-right corner of FloatingPane or other widgets that allows
  	//		the widget to be resized.
  	//		Typically not used directly.
  
  	// targetId: String
  	//		id of the Widget OR DomNode that I will size
  	targetId: "",
  	
  	// targetContainer: DomNode
  	//		over-ride targetId and attch this handle directly to a reference of a DomNode
  	targetContainer: null,
  	
  	// resizeAxis: String
  	//		one of: x|y|xy limit resizing to a single axis, default to xy ...
  	resizeAxis: "xy",
  	
  	// activeResize: Boolean
  	//		if true, node will size realtime with mouse movement,
  	//		if false, node will create virtual node, and only resize target on mouseUp
  	activeResize: false,
  	
  	// activeResizeClass: String
  	//		css class applied to virtual resize node.
  	activeResizeClass: "dojoxResizeHandleClone",
  	
  	// animateSizing: Boolean
  	//		only applicable if activeResize = false. onMouseup, animate the node to the
  	//		new size                
  	animateSizing: true,
  	
  	// animateMethod: String
  	//		one of "chain" or "combine" ... visual effect only. combine will "scale"
  	//		node to size, "chain" will alter width, then height
  	animateMethod: "chain",
  
  	// animateDuration: Integer
  	//		time in MS to run sizing animation. if animateMethod="chain", total animation
  	//		playtime is 2*animateDuration
  	animateDuration: 225,
  
  	// minHeight: Integer
  	//		smallest height in px resized node can be
  	minHeight: 100,
  
  	// minWidth: Integer
  	//		smallest width in px resize node can be
  	minWidth: 100,
  
  	// constrainMax: Boolean
  	//		Toggle if this widget cares about the maxHeight and maxWidth
  	//		parameters.
  	constrainMax: false,
  
  	// maxHeight: Integer
  	//		Largest height size in px the resize node can become.
  	maxHeight:0,
  	
  	// maxWidth: Integer
  	//		Largest width size in px the resize node can become.
  	maxWidth:0,
  
  	// fixedAspect: Boolean
  	//		Toggle to enable this widget to maintain the aspect
  	//		ratio of the attached node.
  	fixedAspect: false,
  
  	// intermediateChanges: Boolean
  	//		Toggle to enable/disable this widget from firing onResize
  	//		events at every step of a resize. If `activeResize` is true,
  	//		and this is false, onResize only fires _after_ the drop
  	//		operation. Animated resizing is not affected by this setting.
  	intermediateChanges: false,
  
  	// startTopic: String
  	//		The name of the topic this resizehandle publishes when resize is starting
  	startTopic: "/dojo/resize/start",
  	
  	// endTopic: String
  	//		The name of the topic this resizehandle publishes when resize is complete
  	endTopic:"/dojo/resize/stop",
  
  	templateString: '<div dojoAttachPoint="resizeHandle" class="dojoxResizeHandle"><div></div></div>',
  
  	postCreate: function(){
  		// summary:
  		//		setup our one major listener upon creation
  		this.connect(this.resizeHandle, "onmousedown", "_beginSizing");
  		if(!this.activeResize){
  			// there shall be only a single resize rubberbox that at the top
  			// level so that we can overlay it on anything whenever the user
  			// resizes something. Since there is only one mouse pointer he
  			// can't at once resize multiple things interactively.
  			this._resizeHelper = manager.byId('dojoxGlobalResizeHelper');
  			if(!this._resizeHelper){
  				this._resizeHelper = new _ResizeHelper({
  						id: 'dojoxGlobalResizeHelper'
  				}).placeAt(windowBase.body());
  				domClass.add(this._resizeHelper.domNode, this.activeResizeClass);
  			}
  		}else{ this.animateSizing = false; }
  
  		if(!this.minSize){
  			this.minSize = { w: this.minWidth, h: this.minHeight };
  		}
  		
  		if(this.constrainMax){
  			this.maxSize = { w: this.maxWidth, h: this.maxHeight };
  		}
  		
  		// should we modify the css for the cursor hover to n-resize nw-resize and w-resize?
  		this._resizeX = this._resizeY = false;
  		var addClass = lang.partial(domClass.add, this.resizeHandle);
  		switch(this.resizeAxis.toLowerCase()){
  			case "xy" :
  				this._resizeX = this._resizeY = true;
  				// FIXME: need logic to determine NW or NE class to see
  				// based on which [todo] corner is clicked
  				addClass("dojoxResizeNW");
  				break;
  			case "x" :
  				this._resizeX = true;
  				addClass("dojoxResizeW");
  				break;
  			case "y" :
  				this._resizeY = true;
  				addClass("dojoxResizeN");
  				break;
  		}
  	},
  
  	_beginSizing: function(/*Event*/ e){
  		// summary:
  		//		setup movement listeners and calculate initial size
  		
  		if(this._isSizing){ return; }
  
  		connect.publish(this.startTopic, [ this ]);
  		this.targetWidget = manager.byId(this.targetId);
  
  		this.targetDomNode = this.targetWidget ? this.targetWidget.domNode : domUtil.byId(this.targetId);
  		if(this.targetContainer){ this.targetDomNode = this.targetContainer; }
  		if(!this.targetDomNode){ return; }
  
  		if(!this.activeResize){
  			var c = domGeometry.position(this.targetDomNode, true);
  			this._resizeHelper.resize({l: c.x, t: c.y, w: c.w, h: c.h});
  			this._resizeHelper.show();
  			if(!this.isLeftToRight()){
  				this._resizeHelper.startPosition = {l: c.x, t: c.y};
  			}
  		}
  
  		this._isSizing = true;
  		this.startPoint  = { x:e.clientX, y:e.clientY };
  
  		// widget.resize() or setting style.width/height expects native box model dimension 
  		// (in most cases content-box, but it may be border-box if in backcompact mode)
  		var style = domStyle.getComputedStyle(this.targetDomNode), 
  			borderModel = domGeometry.boxModel==='border-model',
  			padborder = borderModel?{w:0,h:0}:domGeometry.getPadBorderExtents(this.targetDomNode, style),
  			margin = domGeometry.getMarginExtents(this.targetDomNode, style);
  		this.startSize = { 
  				w: domStyle.get(this.targetDomNode, 'width', style), 
  				h: domStyle.get(this.targetDomNode, 'height', style),
  				//ResizeHelper.resize expects a bounding box of the
  				//border box, so let's keep track of padding/border
  				//width/height as well
  				pbw: padborder.w, pbh: padborder.h,
  				mw: margin.w, mh: margin.h};
  		if(!this.isLeftToRight() && domStyle.get(this.targetDomNode, "position") == "absolute"){
  			var p = domGeometry.position(this.targetDomNode, true);
  			this.startPosition = {l: p.x, t: p.y};
  		}
  		
  		this._pconnects = [
  			connect.connect(windowBase.doc,"onmousemove",this,"_updateSizing"),
  			connect.connect(windowBase.doc,"onmouseup", this, "_endSizing")
  		];
  		
  		eventUtil.stop(e);
  	},
  
  	_updateSizing: function(/*Event*/ e){
  		// summary:
  		//		called when moving the ResizeHandle ... determines
  		//		new size based on settings/position and sets styles.
  
  		if(this.activeResize){
  			this._changeSizing(e);
  		}else{
  			var tmp = this._getNewCoords(e, 'border', this._resizeHelper.startPosition);
  			if(tmp === false){ return; }
  			this._resizeHelper.resize(tmp);
  		}
  		e.preventDefault();
  	},
  
  	_getNewCoords: function(/* Event */ e, /* String */ box, /* Object */startPosition){
  		
  		// On IE, if you move the mouse above/to the left of the object being resized,
  		// sometimes clientX/Y aren't set, apparently.  Just ignore the event.
  		try{
  			if(!e.clientX  || !e.clientY){ return false; }
  		}catch(err){
  			// sometimes you get an exception accessing above fields...
  			return false;
  		}
  		this._activeResizeLastEvent = e;
  
  		var dx = (this.isLeftToRight()?1:-1) * (this.startPoint.x - e.clientX),
  			dy = this.startPoint.y - e.clientY,
  			newW = this.startSize.w - (this._resizeX ? dx : 0),
  			newH = this.startSize.h - (this._resizeY ? dy : 0),
  			r = this._checkConstraints(newW, newH)
  		;
  		
  		startPosition = (startPosition || this.startPosition);
  		if(startPosition && this._resizeX){
  			// adjust x position for RtoL
  			r.l = startPosition.l + dx;
  			if(r.w != newW){
  				r.l += (newW - r.w);
  			}
  			r.t = startPosition.t;
  		}
  
  		switch(box){
  			case 'margin':
  				r.w += this.startSize.mw;
  				r.h += this.startSize.mh;
  				//pass through
  			case "border":
  				r.w += this.startSize.pbw;
  				r.h += this.startSize.pbh;
  				break;
  			//default: //native, do nothing
  		}
  
  		return r; // Object
  	},
  	
  	_checkConstraints: function(newW, newH){
  		// summary:
  		//		filter through the various possible constaint possibilities.
  				
  		// minimum size check
  		if(this.minSize){
  			var tm = this.minSize;
  			if(newW < tm.w){
  				newW = tm.w;
  			}
  			if(newH < tm.h){
  				newH = tm.h;
  			}
  		}
  		
  		// maximum size check:
  		if(this.constrainMax && this.maxSize){
  			var ms = this.maxSize;
  			if(newW > ms.w){
  				newW = ms.w;
  			}
  			if(newH > ms.h){
  				newH = ms.h;
  			}
  		}
  		
  		if(this.fixedAspect){
  			var w = this.startSize.w, h = this.startSize.h,
  				delta = w * newH - h * newW;
  			if(delta<0){
  				newW = newH * w / h;
  			}else if(delta>0){
  				newH = newW * h / w;
  			}
  		}
  		
  		return { w: newW, h: newH }; // Object
  	},
  		
  	_changeSizing: function(/*Event*/ e){
  		// summary:
  		//		apply sizing information based on information in (e) to attached node
  		
  		var isWidget = this.targetWidget && lang.isFunction(this.targetWidget.resize),
  			tmp = this._getNewCoords(e, isWidget && 'margin');
  		if(tmp === false){ return; }
  
  		if(isWidget){
  			this.targetWidget.resize(tmp);
  		}else{
  			if(this.animateSizing){
  				var anim = fxUtil[this.animateMethod]([
  					fxBase.animateProperty({
  						node: this.targetDomNode,
  						properties: {
  							width: { start: this.startSize.w, end: tmp.w }
  						},
  						duration: this.animateDuration
  					}),
  					fxBase.animateProperty({
  						node: this.targetDomNode,
  						properties: {
  							height: { start: this.startSize.h, end: tmp.h }
  						},
  						duration: this.animateDuration
  					})
  				]);
  				anim.play();
  			}else{
  				domStyle.set(this.targetDomNode,{
  					width: tmp.w + "px",
  					height: tmp.h + "px"
  				});
  			}
  		}
  		if(this.intermediateChanges){
  			this.onResize(e);
  		}
  	},
  
  	_endSizing: function(/*Event*/ e){
  		// summary:
  		//		disconnect listenrs and cleanup sizing
  		arrayUtil.forEach(this._pconnects, connect.disconnect);
  		var pub = lang.partial(connect.publish, this.endTopic, [ this ]);
  		if(!this.activeResize){
  			this._resizeHelper.hide();
  			this._changeSizing(e);
  			setTimeout(pub, this.animateDuration + 15);
  		}else{
  			pub();
  		}
  		this._isSizing = false;
  		this.onResize(e);
  	},
  	
  	onResize: function(e){
  		// summary:
  		//		Stub fired when sizing is done. Fired once
  		//		after resize, or often when `intermediateChanges` is
  		//		set to true.
  	}
  	
  });
  
  return ResizeHandle;
  });
  