/**
 * Orphan Manager
 * Removes blocks from the page and puts them in a list,
 * permitting reinsertion.
 */
var OrphanManager = Class.create();
OrphanManager.prototype = {
	initialize: function(s) {
		this.settings         = s;
		this.lastOrphanId     = 0;
		this.ajaxObj          = null;
		this.lastPars         = null;
		this.savedPadding     = null;

		this.s = {
			showErrors: true,
			showDebugs: false,
			ajaxUrl: '',
			n_orphanListBox: null,
			n_orphanList: null,
			c_getOrphanName: function() {},
			c_afterRefreshList: function() {},
			c_getModuleID: function() {},
			c_beforeRelease: function() {},
			c_afterRelease: function() {},
			orphanSelector: '',                                            // Classname to identify orphans by
			removeButtonSelector: '',                                      // Classname by which to identify the "remove" button within an orphan
			groups: []
		};
		for (var key in s) this.s[key] = s[key];                         // Load in settings

		//if (typeof(Event.unObserve) == 'undefined') this.error('I require a later version of Prototype_ss.js!');
		if (!DOM.isNode(this.s.n_orphanListBox)) return false;
		if (!DOM.isNode(this.s.n_orphanList)) return false;


		// Seek out potential orphans
		for (var x=0; x<this.s.groups.length; x++) {
			var grp = this.s.groups[x];

			// Locate insertion points in all groups
			if (!grp.insertBefore) grp.insertBefore = DOM.findFlag('insertBefore', grp.n_container);
			if (!grp.insertBefore && !grp.insertAfter) grp.insertAfter = DOM.findFlag('insertAfter', grp.n_container);

			// Locate orphans within group

			var orphans = document.getElementsBySelector(this.s.orphanSelector, grp.n_container);
			grp.orphans = [];
			for (var y=0; y<orphans.length; y++) {
				if (orphans[y] != this.s.n_orphanListBox) {
					var orphan = {
						id:            this.orphanId(),
						moduleId:      null,
						name:          '',
						content:       orphans[y].cloneNode(true),
						homeless:      false,
						node:          orphans[y],
						removeButtons: []
					};
					orphan.name = this.s.c_getOrphanName(orphan);
					orphan.moduleId = this.s.c_getModuleID(orphan);
					if (!orphan.moduleId) Element.addClassName(orphan.node, 'noid');

					this.acquireRemoveButtons(orphan);
					grp.orphans.push(orphan);
				}
			}
		}



		// Find which orphans are already in custody, and activate their "release" links
		//debugger;
		var prisoners = this.s.n_orphanList.getElementsByTagName('a');

		for (var x=0; x<prisoners.length; x++) {

		var chunk = DOM.getCommentData('InactiveModule', prisoners[x]);
		if (chunk) {
				var bits = chunk.split('_');
				var orphan = this.getOrphanByPmid(bits[1]);
				orphan.homeless = true;

				Event.observe(prisoners[x], 'click', this.release.bind(this, orphan));
			} else {
				this.error('Could not read <!--InactiveModule=?--> comment in "'+prisoners[x].innerHTML+'".');
			}
			//debugger;`
			//var grp = this.getGroupById(bits[0]);
			//grp.orphans.push(orphan);
		}


		this.savedPadding = this.s.n_orphanListBox.style.padding;
		this.fixSortables();
		this.refreshList(true);
},

	ajax: function() {
		// Seek out orphan nodes again, record them in order.
		for (var x=0; x<this.s.groups.length; x++) {
			var grp = this.s.groups[x];


			// Locate orphans within group
			var nodes = document.getElementsBySelector(this.s.orphanSelector, grp.n_container);
			grp.ordered = [];
			for (var y=0; y<nodes.length; y++) {
				// Resolve them to objects
				grp.ordered.push(this.getOrphanForNode(nodes[y]));
			}
		}

		// Serialize for HTTP
		var vars = [];
		for (var x=0; x<this.s.groups.length; x++) {
			var grp = this.s.groups[x];
			for (var y=0; y<grp.ordered.length; y++) {
				var orphan = grp.ordered[y];
				var grpId = (!orphan.homeless) ? grp.id : -1;
				if (orphan.moduleId) vars.push('module['+grp.id+']['+encodeURIComponent(orphan.moduleId)+'][name]='+encodeURIComponent(orphan.name));
				if (orphan.moduleId) vars.push('module['+grp.id+']['+encodeURIComponent(orphan.moduleId)+'][active]='+encodeURIComponent(((!orphan.homeless) ? 1 : 0)));

				if (false && orphan.moduleId && this.s.showDebugs) {
					orphan.node.style.border = '1px solid yellow';
					alert('This ID is '+orphan.moduleId+'\n'+vars.join('&'));
					orphan.node.style.border = 'none';
				}
			}
		}

		// ajax out
		var pars = vars.join('&');
		if (pars != this.lastPars) {
			this.lastPars = pars;
			this.debug('AJAX out to:\n'+this.s.ajaxUrl+'&'+pars.replace('&', '\n&')+'\n');
			this.ajaxObj = new Ajax.Request(this.s.ajaxUrl, {
				method: 'post',
				parameters: pars,
				onComplete: function(req) {
					this.debug('AJAX in:\n'+req.responseText);
				}.bind(this)
			});
		} else {
			this.debug('No AJAX this time - ultimately, no change in data has occurred.');
		}
	},

	acquireRemoveButtons: function(orphan) {
		// First, clear out pre-existing remove buttons & events
		var remButton = null;
		while (remButton = orphan.removeButtons.pop()) {
			Event.unObserve(remButton.event);
		}

		// Locate remove buttons within orphan and activate them
		var remButtons = document.getElementsBySelector(this.s.removeButtonSelector, orphan.node);
		for (var z=0; z<remButtons.length; z++) {
			orphan.removeButtons.push({
				node: remButtons[z],
				event: Event.observe(remButtons[z], 'click', this.adopt.bind(this, orphan))
			});
		}
	},

	adopt: function(orphan) {
		var group = this.getGroupForOrphan(orphan);
		Effect.BlindUp(orphan.node, {
			afterFinish: function(orphan, group) {     // Blind-up the node
				Element.hide(orphan.node);
				orphan.homeless = true;
				this.refreshList();
			}.bind(this, orphan, group)
		});
	},

	// Returns a fresh, never-before-used orphan ID
	orphanId: function() {
		return this.lastOrphanId++;
	},

	getOrphanByPmid: function(orphanPmid) {
		for (var x=0; x<this.s.groups.length; x++) {
			for (var y=0; y<this.s.groups[x].orphans.length; y++) {
				if (this.s.groups[x].orphans[y].moduleId == orphanPmid) return this.s.groups[x].orphans[y];
			}
		}
		return false;
	},

	getGroupById: function(id) {
		for (var x=0; x<this.s.groups.length; x++) {
			if (this.s.groups[x].id == id) return this.s.groups[x];
		}
		return false;
	},

	getOrphanForNode: function(node) {
		for (var x=0; x<this.s.groups.length; x++) {
			for (var y=0; y<this.s.groups[x].orphans.length; y++) {
				if (this.s.groups[x].orphans[y].node == node) return this.s.groups[x].orphans[y];
			}
		}
		return false;
	},

	getGroupForOrphan: function(orphan) {
		for (var x=0; x<this.s.groups.length; x++) {
			for (var y=0; y<this.s.groups[x].orphans.length; y++) {
				if (this.s.groups[x].orphans[y].id == orphan.id) return this.s.groups[x];
			}
		}
		return false;
	},

	release: function(orphan) {
		var grp = this.getGroupForOrphan(orphan);
		var node = DOM.cut(orphan.node);

		var placeHolder = false;
		if (placeHolder = grp.insertBefore) {
			orphan.node = document.insertBefore(orphan.content, placeHolder);
		} else if (placeHolder = grp.insertAfter) {
			orphan.node = DOM.insertAfter(orphan.content, placeHolder);
		}
		if (typeof(this.s.c_beforeRelease) == 'function') this.s.c_beforeRelease(orphan);
		//Element.show(node);
		this.acquireRemoveButtons(orphan);                               // Activate "new" remove buttons in this container
		orphan.homeless = false;                                         // Mark it as having a home
		//Element.show(orphan.node);
		new Effect.BlindDown(orphan.node, {                              // Display the newly-inserted container
			afterFinish: function(orphan) {
				orphan.node.style.display = "block";
				if (typeof(this.s.c_afterRelease) == 'function') this.s.c_afterRelease(this);
				this.refreshList();
				this.fixSortables();                                         // After insertion, draggability needs to be reestablished
			}.bind(this, orphan)
		});
	},

	refreshList: function(noAjax) {
		var savedPadding = this.s.n_orphanListBox.style.padding;
		this.s.n_orphanListBox.style.padding = '1px';                    // div.box style problem
		DOM.empty(this.s.n_orphanList);                                  // Empty out the orphan list
		var orphanCount = 0;

		for (var x=0; x<this.s.groups.length; x++) {
			// Create a new heading within the orphan list, representing this group
			var h5 = document.createElement('h5');
			h5.innerHTML = this.s.groups[x].name;
			this.s.n_orphanList.appendChild(h5);

			var orphans = this.s.groups[x].orphans;

			for (var y=0; y<orphans.length; y++) {
				if (orphans[y].homeless) {
					orphanCount++;
					var p = document.createElement('p');
					p.innerHTML = '<a href="javascript:void(0);">'+orphans[y].name+'<!--InactiveModule=pmid_'+orphans[y].moduleId+'--></a>';
					orphans[y].releaseLink = this.s.n_orphanList.appendChild(p);
					orphans[y].event = Event.observe(p, 'click', this.release.bind(this, orphans[y]));
				}
			}
		}

		
		if (typeof(this.s.c_afterRefreshList) == 'function') this.s.c_afterRefreshList(this);

		if (!noAjax) this.ajax();
		
		this.hideList(orphanCount==0);
//		var direction = 'Up' ;
//
//		if (orphanCount==0)
//		{
//			direction = 'Up' ;
//		}
//		else 
//		{
//			direction = 'Down' ;
//		}
//		var afterFinish = (direction == 'Down' && typeof(this.s.c_afterRelease) == 'function') ? this.s.c_afterRelease.bind(this, this) : function() {};
//		Effect['Blind'+direction](this.s.n_orphanListBox, {
//			afterFinish: afterFinish
//		});	
		

		this.s.n_orphanListBox.style.padding = this.savedPadding;        // div.box style problem
	},

	hideList: function(bool) {
		if (bool != this.hidden) {
			this.hidden = bool;
			var direction = (this.hidden) ? 'Up' : 'Down';
			var afterFinish = (direction == 'Down' && typeof(this.s.c_afterRelease) == 'function') ? this.s.c_afterRelease.bind(this, this) : function() {};
			Effect['Blind'+direction](this.s.n_orphanListBox, {
				afterFinish: afterFinish
			});
		}
	},

	error: function(text) {
		if (this.s.showErrors) alert('OrphanManager.js Says:\n----------------------------------\nError: '+text);
	},

	debug: function(text) {
		if (this.s.showDebugs) alert('OrphanManager.js Says:\n----------------------------------\nDebug: '+text);
	},

	fixSortables: function() {
		// Loops through each group and makes its contents sortable (if they have class:sortable)
		for (var x=0; x<this.s.groups.length; x++) {
			Sortable.create(this.s.groups[x].n_container, {
				tag:      "div",
				only:     "sortable",
				handle:   "move",
				onUpdate: this.ajax.bind(this)
			});
		}
	}
};

