/*  Facebox for Prototype, version 2.0
 *  By Robert Gaal - http://wakoopa.com 
 *
 *  Heavily based on Facebox by Chris Wanstrath - http://famspam.com/facebox
 *  First ported to Prototype by Phil Burrows - http://blog.philburrows.com
 *
 *  Licensed under the MIT:
 *  http://www.opensource.org/licenses/mit-license.php
 *
 *  Need help?  Join the Google Groups mailing list:
 *  http://groups.google.com/group/facebox/
 *
 *  Dependencies:   prototype & script.aculo.us + images & CSS files from original facebox
 *  Usage:          Append 'rel="facebox"' to an element to call it inside a so-called facebox
 *
 *--------------------------------------------------------------------------*/

var Facebox = Class.create({
	initialize: function(extra_set)
	{
		this.locked = false;
		this.isopen = false;
		this.pagename = '';
		this.cbparams = '';
		this.onclose = '';
		this.scrollingrequests = 0;

		this.settings = {
			loading_image: '/images/facebox/loading.gif',
			close_image: '/images/facebox/closelabel.gif',
			image_types: new RegExp('\.' + ['png', 'jpg', 'jpeg', 'gif'].join('|') + '$', 'i'),
			inited: true,	
			facebox_html: '\
				  <div id="facebox" style="display:none;"> \
				    <div class="popup"> \
				      <table id="facebox_table"> \
					<tbody> \
					  <tr> \
					    <td class="facebox_tl transparent"/><td class="facebox_b transparent"/><td class="facebox_tr transparent"/> \
					  </tr> \
					  <tr> \
					    <td class="facebox_b transparent"/> \
					    <td class="body"> \
					      <div class="content"> \
					      </div> \
					      <div class="footer"> \
						<a href="#" class="close"> \
						  <img src="'
				};

					this.settings.facebox_html = this.settings.facebox_html + this.settings.close_image + '" title="close" class="close_image" /> \
						</a> \
					      </div> \
					    </td> \
					    <td class="facebox_b transparent"/> \
					  </tr> \
					  <tr> \
					    <td class="facebox_bl transparent"/><td class="facebox_b transparent"/><td class="facebox_br transparent"/> \
					  </tr> \
					</tbody> \
				      </table> \
				    </div> \
				  </div>';


		if (extra_set) Object.extend(this.settings, extra_set);
		$(document.body).insert({bottom: this.settings.facebox_html});
		
		this.preload = [ new Image(), new Image() ];
		this.preload[0].src = this.settings.close_image;
		this.preload[1].src = this.settings.loading_image;
		
		f = this;
		$$('#facebox .b:first-child, #facebox .bl, #facebox .br, #facebox .tl, #facebox .tr').each(function(elem){
			f.preload.push(new Image());
			f.preload.slice(-1).src = elem.getStyle('background-image').replace(/url\((.+)\)/, '$1');
		});
		
		this.facebox = $('facebox');
    		this.keyPressListener = this.watchKeyPress.bindAsEventListener(this);
    		this.scrollListener = this.watchScroll.bindAsEventListener(this);
		
		this.watchClickEvents();
		fb = this;
		Event.observe($$('#facebox .close').first(), 'click', function(e){
			Event.stop(e);
			fb.close(true);
		});
		Event.observe($$('#facebox .close_image').first(), 'click', function(e){
			Event.stop(e);
			fb.close(true);
		});
	},
	
	watchKeyPress: function(e)
	{
		// Close if espace is pressed or if there's a click outside of the facebox
		if (this.isopen && (e.keyCode == 27))// || !Event.element(e).descendantOf(this.facebox)))
		{
			this.close();
		}
	},
	
	watchScroll: function(e)
	{
		// IE seems to fire several scroll events for a single user scroll action, instead of one.  This causes some glitchiness in the animation...
		// To resolve this, we use a short time internal to "compress" all of the near-instantly-sequential events into one: the last one:
		
		// Increment the scrollingrequests counter (to mark that we're sending a request)
		this.scrollingrequests++;
		// In 50 milliseconds, check if this is the last request, and if so, do the scroll
		window.setTimeout('facebox.doScroll('+this.scrollingrequests+');', 50);
	},
	
	doScroll: function(scrollingrequests)
	{
		if (scrollingrequests == this.scrollingrequests)
		{
			this.scrollingrequests = 0;

			// Slide the facebox to realign it with the scrolled document
			var pageScroll = document.viewport.getScrollOffsets();
			new Effect.Move(this.facebox, {
					x: parseInt(document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2)),
					y: parseInt(pageScroll.top + (document.viewport.getHeight() / 10)),
					mode: 'absolute',
					duration: 1
					});

//			// Move the facebox to realign it with the scrolled document
//			this.facebox.setStyle({
//				'top': parseInt(pageScroll.top + (document.viewport.getHeight() / 10)) + 'px',
//				'left': parseInt(document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2)) + 'px'
//			});
		}
	},
	
	watchClickEvents: function(e)
	{
		var f = this;
		$$('a[rel=facebox], a[rel=facebox_blue]').each(function(elem,i)
		{
			Event.observe(elem, 'click', function(e)
			{
				// Get the pagename from the href
				pagename = '';
				href = elem.href.toString();
				
				// Get the pagename from the filename
				pagename = href.split('.php');
				pagename = pagename.shift().split('/');
				pagename = pagename.pop();

				// Get the onclose from the querystring, ITIS
				onclose = '';
				qs = elem.href.toString();
				qs = qs.split('?');
				qs = qs.pop().split('&');

				regexp = /^onclose=/i;
				for (i = 0; i < qs.length; i++)
				{
					if (qs[i].replace(regexp, '') != qs[i])
					{
						onclose = qs[i].replace(regexp, '').replace(':', '=');
					}
				}

				// Get the cbparams from the querystring, ITIS
				cbparams = '';
				qs = elem.href.toString();
				qs = qs.split('?');
				qs = qs.pop().split('&');

				regexp = /^cbparams=/i;
				for (i = 0; i < qs.length; i++)
				{
					if (qs[i].replace(regexp, '') != qs[i])
					{
						cbparams = qs[i].replace(regexp, '').replace(':', '=');
					}
				}

				Event.stop(e);
				f.click_handler(elem, e, pagename, cbparams, onclose);
			});
		});
	},

	lock: function()
	{
		this.locked = true;
	},
	
	unlock: function()
	{
		this.locked = false;
	},
	
	loading: function()
	{
		// If loading indicator is already showing, just return true
		if ($$('#facebox .loading').length == 1) return true;
		
		// Remove the contents of previous facebox, ITIS
		contentWrapper = $$('#facebox .content').shift();
		contentWrapper.childElements().each(function(elem, i)
		{
			elem.remove();
		});
		
		// Add the loading indicator
		contentWrapper.insert({bottom: '<div class="loading"><img src="'+this.settings.loading_image+'"/></div>'});
		
		// Align the facebox
		var pageScroll = document.viewport.getScrollOffsets();
		this.facebox.setStyle({
			'top': parseInt(pageScroll.top + (document.viewport.getHeight() / 10)) + 'px',
			'left': parseInt(document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2)) + 'px'
		});
		
    		// (Re)Start listeners
    		Event.stopObserving(document, 'keypress', this.keyPressListener);
    		Event.stopObserving(document, 'click', this.keyPressListener);
    		Event.stopObserving(window, 'scroll', this.scrollListener);
    		Event.observe(document, 'keypress', this.keyPressListener);
    		Event.observe(document, 'click', this.keyPressListener);
    		Event.observe(window, 'scroll', this.scrollListener);
	},
	
	reveal: function(data, klass)
	{
		// Hide the loading indicator, ITIS
		this.loading();
		load = $$('#facebox .loading').first();
		if(load) load.remove();
		
		// Apply class to wrapper, ITIS
		contentWrapper = $$('#facebox .content').first();
		if (klass) contentWrapper.addClassName(klass);
		
		// Insert the contents
		contentWrapper.insert({bottom: data});
		
		// Show the facebox contents, if necessary
		if(!this.facebox.visible())
		{
			$$('#facebox .content').first().childElements().each(function(elem,i)
			{
				elem.show();
			});
		}

		// Align the facebox
		this.facebox.setStyle({
			'left': document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2) + 'px'
		});

    		// (Re)Start listeners
    		Event.stopObserving(document, 'keypress', this.keyPressListener);
    		Event.stopObserving(document, 'click', this.keyPressListener);
    		Event.stopObserving(window, 'scroll', this.scrollListener);
		Event.observe(document, 'keypress', this.keyPressListener);
		Event.observe(document, 'click', this.keyPressListener);
    		Event.observe(window, 'scroll', this.scrollListener);
		
		this.unlock();
	},
	
	open: function(elem, pagename, cbparams, onclose)
	{
		this.loading();

		// Save the pagename
		this.pagename = (pagename ? pagename : '');

		// Save the cbparams
		this.cbparams = (cbparams ? cbparams : '');

		// Save the onclose
		this.onclose = (onclose ? onclose : '');

		// Check for a blue-bordered facebox request
		href_tmp = elem;
		try
		{
			if (elem.href.match(/#/))
			{
				href_tmp = elem.href;
			}
		}catch(e){
			href_tmp = elem;
		}
		href_tmp = href_tmp.toString();
		if (href_tmp.match(/fbblueborders/))
		{
			this.facebox.addClassName('fbblueborders');
		}else{
			this.facebox.removeClassName('fbblueborders');
		}

		// Show the facebox
		new Effect.Appear(this.facebox, {duration: .3});

		this.isopen = true;

		elemIsURL = false;
		try
		{
			if (elem.href.match(/#/)) {}
		}catch(e){
			elemIsURL = true;
		}

		if (elem.toString() == elem && elemIsURL)
		{
			url = elem;
			elem = null;
			elem = [];
			elem.href = url;
		}else{
			// support for rel="facebox[.inline_popup]" syntax, to add a class
			var klass = elem.rel.match(/facebox\[\.(\w+)\]/);
			if (klass) klass = klass[1];
		}

		if (elem.href.match(/#/))
		{
			var url = window.location.href.split('#')[0];
			var target = elem.href.replace(url+'#','');

			// var data = $$(target).first();
			var d = $(target);
			
			// create a new element so as to not delete the original on close()
			var data = new Element(d.tagName);
			data.innerHTML = d.innerHTML;
			this.reveal(data, klass);
		}else if (elem.href.match(this.settings.image_types))
		{
			var image = new Image();
			fb = this;
			image.onload = function() {
				fb.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
			}
			image.src = elem.href;
		}else{
			var fb  = this;
			var url = elem.href+(elem.href.indexOf('?') > 0 ? '&skin=none' : '?skin=none');

			new Ajax.Request(url,
			{
				method: 'get',
				requestTimeout: 1,
				
				onSuccess: function(transport)
				{
					fb.reveal(transport.responseText, klass);
				},

				onFailure: function(transport)
				{
					fb.reveal(transport.responseText, klass);
				},
				
				onTimeout: function(transport)
				{
					fb.reveal('<div class="regularcontent"><h1>Loading time out</h1><p>Oops! It looks like a network failure occured or this page took too long to respond. Please try again.</p></div>', klass);
				}
			});
		}
	},
	
	close: function(forced, params)
	{
		// Data protection
		forced = (forced == true ? true : false);
		params = (params != null ? params : '');

		if (!this.locked || forced)
		{
			this.lock();

			// Verify with the onclose function that we can move forward with the close
			goahead = true;
			if (this.onclose != '') 
			{
				if (eval(onclose+'(\''+this.pagename+'\');') == false)
				{
					goahead = false;
				}
			}

			if (goahead)
			{
				new Effect.Fade('facebox', {duration: .3});

				if (this.pagename != '')
				{
					// Run the close callback function on the dashboard
					params = this.cbparams.toString() + params.toString();
					dashboard_closefaceboxcb(this.pagename, params, this.onclose);
				}

				this.isopen = false;

				this.unlock();
			}
		}
	},
	
	click_handler: function(elem, e, pagename, cbparams, onclose)
	{
		Event.stop(e);
			
		this.open(elem, pagename, cbparams, onclose);
	}
});





var facebox;
// Initial facebox is loaded at bottom of refering page...

function reloadFaceboxCodeObject()
{
	// Stop observing keypresses and scrolls
	facebox.keyPressListener = null;
	facebox.scrollListener = null;

	// Stop observing link clicks
	$$('a[rel=facebox], a[rel=facebox_blue]').each(function(elem, i)
	{
		$(elem).stopObserving();
	});

	// Restart observations
	facebox.keyPressListener = facebox.watchKeyPress.bindAsEventListener(facebox);
	facebox.scrollListener = facebox.watchScroll.bindAsEventListener(facebox);
	facebox.watchClickEvents();
}



