define(["require", "dojo/_base/lang", "dojo/_base/declare", "dojo/has", "dojo/on", "dojo/Deferred", "dojo/when",
	"dojo/dom-style", "../Controller", "../utils/constraints"],
	function(require, lang, declare, has, on, Deferred, when, domStyle, Controller, constraints){

	var transit;
	var MODULE = "app/controllers/Transition";
	var LOGKEY = "logTransitions:";

	// module:
	//		dojox/app/controllers/Transition
	//		Bind "app-transition" event on dojox/app application instance.
	//		Do transition from one view to another view.
	return declare("dojox.app.controllers.Transition", Controller, {

		proceeding: false,

		waitingQueue:[],

		constructor: function(app, events){
			// summary:
			//		bind "app-transition" event on application instance.
			//
			// app:
			//		dojox/app application instance.
			// events:
			//		{event : handler}
			this.events = {
				"app-transition": this.transition,
				"app-domNode": this.onDomNodeChange
			};
			require([this.app.transit || "dojox/css3/transit"], function(t){
				transit = t;
			});
			if(this.app.domNode){
				this.onDomNodeChange({oldNode: null, newNode: this.app.domNode});
			}
		},

		transition: function(event){
			// summary:
			//		Response to dojox/app "app-transition" event.
			//
			// example:
			//		Use emit to trigger "app-transition" event, and this function will response to the event. For example:
			//		|	this.app.emit("app-transition", {"viewId": viewId, "opts": opts});
			//
			// event: Object
			//		"app-transition" event parameter. It should be like: {"viewId": viewId, "opts": opts}
			var F = MODULE+":transition";
			this.app.log(LOGKEY,F," ");
			this.app.log(LOGKEY,F,"New Transition event.viewId=["+event.viewId+"]");
			this.app.log(F,"event.viewId=["+event.viewId+"]","event.opts=",event.opts);

			var viewsId = event.viewId || "";
			this.proceedingSaved = this.proceeding;	
			var parts = viewsId.split('+');
			var removePartsTest = viewsId.split('-');
			var viewId, newEvent;
			if(parts.length > 0 || removePartsTest.length > 0){
				while(parts.length > 1){ 	
					viewId = parts.shift();
					newEvent = lang.clone(event);
					if(viewId.indexOf("-") >= 0){ // there is a remove
						var removeParts = viewId.split('-');
						if(removeParts.length > 0){
							viewId = removeParts.shift();
							if(viewId){
								newEvent._removeView = false;
								newEvent.viewId = viewId;
								this.proceeding = true;
								this.proceedTransition(newEvent);
								newEvent = lang.clone(event);
							}
							viewId = removeParts.shift();
							if(viewId){
								newEvent._removeView = true;
								newEvent.viewId = viewId;
								this.proceeding = true;
								this.proceedTransition(newEvent);
							}
						}
					}else{
						newEvent._removeView = false;
						newEvent.viewId = viewId;
						this.proceeding = true;
						this.proceedTransition(newEvent);
					}
				}
				viewId = parts.shift();
				var removeParts = viewId.split('-');
				if(removeParts.length > 0){
					viewId = removeParts.shift();
				}
				if(viewId.length > 0){ // check viewId.length > 0 to skip this section for a transition with only -viewId
					this.proceeding = this.proceedingSaved;
					event.viewId = viewId;
					event._doResize = true; // at the end of the last transition call resize
					event._removeView = false;
					this.proceedTransition(event);
				}
				if(removeParts.length > 0){
					while(removeParts.length > 0){
						var remViewId = removeParts.shift();
						newEvent = lang.clone(event);
						newEvent.viewId = remViewId;
						newEvent._removeView = true;
						newEvent._doResize = true; // at the end of the last transition call resize
						this.proceedTransition(newEvent);
					}
				}
			}else{
				event._doResize = true; // at the end of the last transition call resize
				event._removeView = false;
				this.proceedTransition(event);
			}
		},

		onDomNodeChange: function(evt){
			if(evt.oldNode != null){
				this.unbind(evt.oldNode, "startTransition");
			}
			this.bind(evt.newNode, "startTransition", lang.hitch(this, this.onStartTransition));
		},

		onStartTransition: function(evt){
			// summary:
			//		Response to dojox/app "startTransition" event.
			//
			// example:
			//		Use "dojox/mobile/TransitionEvent" to trigger "startTransition" event, and this function will response the event. For example:
			//		|	var transOpts = {
			//		|		title:"List",
			//		|		target:"items,list",
			//		|		url: "#items,list",
			//		|		data: {}
			//		|	};
			//		|	new TransitionEvent(domNode, transOpts, e).dispatch();
			//
			// evt: Object
			//		transition options parameter

			// prevent event from bubbling to window and being
			// processed by dojox/mobile/ViewController
			if(evt.preventDefault){
				evt.preventDefault();
			}
			evt.cancelBubble = true;
			if(evt.stopPropagation){
				evt.stopPropagation();
			}

			var target = evt.detail.target;
			var regex = /#(.+)/;
			if(!target && regex.test(evt.detail.href)){
				target = evt.detail.href.match(regex)[1];
			}

			// transition to the target view
			this.transition({ "viewId":target, opts: lang.mixin({}, evt.detail), data: evt.detail.data });
		},

		_addTransitionEventToWaitingQueue: function(transitionEvt){
			if(transitionEvt.defaultView && this.waitingQueue.length > 0){ // need to test for defaultView to position this view correctly
				var addedEvt = false;
				for(var i = 0; i < this.waitingQueue.length; i++){
					var evt = this.waitingQueue[i];
					if(!evt.defaultView){
						this.waitingQueue.splice(i,0,transitionEvt); // insert before first non defaultView
						addedEvt = true;
						break;
					}
				}
				if(!addedEvt){
					this.waitingQueue.push(transitionEvt);
				}
			}else{
				this.waitingQueue.push(transitionEvt);
			}
		},
		proceedTransition: function(transitionEvt){
			// summary:
			//		Proceed transition queue by FIFO by default.
			//		If transition is in proceeding, add the next transition to waiting queue.
			//
			// transitionEvt: Object
			//		"app-transition" event parameter. It should be like: {"viewId":viewId, "opts":opts}
			var F = MODULE+":proceedTransition";

			if(this.proceeding){
				this._addTransitionEventToWaitingQueue(transitionEvt);
				this.app.log(F+" added this event to waitingQueue", transitionEvt);
				this.processingQueue = false;
				return;
			}
			// If there are events waiting, needed to have the last in be the last processed, so add it to waitingQueue
			// process the events in order.
			this.app.log(F+" this.waitingQueue.length ="+ this.waitingQueue.length+ " this.processingQueue="+this.processingQueue);
			if(this.waitingQueue.length > 0 && !this.processingQueue){
				this.processingQueue = true;
				this._addTransitionEventToWaitingQueue(transitionEvt);
				this.app.log(F+" added this event to waitingQueue passed proceeding", transitionEvt);
				transitionEvt = this.waitingQueue.shift();
				this.app.log(F+" shifted waitingQueue to process", transitionEvt);
			}
			
			this.proceeding = true;

			this.app.log(F+" calling trigger load", transitionEvt);
			if(!transitionEvt.opts){
				transitionEvt.opts = {};
			}
			var params = transitionEvt.params || transitionEvt.opts.params;
			this.app.emit("app-load", {
				"viewId": transitionEvt.viewId,
				"params": params,
				"forceTransitionNone": transitionEvt.forceTransitionNone,
				"callback": lang.hitch(this, function(needToHandleDefaultView, defaultHasPlus){
					if(needToHandleDefaultView){ // do not process this view if needToHandleDefaultView true
						this.proceeding = false;
						this.processingQueue = true;
						// use pop instead of shift here to get the last event for the defaultView when the default does not have a +
						// use shift when it has a + or the defaults will be out of order but it can move the default to be after other views if we are processing views with a +
						var nextEvt = (defaultHasPlus) ? this.waitingQueue.shift() : this.waitingQueue.pop();
						if(nextEvt){
							this.proceedTransition(nextEvt);
						}
					}else{
						var transitionDef = this._doTransition(transitionEvt.viewId, transitionEvt.opts, params, transitionEvt.opts.data, this.app, transitionEvt._removeView, transitionEvt._doResize, transitionEvt.forceTransitionNone);
						when(transitionDef, lang.hitch(this, function(){
							this.proceeding = false;
							this.processingQueue = true;
							var nextEvt = this.waitingQueue.shift();
							if(nextEvt){
								this.proceedTransition(nextEvt);
							}
						}));
					}
				})
			});
		},

		_getTransition: function(nextView, parent, transitionTo, opts, forceTransitionNone){
			// summary:
			//		Get view's transition type from the config for the view or from the parent view recursively.
			//		If not available use the transition option otherwise get view default transition type in the
			//		config from parent view.
			//
			// parent: Object
			//		view's parent
			// transitionTo: Object
			//		view to transition to
			//	opts: Object
			//		transition options
			// forceTransitionNone: boolean
			//		true if the transition type should be forced to none, used for the initial defaultView
			//
			// returns:
			//		transition type like "slide", "fade", "flip" or "none".
			if(forceTransitionNone){
				return "none";
			}
			var parentView = parent;
			var transition = null;
			if(nextView){
				transition = nextView.transition;
			}
			if(!transition && parentView.views[transitionTo]){
				transition = parentView.views[transitionTo].transition;
			} 
			if(!transition){
				transition = parentView.transition;
			}
			var defaultTransition = (nextView && nextView.defaultTransition) ?  nextView.defaultTransition : parentView.defaultTransition;
			while(!transition && parentView.parent){
				parentView = parentView.parent;
				transition = parentView.transition;
				if(!defaultTransition){
					defaultTransition = parentView.defaultTransition;
				}
			}
			return transition || opts.transition || defaultTransition || "none";
		},


		_getParamsForView: function(view, params){
			// summary:
			//		Get view's params only include view specific params if they are for this view.
			//
			// view: String
			//		the view's name
			// params: Object
			//		the params
			//
			// returns:
			//		params Object for this view
			var viewParams = {};
			for(var item in params){
				var value = params[item];
				if(lang.isObject(value)){	// view specific params
					if(item == view){		// it is for this view
						// need to add these params for the view
						viewParams = lang.mixin(viewParams, value);
					} 
				}else{	// these params are for all views, so add them
					if(item && value != null){
						viewParams[item] = params[item];
					}
				}
			}
			return viewParams;
		},

		_doTransition: function(transitionTo, opts, params, data, parent, removeView, doResize, forceTransitionNone, nested){
			// summary:
			//		Transitions from the currently visible view to the defined view.
			//		It should determine what would be the best transition unless
			//		an override in opts tells it to use a specific transitioning methodology
			//		the transitionTo is a string in the form of [view1,view2].
			//
			// transitionTo: Object
			//		transition to view id. It looks like #tabView,tab1
			// opts: Object
			//		transition options
			// params: Object
			//		params
			// data: Object
			//		data object that will be passed on activate & de-activate methods of the view
			// parent: Object
			//		view's parent
			// removeView: Boolean
			//		remove the view instead of transition to it
			// doResize: Boolean
			//		emit a resize event
			// forceTransitionNone: Boolean
			//		force the transition type to be none, used for the initial default view
			// nested: Boolean
			//		whether the method is called from the transitioning of a parent view
			//
			// returns:
			//		transit dojo/promise/all object.
			var F = MODULE+":_doTransition";

			if(!parent){
				throw Error("view parent not found in transition.");
			}

			this.app.log(F+" transitionTo=[",transitionTo,"], removeView=[",removeView,"] parent.name=[",parent.name,"], opts=",opts);

			var parts, toId, subIds, next;
			if(transitionTo){
				parts = transitionTo.split(",");
			}else{
				// If parent.defaultView is like "main,main", we also need to split it and set the value to toId and subIds.
				// Or cannot get the next view by "parent.children[parent.id + '_' + toId]"
				parts = parent.defaultView.split(",");
			}
			toId = parts.shift();
			subIds = parts.join(',');

			// next is loaded and ready for transition
			next = parent.children[parent.id + '_' + toId];
			if(!next){
				if(removeView){
					this.app.log(F+" called with removeView true, but that view is not available to remove");
					return;	// trying to remove a view which is not showing
				}
				throw Error("child view must be loaded before transition.");
			}
			// if no subIds and next has default view,
			// set the subIds to the default view and transition to default view.
			if(!subIds && next.defaultView){
				subIds = next.defaultView;
			}

			var nextSubViewArray = [next || parent];
			if(subIds){
				nextSubViewArray = this._getNextSubViewArray(subIds, next, parent);
			}

			var current = constraints.getSelectedChild(parent, next.constraint);
			var currentSubViewArray = this._getCurrentSubViewArray(parent, nextSubViewArray, removeView);

			var currentSubNames = this._getNamesFromArray(currentSubViewArray, false);
			var nextSubNames = this._getNamesFromArray(nextSubViewArray, true);

			// set params on next view.
			next.params = this._getParamsForView(next.name, params);

			if(removeView){
				if(next !== current){ // nothing to remove
					this.app.log(F+" called with removeView true, but that view is not available to remove");
					return;	// trying to remove a view which is not showing
				}	
				this.app.log(LOGKEY,F,"Transition Remove current From=["+currentSubNames+"]");
				// if next == current we will set next to null and remove the view with out a replacement
				next = null;
			}

			if(nextSubNames == currentSubNames && next == current){ // new test to see if current matches next
				this.app.log(LOGKEY,F,"Transition current and next DO MATCH From=["+currentSubNames+"] TO=["+nextSubNames+"]");
				this._handleMatchingViews(nextSubViewArray, next, current, parent, data, removeView, doResize, subIds, currentSubNames, toId, forceTransitionNone, opts);

			}else{
				this.app.log(LOGKEY,F,"Transition current and next DO NOT MATCH From=["+currentSubNames+"] TO=["+nextSubNames+"]");
				//When clicking fast, history module will cache the transition request que
				//and prevent the transition conflicts.
				//Originally when we conduct transition, selectedChild will not be the
				//view we want to start transition. For example, during transition 1 -> 2
				//if user click button to transition to 3 and then transition to 1. After
				//1->2 completes, it will perform transition 2 -> 3 and 2 -> 1 because
				//selectedChild is always point to 2 during 1 -> 2 transition and transition
				//will record 2->3 and 2->1 right after the button is clicked.

				//assume next is already loaded so that this.set(...) will not return
				//a promise object. this.set(...) will handles the this.selectedChild,
				//activate or deactivate views and refresh layout.

				//necessary, to avoid a flash when the layout sets display before resize
				if(!removeView && next){
					var nextLastSubChild = this.nextLastSubChildMatch || next;
					var startHiding = false; // only hide views which will transition in
					for(var i = nextSubViewArray.length-1; i >= 0; i--){
						var v = nextSubViewArray[i];
						if(startHiding || v.id == nextLastSubChild.id){
							startHiding = true;
							if(!v._needsResize && v.domNode){
								this.app.log(LOGKEY,F," setting domStyle visibility hidden for v.id=["+v.id+"], display=["+v.domNode.style.display+"], visibility=["+v.domNode.style.visibility+"]");
								this._setViewVisible(v, false);
							}
						}
					}
				}

				if(current && current._active){
					this._handleBeforeDeactivateCalls(currentSubViewArray, this.nextLastSubChildMatch || next, current, data, subIds);
				}
				if(next){
					this.app.log(F+" calling _handleBeforeActivateCalls next name=[",next.name,"], parent.name=[",next.parent.name,"]");
					this._handleBeforeActivateCalls(nextSubViewArray, this.currentLastSubChildMatch || current, data, subIds);
				}
				if(!removeView){
					var nextLastSubChild = this.nextLastSubChildMatch || next;
					var trans = this._getTransition(nextLastSubChild, parent, toId, opts, forceTransitionNone)
					this.app.log(F+" calling _handleLayoutAndResizeCalls trans="+trans);
					this._handleLayoutAndResizeCalls(nextSubViewArray, removeView, doResize, subIds, forceTransitionNone, trans);
				}else{
					// for removeView need to set visible before transition do it here
					for(var i = 0; i < nextSubViewArray.length; i++){
						var v = nextSubViewArray[i];
						this.app.log(LOGKEY,F,"setting visibility visible for v.id=["+v.id+"]");
						if(v.domNode){
							this.app.log(LOGKEY,F,"  setting domStyle for removeView visibility visible for v.id=["+v.id+"], display=["+v.domNode.style.display+"]");
							this._setViewVisible(v, true);
						}
					}
				}
				var result = true;

				// this.currentLastSubChildMatch holds the view to transition from
				if(transit && (!nested || this.currentLastSubChildMatch != null) && this.currentLastSubChildMatch !== next){
					// css3 transit has the check for IE so it will not try to do it on ie, so we do not need to check it here.
					// We skip in we are transitioning to a nested view from a parent view and that nested view
					// did not have any current
					result = this._handleTransit(next, parent, this.currentLastSubChildMatch, opts, toId, removeView, forceTransitionNone, doResize);
				}
				when(result, lang.hitch(this, function(){
					if(next){
						this.app.log(F+" back from transit for next ="+next.name);
					}
					if(removeView){
						var nextLastSubChild = this.nextLastSubChildMatch || next;
						var trans = this._getTransition(nextLastSubChild, parent, toId, opts, forceTransitionNone)
						this._handleLayoutAndResizeCalls(nextSubViewArray, removeView, doResize, subIds, forceTransitionNone, trans);
					}

					// Add call to handleAfterDeactivate and handleAfterActivate here!
					this._handleAfterDeactivateCalls(currentSubViewArray, this.nextLastSubChildMatch || next, current, data, subIds);
					this._handleAfterActivateCalls(nextSubViewArray, removeView, this.currentLastSubChildMatch || current, data, subIds);
				}));
				return result; // dojo/promise/all
			}
		},

		_handleMatchingViews: function(subs, next, current, parent, data, removeView, doResize, subIds, currentSubNames, toId, forceTransitionNone, opts){
			// summary:
			//		Called when the current views and the next views match
			var F = MODULE+":_handleMatchingViews";

			this._handleBeforeDeactivateCalls(subs, this.nextLastSubChildMatch || next, current, data, subIds);
			// this is the order that things were being done before on a reload of the same views, so I left it
			// calling _handleAfterDeactivateCalls here instead of after _handleLayoutAndResizeCalls
			this._handleAfterDeactivateCalls(subs, this.nextLastSubChildMatch || next, current, data, subIds);
			this._handleBeforeActivateCalls(subs, this.currentLastSubChildMatch || current, data, subIds);
			var nextLastSubChild = this.nextLastSubChildMatch || next;
			var trans = this._getTransition(nextLastSubChild, parent, toId, opts, forceTransitionNone)
			this._handleLayoutAndResizeCalls(subs, removeView, doResize, subIds, trans);
			this._handleAfterActivateCalls(subs, removeView, this.currentLastSubChildMatch || current, data, subIds);
		},

		_handleBeforeDeactivateCalls: function(subs, next, current, /*parent,*/ data, /*removeView, doResize,*/ subIds/*, currentSubNames*/){
			// summary:
			//		Call beforeDeactivate for each of the current views which are about to be deactivated
			var F = MODULE+":_handleBeforeDeactivateCalls";
			if(current._active){
				//now we need to loop backwards thru subs calling beforeDeactivate
				for(var i = subs.length-1; i >= 0; i--){
					var v = subs[i];
					if(v && v.beforeDeactivate && v._active){
						this.app.log(LOGKEY,F,"beforeDeactivate for v.id="+v.id);
						v.beforeDeactivate(next, data);
					}
				}
			}
		},

		_handleAfterDeactivateCalls: function(subs, next, current, data, subIds){
			// summary:
			//		Call afterDeactivate for each of the current views which have been deactivated
			var F = MODULE+":_handleAfterDeactivateCalls";
			if(current && current._active){
				//now we need to loop forwards thru subs calling afterDeactivate
				for(var i = 0; i < subs.length; i++){
					var v = subs[i];
					if(v && v.beforeDeactivate && v._active){
						this.app.log(LOGKEY,F,"afterDeactivate for v.id="+v.id);
						v.afterDeactivate(next, data);
						v._active = false;
					}
				}

			}
		},

		_handleBeforeActivateCalls: function(subs, current, data, subIds){
			// summary:
			//		Call beforeActivate for each of the next views about to be activated
			var F = MODULE+":_handleBeforeActivateCalls";
			//now we need to loop backwards thru subs calling beforeActivate (ok since next matches current)
			for(var i = subs.length-1; i >= 0; i--){
				var v = subs[i];
				this.app.log(LOGKEY,F,"beforeActivate for v.id="+v.id);
				v.beforeActivate(current, data);
			}
		},

		_handleLayoutAndResizeCalls: function(subs, removeView, doResize, subIds, forceTransitionNone, transition){
			// summary:
			//		fire app-layoutView for each of the next views about to be activated, and fire app-resize if doResize is true
			var F = MODULE+":_handleLayoutAndResizeCalls";
			var remove = removeView;
			for(var i = 0; i < subs.length; i++){
				var v = subs[i];
				this.app.log(LOGKEY,F,"emit layoutView v.id=["+v.id+"] removeView=["+remove+"]");
				// it seems like we should be able to minimize calls to resize by passing doResize: false and only doing resize on the app-resize emit
				this.app.emit("app-layoutView", {"parent": v.parent, "view": v, "removeView": remove, "doResize": false, "transition": transition, "currentLastSubChildMatch": this.currentLastSubChildMatch});
				remove = false;
			}
			if(doResize){
				this.app.log(LOGKEY,F,"emit doResize called");
				this.app.emit("app-resize"); // after last layoutView fire app-resize
				if(transition == "none"){
					this._showSelectedChildren(this.app); // Need to set visible too before transition do it now.
				}
			}

		},

		_showSelectedChildren: function(w){
			var F = MODULE+":_showSelectedChildren";
			this.app.log(LOGKEY,F," setting domStyle visibility visible for w.id=["+w.id+"], display=["+w.domNode.style.display+"], visibility=["+w.domNode.style.visibility+"]");
			this._setViewVisible(w, true);
			w._needsResize = false;
			for(var hash in w.selectedChildren){	// need this to handle all selectedChildren
				if(w.selectedChildren[hash] && w.selectedChildren[hash].domNode){
					this.app.log(LOGKEY,F," calling _showSelectedChildren for w.selectedChildren[hash].id="+w.selectedChildren[hash].id);
					this._showSelectedChildren(w.selectedChildren[hash]);
				}
			}
		},

		_setViewVisible: function(v, visible){
			if(visible){
				domStyle.set(v.domNode, "visibility", "visible");
			}else{
				domStyle.set(v.domNode, "visibility", "hidden");
			}
		},


		_handleAfterActivateCalls: function(subs, removeView, current, data, subIds){
			// summary:
			//		Call afterActivate for each of the next views which have been activated
			var F = MODULE+":_handleAfterActivateCalls";
			//now we need to loop backwards thru subs calling beforeActivate (ok since next matches current)
			var startInt = 0;
			if(removeView && subs.length > 1){
				startInt = 1;
			}
			for(var i = startInt; i < subs.length; i++){
				var v = subs[i];
				if(v.afterActivate){
					this.app.log(LOGKEY,F,"afterActivate for v.id="+v.id);
					v.afterActivate(current, data);
					v._active = true;
				}
			}
		},

		_getNextSubViewArray: function(subIds, next, parent){
			// summary:
			//		Get next sub view array, this array will hold the views which are about to be transitioned to
			//
			// subIds: String
			//		the subids, the views are separated with a comma
			// next: Object
			//		the next view to be transitioned to.
			// parent: Object
			//		the parent view used in place of next if next is not set.
			//
			// returns:
			//		Array of views which will be transitioned to during this transition
			var F = MODULE+":_getNextSubViewArray";
			var parts = [];
			var p = next || parent;
			if(subIds){
				parts = subIds.split(",");
			}
			var nextSubViewArray = [p];
			//now we need to loop forwards thru subIds calling beforeActivate
			for(var i = 0; i < parts.length; i++){
				toId = parts[i];
				var v = p.children[p.id + '_' + toId];
				if(v){
					nextSubViewArray.push(v);
					p = v;
				}
			}
			nextSubViewArray.reverse();
			return nextSubViewArray;
		},

		_getCurrentSubViewArray: function(parent, nextSubViewArray, removeView){
			// summary:
			//		Get current sub view array which will be replaced by the views in the nextSubViewArray
			//
			// parent: String
			//		the parent view whose selected children will be replaced
			// nextSubViewArray: Array
			//		the array of views which are to be transitioned to.
			//
			// returns:
			//		Array of views which will be deactivated during this transition
			var F = MODULE+":_getCurrentSubViewArray";
			var currentSubViewArray = [];
			var constraint, type, hash;
			var p = parent;
			this.currentLastSubChildMatch = null;
			this.nextLastSubChildMatch = null;

			for(var i = nextSubViewArray.length-1; i >= 0; i--){
				constraint = nextSubViewArray[i].constraint;
				type = typeof(constraint);
				hash = (type == "string" || type == "number") ? constraint : constraint.__hash;
				// if there is a selected child for this constraint, and the child matches this view, push it.
				if(p && p.selectedChildren && p.selectedChildren[hash]){
					if(p.selectedChildren[hash] == nextSubViewArray[i]){
						this.currentLastSubChildMatch = p.selectedChildren[hash];
						this.nextLastSubChildMatch = nextSubViewArray[i];
						currentSubViewArray.push(this.currentLastSubChildMatch);
						p = this.currentLastSubChildMatch;
					}else{
						this.currentLastSubChildMatch = p.selectedChildren[hash];
						currentSubViewArray.push(this.currentLastSubChildMatch);
						this.nextLastSubChildMatch = nextSubViewArray[i]; // setting this means the transition will be done to the child instead of the parent
						// since the constraint was set, but it did not match, need to deactivate all selected children of this.currentLastSubChildMatch
						if(!removeView){
							var selChildren = constraints.getAllSelectedChildren(this.currentLastSubChildMatch);
							currentSubViewArray = currentSubViewArray.concat(selChildren);
						}
						break;
					}
				}else{ // the else is for the constraint not matching which means no more to deactivate.
					this.currentLastSubChildMatch = null; // there was no view selected for this constraint
					this.nextLastSubChildMatch = nextSubViewArray[i]; // set this to the next view for transition to an empty constraint
					break;
				}

			}
			// Here since they had the constraint but it was not the same I need to deactivate all children of p
			if(removeView){
				var selChildren = constraints.getAllSelectedChildren(p);
				currentSubViewArray = currentSubViewArray.concat(selChildren);
			}

			return currentSubViewArray;
		},

		_getNamesFromArray: function(subViewArray, backward){
			// summary:
			//		Get names from the sub view names array
			//
			// subViewArray: Array
			//		the array of views to get the names from.
			// backward: boolean
			//		the direction to loop thru the array to get the names.
			//
			// returns:
			//		String of view names separated by a comma
			//
			var F = MODULE+":_getNamesFromArray";
			var subViewNames = "";
			if(backward){
				for (var i = subViewArray.length - 1; i >= 0; i--) {
					subViewNames = subViewNames ? subViewNames+","+subViewArray[i].name : subViewArray[i].name;
				}
			}else{
				for(var i = 0; i < subViewArray.length; i++){
					subViewNames = subViewNames ? subViewNames+","+subViewArray[i].name : subViewArray[i].name;
				}
			}
			return subViewNames;
		},

		_handleTransit: function(next, parent, currentLastSubChild, opts, toId, removeView, forceTransitionNone, resizeDone){
			// summary:
			//		Setup the options and call transit to do the transition
			//
			// next: Object
			//		the next view, the view which will be transitioned to
			// parent: Object
			//		the parent view which is used to get the transition type to be used
			// currentLastSubChild: Object
			//		the current view which is being transitioned away from
			// opts: Object
			//		the options used for the transition
			// toId: String
			//		the id of the view being transitioned to
			// removeView: boolean
			//		true if the view is being removed
			// forceTransitionNone: boolean
			//		true if the transition type should be forced to none, used for the initial defaultView
			// resizeDone: boolean
			//		true if resize was called before this transition
			//
			// returns:
			//		the promise returned by the call to transit
			var F = MODULE+":_handleTransit";

			var nextLastSubChild = this.nextLastSubChildMatch || next;

			var mergedOpts = lang.mixin({}, opts); // handle reverse from mergedOpts or transitionDir
			mergedOpts = lang.mixin({}, mergedOpts, {
				reverse: (mergedOpts.reverse || mergedOpts.transitionDir === -1)?true:false,
				// if transition is set for the view (or parent) in the config use it, otherwise use it from the event or defaultTransition from the config
				transition: this._getTransition(nextLastSubChild, parent, toId, mergedOpts, forceTransitionNone)
			});

			if(removeView){
				nextLastSubChild = null;
			}
			if(currentLastSubChild){
				this.app.log(LOGKEY,F,"transit FROM currentLastSubChild.id=["+currentLastSubChild.id+"]");
			}
			if(nextLastSubChild){
				if(mergedOpts.transition !== "none"){
					if(!resizeDone && nextLastSubChild._needsResize){ // need to resize if not done yet or things will not be positioned correctly
						this.app.log(LOGKEY,F,"emit doResize called from _handleTransit");
						this.app.emit("app-resize"); // after last layoutView fire app-resize
					}
					this.app.log(LOGKEY,F,"  calling _showSelectedChildren for w3.id=["+nextLastSubChild.id+"], display=["+nextLastSubChild.domNode.style.display+"], visibility=["+nextLastSubChild.domNode.style.visibility+"]");
					this._showSelectedChildren(this.app); // Need to set visible too before transition do it now.
				}
				this.app.log(LOGKEY,F,"transit TO nextLastSubChild.id=["+nextLastSubChild.id+"] transition=["+mergedOpts.transition+"]");
			}else{
				this._showSelectedChildren(this.app); // Need to set visible too before transition do it now.
			}
			return transit(currentLastSubChild && currentLastSubChild.domNode, nextLastSubChild && nextLastSubChild.domNode, mergedOpts);
		}

	});
});
