/*  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 + effects.js lib + images & CSS files from original facebox
 *		    Also requires ajaxtransfer js lib for Core
 *  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 = {
			followScroll: false,
			loading_image: '/images/facebox/loading.gif',
			close_image: '/images/facebox/closelabel.png',
			image_extensions: ['png', 'jpg', 'jpeg', 'gif'],
			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_t transparent"/><td class="facebox_tr transparent"/> \
								</tr> \
								<tr> \
									<td class="facebox_l transparent"></td> \
									<td class="body"> \
										<div class="toprow"> \
											<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 class="loading" > \
												<div id="facebox_responses_wrapper" class="facebox_responses_wrapper"> \
													<img src="/images/loading_sm.gif" class="facebox_responses_loading" alt="loading..." id="facebox_responses_loading" style="display: none;" /> \
													<img src="/images/icon_error_sm.png" class="facebox_responses_error transparent" alt="Error: " id="facebox_responses_error" style="display: none;" /> \
													<img src="/images/icon_success.png" class="facebox_responses_success transparent" alt="Success: " id="facebox_responses_success" style="display: none;" /> \
													<div id="facebox_responses_text" class="facebox_responses_text"></div> \
													<div style="clear: both;"></div> \
												</div> \
											</div> \
											<div style="clear: right;"></div> \
										</div> \
										<div class="content"> \
										</div> \
									</td> \
									<td class="facebox_r transparent"/> \
								</tr> \
								<tr> \
									<td class="facebox_bl transparent"></td><td class="facebox_b transparent"></td><td class="facebox_br transparent"></td> \
								</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)
	{
		if (!this.settings.followScroll) return true;
	
		// 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
					});
		}
	},
	
	watchClickEvents: function(e)
	{
		var f = this;
		$$('a[rel=facebox]').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()
	{
		this.showLoadingIndicator();
		
//		// If loading indicator is already showing, just return true
//		if ($$('#facebox .loading img').length == 1) return true;
		
		// Remove the contents of previous facebox, ITIS
		contentWrapper = $$('#facebox .content').shift();
		contentWrapper.childElements().each(function(elem, i)
		{
			elem.remove();
		});

//		// Get the loading wrapper
//		loadingWrapper = $$('#facebox .loading').shift();
//
//		// Add the loading indicator
//		loadingWrapper.insert({bottom: '<img src="'+this.settings.loading_image+'"/>'});
//		
//		// 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);
	},
	
	showLoadingIndicator: function()
	{
		ajax.showLoadingIndicator();
	},
	
	reveal: function(data, klass)
	{
		// Apply class to wrapper, ITIS
		contentWrapper = $$('#facebox .content').first();
		if (klass) contentWrapper.addClassName(klass);

		// Slide the viewport if the facebox is "above" the current viewport
//		if (document.viewport.getHeight() < 820)
		if ($('facebox').positionedOffset().top - document.body.cumulativeScrollOffset().top < 0)
		{
			window.setTimeout('Effect.ScrollTo(\'facebox\', {\'duration\': .5, \'offset\': -5});', 500);
		}
		
		// Insert the contents
		contentWrapper.setStyle('display: none;');
		contentWrapper.insert({bottom: data});

		// Graphically deliver the payload
		window.setTimeout('Effect.Grow($$(\'#facebox .content\').first(), {\'direction\': \'top-left\', \'duration\': .5});', 500);
		window.setTimeout('ajax.done(); ajax.hideLoadingIndicator();', 500);

		// 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();
	},
	
	hideLoadingIndicator: function()
	{
		// Hide the loading indicator, ITIS
		this.loading();
		loadingindicator = $$('#facebox .loading').first();
		if(loadingindicator) Effect.Fade($$('#facebox .loading').first(), {'direction': 'center', 'duration': .1});
		if(loadingindicator) Effect.Shrink($$('#facebox .loading').first(), {'direction': 'center', 'duration': .1});
		window.setTimeout('if($$(\'#facebox .loading img\').length > 0) $$(\'#facebox .loading img\').first().remove();', 500);
		
	},
	
	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 : '');

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

		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{
			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)
			{
				contentWrapper = $$('#facebox .content').first();

				// Show the loading indicator
				this.showLoadingIndicator();
				
				// Shrink the content
				new Effect.Shrink(contentWrapper, {duration: .5, direction: 'top-left'});

				// Hide the facebox
				window.setTimeout('new Effect.Fade(\'facebox\', {duration: .5});', 500);

				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]').each(function(elem, i)
	{
		$(elem).stopObserving();
	});

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

