

	
	var Reorder = Class.create();

	Reorder.prototype = {
		initialize: function() {
			this.currentIndex = -1;
			this.isScrolling  = false;
			this.lastMovedElement  = null;
			this.lastParent        = null;
			this.lastStructuredNav = null;
			this.isReorderingNow   = false;
		},
		
		doneReordering: function(projectId) {
			this.cancelReordering();
			this.done(this, projectId);
		},
		
		cancelReordering: function(projectId, resetNav) {
			this.isReorderingNow = false;
			if(typeof(resetNav) == 'undefined') resetNav = false;

			$('nav').removeClassName('isReorderingPages');
			$('nav').addClassName('notReordering');
			$('reorderPageDone').hide();
			$('reorderPageStart').show();
			$$('#reorderablePages a.navPageLink').each(function(a){ a.onclick=null; });

			if(resetNav)
				$('reorderablePages').update(this.lastStructuredNav);

			pageChangeConfirmationOff();
		},
		
		startReordering: function(projectId) {
			this.isReorderingNow = true;
			this.lastStructuredNav = $('reorderablePages').innerHTML;

			pageChangeConfirmationOn();
			$$('#reorderablePages a.navPageLink').each(function(a){ a.onclick=function(){return false;} });
			
			$('nav').addClassName('isReorderingPages');
			$('nav').removeClassName('notReordering');
			$('reorderPageStart').hide();
			$('reorderPageDone').show();
			this.startList(projectId);
		},
		
		startList: function(projectId) {
			if(typeof(this.projectId) == 'undefined') this.projectId = projectId;
			$j('#reorderablePages').NestedSortableDestroy();
			jQuery.iDrop.destroy();

			var myNav = $j('#reorderablePages').NestedSortable({
				topLevelId: 'reorderablePages',
				accept: 'reorderableSection',
				helperclass: 'reorderHelper',
				nestingPxSpace: 12,
				currentNestingClass: 'reorderCurrentNesting',
				autoScroll: true,
				scrollSensitivity: 40,
				scrollSpeed: 60,
				// handle: '.pageNameAndReorderHandle',
				onStart: reorder.start.bindAsEventListener(this),
				onChange: this.change.bindAsEventListener(this)
				// onChange: function(){
				// 					$$('.treeExpander').invoke('remove');
				// 					var treeClassStr = '';
				// 					$$('.reorderableSection .pageList:not(:empty)').each(function(e) {
				// 						treeClassStr = (e.hasClassName('collapsed')) ? '' : ' opened';
				// 						e.previous('.pageNameAndReorderHandle').insert({'top':'<a class="treeExpander'+treeClassStr+'" href="javascript:void(0);" onclick="jumpchart.expandNav(this)">Collapse</a>'});
				// 					});
				// 				}
			});

			if(Prototype.Browser.WebKit && $$('.currentOpenedPage')[0].getWidth() > 185)
			{
				var i = 0;	
				var marginLeft = ((this.px($$('.currentOpenedPage')[0].getStyle('margin-left'))*-1)+20);
				while($$('.currentOpenedPage')[0].getWidth() > 185 && i<10)
				{					
					var newWidth = $$('.currentOpenedPage')[0].getWidth() - marginLeft;
					$$('.currentOpenedPage')[0].style.width = newWidth+'px';
					i++;
				}
				if($$('.currentOpenedPage')[0].getWidth() != 185)
					$$('.currentOpenedPage')[0].style.width = 'auto';
			}
		},

		/*  updates the treeExpander as necessary (remove or add) */
		change: function() {
			if(this.lastParent != null)
			{
				if(!this.lastParent.down())
				{
					var lastParentTreeExpander = this.lastParent.previous('.pageNameAndReorderHandle').down('.treeExpander');
					if(lastParentTreeExpander)
					{
						lastParentTreeExpander.remove();
					}
				}

				var newParent = this.lastMovedElement.up('.reorderableSection');

				if(newParent)
				{
					var newParentNameContainer = newParent.down('.pageNameAndReorderHandle');
					var pageId = newParent.id.split('-')[1];

					if(!newParentNameContainer.down('.treeExpander'))
					{
						var treeExpanderStr = '<a class="treeExpander opened" id="treeExpander'+pageId+'" href="javascript:void(0);" onclick="jumpchart.expandNav(this)">Collapse</a>';
						newParentNameContainer.insert({'top':treeExpanderStr});
					}
				}
			}
		},
		
		start: function(el) {
			this.lastMovedElement = $(el.id);
			this.lastParent = $(el.id).up('.pageList');
		},
		
		px: function(str)
		{
			return str.replace('px','')*1;
		},
		
		show: function(projectId, userId)
		{
			var pars = 'ajaxAction=showReorder&project_id=' + projectId;
			showLoading('jumpchartNav');
			var myAjax = new Ajax.Request( ajaxUrl, { method: 'post', parameters: pars, onComplete: this._show_callback.bindAsEventListener(this, projectId, userId)});
			pageChangeConfirmationOn();
		},

		_show_callback: function (request, projectId, userId)
		{
			hideLoading('jumpchartNav');
			if(request.responseText == 'false')
				alert("There was an error processing your request. Please reload the page and try again.");
			else if(request.responseText == 'no-access')
				alert("You don't have permission to reorder this Jumpchart");
			else
			{
				$('jumpchartNav').replace(request.responseText);
				
				// $('jumpchartNav').innerHTML = request.responseText;
				// 				if(Prototype.Browser.IE)
				// 					$('jumpchartNav').addClassName('isReordering');
				// 
				// 				uls   = getByTag('ul');
				// 				size  = uls.length;
				// 				i     = size-1;
				// 
				// 				Sortable.create('jumpchartNav', { tree:true, dragOnEmpty:true, scroll:window,onUpdate: this._showChange.bindAsEventListener(this) });
				// 
				// 				$$('.reorderItem').each(this._registerReorderClick.bindAsEventListener(this));
				// 

				$('showReorderLink').style.display = 'none';
				$('pageSecondToolbar').appendChild(Builder.build('<a href="javascript:void(0);" onclick="reorder.done(' + projectId + ')" id="doneReorderLink">Done reordering</a>'));
				
				/*
				 * TODO need to fix reorder by keyboard before launching it
				 */
				// if(userId == 7 || userId == 1914 || userId == 3158)
				// 	this.keyboardInit();
			}
		},
		
		done: function(el, projectId)
		{
			new Ajax.Request(ajaxUrl + '?ajaxAction=doReorder', 
				{
					onComplete: this.done_callback.bindAsEventListener(this,projectId),
					parameters: 'projectId=' + this.projectId + '&' + jQuery.iNestedSortable.newSerialize('reorderablePages').hash,
					evalScripts:true, asynchronous:true
				});
			
			/*
			 * DEPRECATED: this happens on the change() method now, since it's faster and more precise and makes more sense
			 * Remove or add a tree expander as necessary
			 */
			// $$('.treeExpander').invoke('remove');
			// var treeClassStr = '';
			// $$('.reorderableSection .pageList:not(:empty)').each(function(e) {
			// 	treeClassStr = (e.hasClassName('collapsed')) ? '' : ' opened';
			// 	e.previous('.pageNameAndReorderHandle').insert({'top':'<a class="treeExpander'+treeClassStr+'" href="javascript:void(0);" onclick="jumpchart.expandNav(this)">Collapse</a>'});
			// });
			
			pageChangeConfirmationOff();
			

		},
		
		done_callback: function(request,projectId) {
			$j('#reorderablePages').NestedSortableDestroy();

			if(request.responseText == 'false')
				alert("There was an error reordering the pages.");
			else if(request.responseText == 'no-access')
				alert("You don't have permission to reorder this Jumpchart.");
			else
			{
				/*
				 * Once we know the new order has been successfully saved, we update the Expand/Collapse info from the database with the current structure 
				 * (this is done so we can avoid having collapsed/expanded elements that don't even have children anymore)
				 */
				jumpchart.expandNavSaveCurrentState(projectId);
				
				/* We also update the current page breadcrumb to make sure it's the most updated as possible */
				page.updateCurrentBreadcrumb(projectId);
			}
		},
		
		/*
		 * Keyboard Reorder
		 */
		
		keyboardInit: function() {
			/* Clean up shortcuts to avoid problems when you hit "Reorder" two times on the same page load */
			shortcut.remove('Ctrl+Down');
			shortcut.remove('Ctrl+Up');
			shortcut.remove('Shift+Down');
			shortcut.remove('Shift+Up');
			shortcut.remove('Shift+Right');
			shortcut.remove('Shift+Left');
			
			this.allItems = $$('#jumpchartNav li[class!=dummyLI]');

			/* Mark first item as selected */
			this.currentIndex++;
			this.selectItem();
			
 			var keyEvent = (Prototype.Browser.Gecko) ? 'keypress' : 'keydown';

			shortcut.add('Ctrl+Down', function(){reorder.goToNextItem();}, {'propagate': false, 'type':keyEvent});
			shortcut.add('Ctrl+Up', function(){reorder.goToPreviousItem();}, {'propagate': false, 'type':keyEvent});

			shortcut.add('Shift+Down', function(){reorder.moveDown();}, {'propagate': false, 'type':keyEvent});
			shortcut.add('Shift+Up', function(){reorder.moveUp();}, {'propagate': false, 'type':keyEvent});

			shortcut.add('Shift+Right', function(){reorder.moveRight();}, {'propagate': false, 'type':keyEvent});
			shortcut.add('Shift+Left', function(){reorder.moveLeft();}, {'propagate': false, 'type':keyEvent});
		},

		selectItem:function(itemIndex) {
			if(typeof(itemIndex) == 'undefined') itemIndex = this.currentIndex;

			var newItem = this.allItems[itemIndex];

			var currentlySelected = $$('.keyboardReorderSelected');
			if(currentlySelected.size() > 0)
				currentlySelected[0].removeClassName('keyboardReorderSelected');

			newItem.addClassName('keyboardReorderSelected');
			
			this.scrollScreen();
		},
		
		scrollScreen: function(itemIndex) {
			if(this.isScrolling)
				return;

			if(typeof(itemIndex) == 'undefined') itemIndex = this.currentIndex;

			var item = this.allItems[itemIndex];
			var viewportHeight         = document.viewport.getHeight();
			var itemViewportOffset     = item.viewportOffset()[1];
			var viewportBottomBoundary = viewportHeight * 0.9;
			var viewportTopBoundary    = viewportHeight * 0.1;

			if(itemViewportOffset > viewportBottomBoundary || itemViewportOffset < viewportTopBoundary)
			{
				this.isScrolling = true;
				var scrollOffset = viewportHeight/2*-1;
				var self = this;
				new Effect.ScrollTo(item, {duration:0.3,offset:scrollOffset, afterFinish:function(){self.isScrolling=false;}});
			}
		},
		
		goToNextItem: function() {
			if(this.allItems[this.currentIndex+1])
				this.currentIndex++;
			else
				this.currentIndex = 0;
			
			this.selectItem();
		},
		
		goToPreviousItem: function() {
			if(this.allItems[this.currentIndex-1])
				this.currentIndex--;
			else
				this.currentIndex = this.allItems.size()-1;
			this.selectItem();
		},
		
		reconstructIndex: function(currentlyMovedElement, a, searchForNewCurrent) {
			this.allItems = null;
			this.allItems = $$('#jumpchartNav li[class!=dummyLI]');
			if(!a)
			{
				this.allItems.each(function(e, index){ if(e == currentlyMovedElement) currentIndex = index; });
				this.currentIndex = (typeof(currentIndex) != 'undefined') ? currentIndex : 0;
			}
			
			if(typeof(searchForNewCurrent) != 'undefined' && searchForNewCurrent)
			{
				var self = this;
				var currentlyHighlighted = $$('.keyboardReorderSelected')[0];
				this.allItems.each(function(e, index){ 
					if(e == currentlyHighlighted)
					{
						currentlyHighlighted.removeClassName('keyboardReorderSelected');
						e.addClassName('keyboardReorderSelected');
						self.currentIndex = index;
						return;
					} 
				});
			}
		},

		moveDown: function(element) {
			var current       = this.allItems[this.currentIndex];
			var nextInTheTree = this.allItems[this.currentIndex+1];

			if(nextInTheTree)
			{
				var current = this.allItems[this.currentIndex];
				/* Check if the $nextInTheTree isn't a child of $current */
				var isChild = current.descendants().find(function(e){ if(e == nextInTheTree) return true; });

				if(nextInTheTree.down('ul[class!=dummyUL]') && !isChild)
				{
					nextInTheTree.down('ul[class!=dummyUL]').insert({'top':current});
				}
				else if(isChild)
				{
					/* We must calculate the absolute next using the next() function, since $nextInTheTree is a child of $current */
					if(current.next('[class!=dummyLI]'))
					{
						if(current.next('[class!=dummyLI]').down('ul'))
						{
							current.next('[class!=dummyLI]').down('ul').insert({'top':current});
						}
						else
						{
							current.next('[class!=dummyLI]').insert({'after':current});
						}
					}
					else
					{
						/* If there's no direct subtree, we must get it from the closest root LI */
						// var closestRootLi = current.up('ul').up('ul').up('li');
						var closestRootLi = current.up('li');
						if(closestRootLi)
						{
							var nextSubtreeFromClosestRootLi = closestRootLi.next();

							while(!nextSubtreeFromClosestRootLi)
							{
								closestRootLi = closestRootLi.up('ul').up('li');
								if(!closestRootLi)
								{
									nextSubtreeFromClosestRootLi = null;
									break;
								}
								else
									nextSubtreeFromClosestRootLi = closestRootLi.next();
							}

							if(nextSubtreeFromClosestRootLi)
							{
								if(!nextSubtreeFromClosestRootLi.down('ul'))
								{
									nextSubtreeFromClosestRootLi.insert({'bottom':'<ul></ul>'});
								}
								nextSubtreeFromClosestRootLi.down('ul').insert({'top':current});
							}
						}
					}
				}
				else
				{
					nextInTheTree.insert({'after':current});
				}

			}
			this.reconstructIndex(current);
			this.scrollScreen();
		},
		
		moveUp: function() {
			// var previousInTheTree = this.allItems[this.currentIndex].previous();
		 	var previousInTheTree = this.allItems[this.currentIndex-1];

			if(previousInTheTree)
			{
				var current       = this.allItems[this.currentIndex];
				previousInTheTree.insert({'before':current});
			}
			this.reconstructIndex(current);
			this.scrollScreen();
		},
		
		moveRight: function() {
			var previousInTheTree = this.allItems[this.currentIndex].previous('[class!=dummyLI]');

			if(previousInTheTree)
			{
				var current = this.allItems[this.currentIndex];
				
				if(previousInTheTree.tagName == 'UL')
					previousInTheTree.insert({'bottom':current});
				else
				{
					if(!previousInTheTree.down('ul'))
						previousInTheTree.insert({'bottom':'<ul></ul>'});

					previousInTheTree.down('ul').insert({'bottom':current});					
				}
			}
			this.scrollScreen();
		},
		
		moveLeft: function() {
			var previousInTheTree = this.allItems[this.currentIndex].up('li[class!=dummyLI]');
			if(previousInTheTree && previousInTheTree.id != 'jumpchartNav')
			{
				var current = this.allItems[this.currentIndex];

				if(previousInTheTree.tagName == 'UL')
					previousInTheTree.insert({'after':current});
				else
				{
					// if(!previousInTheTree.down('ul'))
					// 	previousInTheTree.insert({'bottom':'<ul></ul>'});
					// 
					// previousInTheTree.down('ul').insert({'after':current});
					previousInTheTree.insert({'after':current});
				}

			}
			this.scrollScreen();
		},
		
		keyboardSave:function() {
			Sortable.create('jumpchartNav', {tree:true});
			new Ajax.Request(ajaxUrl, { postBody: 'ajaxAction=keyboardReorderSave&' + Sortable.serialize('jumpchartNav'), onComplete: this._keyboardReorderSave_callback.bindAsEventListener(this) });
		},
		
		_keyboardReorderSave_callback:function(request) {
			$('result').update(request.responseText);
		},
		
		/*
		 * Mouse Reorder
		 */
		_registerReorderClick: function(e) {
			Event.observe(e, 'mousedown', this._reorderMouseDown.bindAsEventListener(this, e));
			Event.observe(e, 'mouseup', this._reorderMouseUp.bindAsEventListener(this, e));
		},

		_reorderMouseDown: function(event, element) { element.addClassName('clickedReorderItem'); },
		_reorderMouseUp: function(event, element) { element.removeClassName('clickedReorderItem'); },

		_showChange: function(e,ev) {
			var dummyULs = $$('.dummyUL');
			dummyULs.each(function(ul) {
				if(ul.immediateDescendants().size() > 1)
				{
					ul.className = '';
					ul.immediateDescendants().each(function(li) {
						if(li.empty())
							li.remove();
					});
				}
			});

			$$('#jumpchartNav li').each(function(li) {
				if(li.descendants().size() == 0)
					if(li.className != 'dummyLI')
						li.appendChild(Builder.build('<ul class="dummyUL-ASDF"><li class="dummyLI-ASDF"></li></ul>'));
			});
			

			this.reconstructIndex(null, true, true);
		}

		
	};

	var reorder = new Reorder();
	