Behaviour.addLoadEvent(function() {
	// This is disabled until Kevin gets the module display running.
	// It's interfering with Damien's module.
	om = new OrphanManager({
		ajaxUrl: '/?__ajax__=ColumnDisplayCustomize',
		n_orphanListBox: document.getElementsBySelector('div#sidebar div#pmid_36')[0],
		n_orphanList: document.getElementsBySelector('div#sidebar div#pmid_36 div.prefs')[0],
		c_getOrphanName: function(orphan) {
			var attempt = null;

			if (!DOM.isNode(attempt)) attempt = document.getElementsBySelector('h3 span.sIFR-alternate span.sIFR-alternate', orphan.node)[0];
			if (!DOM.isNode(attempt)) attempt = document.getElementsBySelector('h3 span.sIFR-alternate', orphan.node)[0];
			if (!DOM.isNode(attempt)) attempt = document.getElementsBySelector('h2 span.sIFR-alternate span.sIFR-alternate', orphan.node)[0];
			if (!DOM.isNode(attempt)) attempt = document.getElementsBySelector('h2 span.sIFR-alternate', orphan.node)[0];
			if (!DOM.isNode(attempt)) attempt = document.getElementsBySelector('h3 span', orphan.node)[0];
			if (!DOM.isNode(attempt)) {
				attempt = document.getElementsBySelector('h2', orphan.node)[0];
				if (attempt) {
					var b = null;
					while (b = attempt.getElementsByTagName('b')[0]) {
						DOM.remove(b);
					}
				}
			}
			if (DOM.isNode(attempt)) return attempt.innerHTML;
			return 'Unknown';
		},
		c_getModuleID: function(orphan) {
			var id = orphan.node.getAttribute('id');
			if (id) {
				var id2 = id.split('_');
				if (id2.length > 1) {
					if (id2[0] == 'pmid') return id2[1];
				}
			}
			return false;
		},
		c_beforeRelease: function(orphan) {
			var heading = orphan.node.getElementsByTagName('h3')[0];
			if (!heading) heading = orphan.node.getElementsByTagName('h2')[0];
			heading.innerHTML = '<span>'+orphan.name+'</span>';
			//heading.innerHTML = '<span class="sIFR-replaced"><embed width="140" height="16" src="/themes/civil/kievit_regular.swf" quality="best" flashvars="txt='+orphan.name+'&&textcolor=#8ABA68&hovercolor=#CCCCCC&linkcolor=#000000&w=140&h=16" wmode="transparent" bgcolor="transparent" sifr="true" type="application/x-shockwave-flash" class="sIFR-flash" style="width: 140px; height: 16px;"/><span class="sIFR-alternate">'+orphan.name+'</span></span>';
		},
		c_afterRelease: function() {
			EventSelectors.apply();
			do_sIFR();

		},
		c_afterRefreshList: function(who) {
			who.s.n_orphanListBox.style.margin = '0px';
			who.s.n_orphanListBox.style.margin = '0';
			who.s.n_orphanListBox.style.height = 'auto';
		},
		orphanSelector: 'div.box',                                     // Classname to identify orphans by
		removeButtonSelector: 'a.remove',                              // Classname by which to identify the "remove" button within an orphan
		groups: [
			{
				id: 0,
				name: 'Left-Column Modules',
				n_container: document.getElementById('content'),
				insertBefore: null,
				insertAfter: null,
				ordered: [],
				orphans: []
			},
			{
				id: 1,
				name: 'Right-Column Modules',
				n_container: document.getElementById('sidebar'),
				insertBefore: null,
				insertAfter: null,
				ordered: [],
				orphans: []
			}
		]
	});
});
