/*
	For gallery functionality.
 	We want to cache the HTML text from the QE requests (we leave it to the browser to cache actual images etc)

	Follow variables must be set first (note query string don't start or end with ';'):

	[NOTE: global blast variables begin 'gb_']

		gb_qe_n_page_requested

		gb_qe_nossi_gallery_url	// QE base URL 
		gb_qe_base	// base of QE query (no page) e.g. [pagesize=10;...;namelength=20]
		gb_qe_search	// e.g. [attrib_1=source; ... val_2_1=]
	    gb_qe_top_level_filters  // custom query part 1
	    gb_qe_non_tax_filters // custom query part 2
	    gb_qe_tax_filters // custom query part 3

		gb_qe_caching	// append to end of url to switch QE caching on/off e.g. [SuppressCaching=1]
		gb_qe_total_hits	// total hits
		gb_qe_n_pages_total	// total pages
		gb_qe_n_current_page // number of current page

NOTE: these variables are changed externally to this script when template pages are loaded.

JA comments: could do in a more object-oriented way, with objects for each page & navigation.
Could then silo some code off for testing, e.g. to test result of calling page 3.

*/

	// allow CSS to distinguish whether glow is supported AND gallery JS is included
	if (document.documentElement && glow.isSupported) {
		document.documentElement.className += " js-gallery";
	}

var blast_gallery = (function() {

// MAINTAINED VARIABLES (all being with g_):

	var gallery = null // could be returned as a Gallery object		
		, g_lightbox = null // blast lightbox object
		, g_n_current_page = 1 // first page is fetched 'manually' (not by JS)
		, g_a_ns_page = [] // pre-fetched pages (just text)
		, g_a_ns_page_fetch = [] // set true if we're fetching or have fetched a page
		, g_ns_container = null // container nodeset
		, g_n_seconds_for_slide = 1.0 // seconds for set to slide in/out
		, g_n_set_width_px = 706 // width of gallery grid in pixels
		, g_s_select_container = '#vision-gallery-view' // contains the gallery (not replaced on JS reload)
		, g_ns_gallery = [] // nodelist corresponding to above container
		, g_s_select_load_container = '#gallery-load-message' // contains the gallery (not replaced on JS reload)
		, g_ns_load_container = [] // nodelist for above
		, g_s_id_prev_set = 'prev-set'	// container of QE output (previous page)
		, g_s_id_this_set = 'this-set'	// container of QE output (current page)
		, g_s_id_next_set = 'next-set'	// container of QE output (next page)
		, g_s_class_set = 'gallery-set' // class for container of QE output
		, g_select_page_nav = g_s_select_container + ' .gallery-page' // contains nav buttons container
		, g_select_this_page = '.this-page-num' // selects this page within nav buttons container
		, g_select_prev_btn = '.page-nav-prev input' // selects 'previous' button within nav buttons container
		, g_select_next_btn = '.page-nav-next input' // selects 'next' button within nav buttons container
		, g_s_select_prev_set = '#' + g_s_id_prev_set
		, g_s_select_this_set = '#' + g_s_id_this_set
		, g_s_select_next_set = '#' + g_s_id_next_set
		, g_n_pending = 0 // number of actions pending before next move allowed
		, g_a_listener_ids = [] // save these so we can remove them again
		, g_ns_page_nav = [] // objects corresponding to above
		, g_ns_this_page = []
		, g_ns_prev_btns = []
		, g_ns_next_btns = []
		, g_dim_to_opacity = '0.2' // opacity to dim to when reloading gallery
		, g_b_reloading = false // set true while gallery is reloading
		, request = null
		;

// FUNCTIONS:

	/*
		fire this when both animations ('this' and 'switch') are complete
		some sets passed as nodesets (to avoid re-fetching), others as ids
	*/
	function anim_complete(n_page_inc, id_drop_set, ns_this_set, ns_switch_set) {

		var dbg = 0
			, ns_drop_set = glow.dom.get('#' + id_drop_set) // set to be dropped
			, id_switch_set = ns_switch_set[0].id	// id of set to be switched in
			, new_btn_src = '' // new src value for btn image
			;

		if (dbg) { gb_lib.dbg_msg('anim_complete: pending=' + g_n_pending); }

		--g_n_pending; // count down

		// this 'complete' function is the final pending action.
		// proceed further only once BOTH animations are complete (one pending action left)
		if (g_n_pending > 1) { 
			return;
		}

		if (dbg) { gb_lib.dbg_msg('completing animation'); }

		g_n_current_page += n_page_inc; // we've moved on - this is now the page number

		// just keep 3 sets of HTML grid objects, so 'drop' one off the edge (replace the HTML)
		// relabel the two we've moved, and add a further one to fill the gap

		// re-order blocks (depends on direction of move)
		if (n_page_inc > 0) {
			ns_switch_set.after(ns_drop_set);
		}
		else {
			ns_switch_set.before(ns_drop_set);
		}

		ns_switch_set.css('left', '');
		ns_this_set.css('left', '');

		// now rename
		ns_drop_set[0].id = 'old-' + id_drop_set;
		ns_this_set[0].id = id_drop_set;
		ns_switch_set[0].id = g_s_id_this_set;
		ns_drop_set[0].id = id_switch_set; // re-use this 'dropped' set by replacing its HTML
		
		// now relabelled, CSS will be applied from stylesheet to the moved sets:
		ns_switch_set.css('visibility', ''); // drop the inline style to avoid complications.

		// really need a callback here for when this finishes.
		set_missing_page(g_n_current_page + n_page_inc, ns_drop_set, on_missing_page_load);

		// alter buttons as we scroll to each end

		g_ns_this_page.val(g_n_current_page);

		// disable/enable buttons when arriving at / leaving the ends
		// (JA: could reset (enable), then check & disable as necessary to simplify this code)
		if (g_n_current_page == 2 && n_page_inc > 0) {
			new_btn_src = g_ns_prev_btns.attr('src').replace('_dis', ''); // value for first node
			g_ns_prev_btns.attr('src', new_btn_src) ;
			g_ns_prev_btns.removeAttr('disabled').removeClass('disabled');
		}
		else if (g_n_current_page == 1 && n_page_inc < 0) {
			new_btn_src = g_ns_prev_btns.attr('src').replace('_prev', '_prev_dis');
			g_ns_prev_btns.attr('src', new_btn_src);
			g_ns_prev_btns.attr('disabled', 'disabled').addClass('disabled');
		}

		if (g_n_current_page == gb_qe_n_pages_total - 1 && n_page_inc < 0) {
			new_btn_src = g_ns_next_btns.attr('src').replace('_dis', '');
			g_ns_next_btns.attr('src', new_btn_src);
			g_ns_next_btns.removeAttr('disabled').removeClass('disabled');
		}
		else if (g_n_current_page == gb_qe_n_pages_total && n_page_inc > 0) {
			new_btn_src = g_ns_next_btns.attr('src').replace('_next', '_next_dis');
			g_ns_next_btns.attr('src', new_btn_src);
			g_ns_next_btns.attr('disabled', 'disabled').addClass('disabled');
		}

		g_n_pending = 0; // nothing pending
	}
	//-----

	// attach nav actions to whatever occupies the "current" set
	function attach_nav_actions() { // set containing controls

		var dbg = 0
			;

		if (dbg > 1) { gb_lib.dbg_msg('attach_nav_actions:\n'
			+ '\nNext btns: ' + g_ns_next_btns.length 
			+ '\nPrev btns: ' + g_ns_prev_btns.length); }

		g_a_listener_ids.push(
			glow.events.addListener(g_ns_next_btns, 'click', 
				function(g_evt) { if (dbg) { gb_lib.dbg_msg('next'); } switch_page(+1); return false; }
			)
		);

		g_a_listener_ids.push(
			glow.events.addListener(g_ns_prev_btns, 'click', 
				function(g_evt) { if (dbg) { gb_lib.dbg_msg('prev'); } switch_page(-1); return false; }
			)
		);

		if (dbg) { gb_lib.dbg_msg('Added with ids: ' + g_a_listener_ids); }
	}
	//-----

	/* 
		Stores the given, loaded page.
		Used e.g. when a page has been loaded statically.
	*/
	function cache_current_page(n_page) {
		g_a_ns_page[n_page] = glow.dom.get(g_s_select_this_set).html();
		g_lightbox.mapPage(g_a_ns_page[n_page],n_page);
	}
	//-----

	/*
		actions which take place once extra pages have loaded.
		if n_inc > 0, page was to be linked to as 'next'; if n_inc < 0, page was to be linked to as 'prev'
	*/
	function on_missing_page_load(n_page) {

		var dbg = 0
			;

		if (dbg) { gb_lib.dbg_msg('page ' + n_page + ' has loaded'
			+ '\nnext btn points to page ' + g_ns_next_btns._points_to_page
			+ '\nprev btn points to page ' + g_ns_prev_btns._points_to_page); }

		if (n_page == g_ns_next_btns._points_to_page) {
			if (dbg) { gb_lib.dbg_msg('Enable next button'); }
			g_ns_next_btns.removeClass('hidden');
		}

		if (n_page == g_ns_prev_btns._points_to_page) {
			if (dbg) { gb_lib.dbg_msg('Enable prev button'); }
			g_ns_prev_btns.removeClass('hidden');
		}

		//	Fire gallery events
		glow.events.fire(gallery,"pageLoad");

	}
	//-----

	/*
		return the url for fetching a whole or partial page. 
		page: number of page to load
		template (optional): use this for output (if omitted, default template from config will be used)
	*/
	function query_url(n_page, template) {

		var dbg = 0
			, qe_filters = gb_qe_top_level_filters + ';' + gb_qe_non_tax_filters + ';' + gb_qe_tax_filters + ';' + gb_qe_sort_filters
			, qe_fwd = gb_qe_fwd_top_level + ';' + gb_qe_fwd_non_tax + ';' + gb_qe_fwd_tax + ';' + gb_qe_fwd_sort
			;

		return gb_qe_gallery_url + '?' 
			+ 'ContentType=text%2Fhtml%3B+charset%3Dutf-8' // required for IE6 (UTF-8 or utf-8) to avoid "system error: -1072896658"
			+ ';' + gb_qe_view
			+ ';config=' + gb_qe_browse_config
			+ (template ? (';Template=' + gb_qe_browse_js_template) : '')
			+ ';' + qe_filters
			+ ';' + qe_fwd
			+ ';page=' + n_page
			+ ';called_from=javascript'
			+ gb_qe_caching

	}
	//-----

	/*
		indicate visually that gallery is reloading
	*/
	function gallery_before_load() {
		var dbg = 0;
		glow.anim.css(g_ns_gallery, 0.3, { 
				'opacity': { 'to': g_dim_to_opacity } 
			}, 
			{
				tween: glow.tweens.easeOut() 
			}
		).start();
		g_ns_load_container.css('visibility', 'visible');
		if (dbg) { gb_lib.dbg_msg('gallery_before_load executed'); }
	}
	//-----

	/*
		indicate visually that gallery has loaded
	*/
	function gallery_after_load() {
		var dbg = 0;
		g_ns_load_container.css('visibility', 'hidden');
		glow.anim.css(g_ns_gallery, 1.0, { 
				'opacity': { 'to': '1.0'} 
			}, 
			{
				tween: glow.tweens.easeBoth() 
			}
		).start();
		if (dbg) { gb_lib.dbg_msg('gallery_after_load executed'); }
	}
	//-----

	/*
		reload the whole gallery with a new set of search parameters.
		callback_on_finish: optional callback once requested action is finished
	*/
	function reload_gallery() {

		var dbg = 0
			, url = ''
			//, request = null
			, ns_set = g_ns_gallery
			, i = 0 // loop counter
			, ns_this_set = []
			;

		if (g_b_reloading) { // don't start if already reloading
			return;
		}

		g_b_reloading = true;

		// clean up listeners and clear out saved pages
		for (i = 0; g_a_listener_ids[i]; ++i) {
			glow.events.removeListener(g_a_listener_ids[i]);
		}

		g_a_ns_page.length = 0; // clear cache

		url = query_url(1);

		if (dbg > 1) { gb_lib.dbg_msg('reloading page:\n\n' + url); }

		//	Clear out page fetch status and abort previous requests
		g_a_ns_page_fetch = [];
		if (request !== null) {
			request.abort();
		}

		request = glow.net.get(url,
			{
				onLoad: function(response) {

					if (dbg > 1) { gb_lib.dbg_msg('new gallery fetched: [' + response.status + "] (" + response.statusText() + ")"
							+ '\n' + url); }

					ns_set.html(response.text());
					g_b_reloading = false; // some processing still to go, but corec gallery reloaded
					gallery_after_load();
					setup_page(1);

					//	Update total hits and total pages js vars
					gb_qe_total_hits = parseInt(glow.dom.get("#total_hits").text());
					gb_qe_n_pages_total = parseInt(glow.dom.get("input.total-page-num").val());

					//	Fire afterReload event
					glow.events.fire(gallery,"afterReload");

					if (dbg > 0) { 
						var ns_dbg = ns_set.get('.item'); gb_lib.dbg_msg('Found ' + ns_dbg.length + ' items '
							+ 'in first page from\n' + url); 
					}
				},
				onError: function(response) {
					if (dbg) {gb_lib.dbg_msg("Error getting Gallery file: " + response.statusText());}
				}
			});
		
		if (dbg) { gb_lib.dbg_msg('reload_gallery executed'); }

	}
	//-----

	/*
		set up a newly loaded page.
	*/
	 
	function setup_page(n_page) {

		var dbg = 0
			, ns_this_set = glow.dom.get(g_s_select_this_set)
			, ns_prev_set = glow.dom.get('#' + g_s_id_prev_set)
			, ns_next_set = glow.dom.get('#' + g_s_id_next_set)
			;

		// store the newly loaded page in the cache
		cache_current_page(n_page);

		// get the navigation buttons
		g_ns_page_nav = glow.dom.get(g_select_page_nav);
		g_ns_this_page = g_ns_page_nav.get(g_select_this_page);
		g_ns_prev_btns = g_ns_page_nav.get(g_select_prev_btn);
		g_ns_next_btns = g_ns_page_nav.get(g_select_next_btn);

		// insert the empty containers for result sets
//		ns_this_set.before(ns_prev_set);
//		ns_this_set.after(ns_next_set);

		g_n_current_page = parseInt(n_page || 1);

		if (dbg  > 1) { gb_lib.dbg_msg('current page: ' + g_n_current_page + '\ntotal pages: ' + gb_qe_n_pages_total); }

		// anticipate where next/prev buttons will point after loading 
		g_ns_prev_btns._points_to_page = parseInt(n_page) - 1;
		g_ns_prev_btns.addClass('hidden');
		if (dbg > 1) { gb_lib.dbg_msg('Prev btn will point to page ' + g_ns_prev_btns._points_to_page); }

		g_ns_next_btns._points_to_page = parseInt(n_page) + 1;
		g_ns_next_btns.addClass('hidden');
		if (dbg > 1) { gb_lib.dbg_msg('Next btn will point to page ' + g_ns_next_btns._points_to_page); }

		// make the buttons work JavaScriptly - now only need to do this once
		attach_nav_actions();
		
		//set gallery thumbnails to open a lightbox
		if (dbg) { gb_lib.dbg_msg('gal:setting lightbox events'); }
		g_lightbox.set_events(ns_this_set);

		// if appropriate, we need the pages either side
		set_missing_page(g_n_current_page + 1, glow.dom.get(g_s_select_next_set), on_missing_page_load);
		set_missing_page(g_n_current_page - 1, glow.dom.get(g_s_select_prev_set), on_missing_page_load);

	}
	//-----

	/*
		sets the missing (e.g. dropped) page following a move.
		if the move was to increasing page number, we may need to fetch the page first.

	*/
	function set_missing_page(
		  n_page	// which page to load
		, ns_set	// where to put it
		, callback_on_load // optional callback once requested action is finished, passing the page number
		) { 

		var dbg = 0
			, url = query_url(n_page, gb_qe_browse_js_template)
			//, request = null
			;

		if (dbg > 2) { gb_lib.dbg_msg('set_missing_page(' + n_page + ') fetch=' + !!g_a_ns_page_fetch[n_page]); }

		//If page is already being fetch do nothing
		if (g_a_ns_page_fetch[n_page]) {		
// EARLY RETURN:
			//if (callback_on_load) { callback_on_load(n_page); }
			return;
		}
		//If invalid page requested
		if (n_page < 1 || n_page > gb_qe_n_pages_total) {
			ns_set.html('');
// EARLY RETURN:
			if (callback_on_load) { callback_on_load(n_page); }
			return;
		}
		if (g_a_ns_page[n_page]) { // get HTML text from cache
			if (dbg > 1) { gb_lib.dbg_msg('setting page ' + n_page + ' from cache'); }
			ns_set.html(g_a_ns_page[n_page]);
			
			//set gallery thumbnails to open a lightbox
			if (dbg) { gb_lib.dbg_msg('gal: calling set_events for cached page'); }
			g_lightbox.set_events(ns_set);
			
			if (callback_on_load) { callback_on_load(n_page); }
// EARLY RETURN:
			return;
		}

		g_a_ns_page_fetch[n_page] = true; // use to prevent us fetching a page that has been requested but not yet loaded

		if (dbg > 1) { gb_lib.dbg_msg('loading data for page(' + n_page + ')'); }

		request = glow.net.get(url,
			{
				onLoad: function(response) {

					if (dbg > 1) { gb_lib.dbg_msg('set for page '+n_page+' fetched: [' + response.status + "] (" + response.statusText() + ")"
							+ '\n' + url); }

					if (dbg > 0) { 
						var ns_dbg = ns_set.get('.item'); gb_lib.dbg_msg('Found ' + ns_dbg.length + ' items '
							+ 'for page ' + n_page); 
					}

					g_a_ns_page[n_page] = response.text(); // add to cache
					g_a_ns_page_fetch[n_page] = false;
					ns_set.html(g_a_ns_page[n_page]);

					//	Add the page to the lightbox navigation map
					g_lightbox.mapPage(g_a_ns_page[n_page],n_page);

					//set gallery thumbnails to open a lightbox
					if (dbg) { gb_lib.dbg_msg('gal:calling set_events for js loaded page'); }
					g_lightbox.set_events(ns_set);

					if (callback_on_load) { callback_on_load(n_page); }
				},
				onError: function(response) {
					g_a_ns_page_fetch[n_page] = false;
					if (dbg) {gb_lib.dbg_msg("Error getting Gallery file: " + response.statusText())};
				}
			});

	}
	//-----

	/*
		switch to a new page (the 'switch' page), dropping one page (if present) to keep only 3 sets
		page_inc: = +1 (next, leftwards) or -1 (prev, rightwards)
	*/
	function switch_page(n_page_inc) {

		var dbg = 0
			, n_page_to_switch_to = g_n_current_page + n_page_inc
			, id_switch_set = (n_page_inc > 0 ? g_s_id_next_set : g_s_id_prev_set)
			, id_drop_set = (n_page_inc > 0 ? g_s_id_prev_set : g_s_id_next_set)
			, ns_this_set = null // container for all current gallery page content
			, ns_switch_set = null // container for switch 
			, fn_complete = function() {}
			, anim_this = null
			, anim_switch = null
			;

		if (dbg) { gb_lib.dbg_msg('switch page from (' + g_n_current_page + ') by (' + n_page_inc + ') - pending=' + g_n_pending); }

		if (n_page_to_switch_to < 1 || n_page_to_switch_to > gb_qe_n_pages_total)
			return;

		if (g_n_pending > 0) // don't fire again until all pending actions are complete
			return;

		g_n_pending = 3; // two moves + one completion action

		// hide the nav buttons unless the new page already exists

		// before switching, our current page is 'n'
		// we CAN'T rely on the button in the other direction pointing at an existing page - this might not have loaded yet. 
		// these properties will be overridden by later calls.
		g_ns_prev_btns._points_to_page = parseInt(n_page_to_switch_to) - 1;
		g_ns_next_btns._points_to_page = parseInt(n_page_to_switch_to) + 1;

		if (dbg) { gb_lib.dbg_msg('Prev btns point to page ' + g_ns_prev_btns._points_to_page + '; Next btns point to page ' + g_ns_next_btns._points_to_page); }

		// hide these buttons. Should be unhidden when the page is loaded
		if (!g_a_ns_page[g_ns_next_btns._points_to_page]) {
			if (dbg) gb_lib.dbg_msg('Page ' + g_ns_next_btns._points_to_page + ' (new target of next btn) is not in cache - will hide next buttons');
			g_ns_next_btns.addClass('hidden');
		}
		if (!g_a_ns_page[g_ns_prev_btns._points_to_page]) {
			if (dbg) gb_lib.dbg_msg('Page ' + g_ns_prev_btns._points_to_page + ' (new target of prev btn) is not in cache - will hide prev buttons');
			g_ns_prev_btns.addClass('hidden');
		}

		// fetch the nodesets
		ns_this_set = glow.dom.get(g_s_select_this_set);
		ns_switch_set = glow.dom.get('#' + id_switch_set);

		if (dbg) gb_lib.dbg_msg('Switch page: pending actions=' + g_n_pending);

		if (dbg) gb_lib.dbg_msg("NEXT: Found " + ns_this_set.length + " this sets and " + ns_switch_set.length + " switch sets with "
			+ ns_switch_set.get('.item').length + ' items');

		if (ns_switch_set.get('.item').length < 1) {
			if (dbg) gb_lib.dbg_msg('no items in next set');

			g_n_pending = 0;
			return; // nothing to move to
		}

		// set up animations for each, then set them off (nearly) together
		// my preferences is tweens.linear() plus n_secs/3 for time. But what do I know.
		anim_this = glow.anim.css(ns_this_set, g_n_seconds_for_slide
			, { 'left': {to: (parseInt(ns_this_set.css('left')) - (n_page_inc * g_n_set_width_px))} }
			, { 
				'tween': glow.tweens.easeBoth() 
			}
		);

		anim_switch = glow.anim.css(ns_switch_set, g_n_seconds_for_slide
			, { 'left': {to: (parseInt(ns_switch_set.css('left')) - (n_page_inc * g_n_set_width_px))} }
			, { 
				'tween': glow.tweens.easeBoth() 
			}
		);

		fn_complete = function() { anim_complete(n_page_inc, id_drop_set, ns_this_set, ns_switch_set); };
		glow.events.addListener(anim_this, 'complete', fn_complete);
		glow.events.addListener(anim_switch, 'complete', fn_complete);

		ns_switch_set.css('visibility', 'visible'); // will be hidden to avoid tabbing into it
		anim_this.start();
		anim_switch.start();
	}
	//-----

	gallery = {

		// set up the gallery
		init: function(lightbox) {  // page which has been loaded statically
			
//			gb_lib.dbg_msg('version: ' + glow.env.version);
//			gb_lib.dbg_msg('webkit: ' + glow.env.webkit);
// Safari 2 has webkit 418.9.1 on vnc test bench
			
			g_lightbox = lightbox;

			g_ns_gallery = glow.dom.get(g_s_select_container); 
			g_ns_load_container = glow.dom.get(g_s_select_load_container);

			setup_page(gb_qe_n_page_requested);
		},
		//-----

		// reload the whole gallery JavaScriptly
		reload: function(opts) {  

			var opt_name = ''
				;

			if (opts) {
				gb_qe_non_tax_filters = opts['qe_non_tax_filters'] || gb_qe_non_tax_filters;
				gb_qe_tax_filters = opts['qe_tax_filters'] || gb_qe_tax_filters;
				gb_qe_fwd_non_tax = opts['qe_fwd_non_tax'] || gb_qe_fwd_non_tax;
				gb_qe_fwd_tax = opts['qe_fwd_tax'] || gb_qe_fwd_tax;
			}

			reload_gallery();
		},
		//-----

		// show visually that gallery is about to reload
		loading: function() {
			gallery_before_load();	
		},
		//-----

		// returns true if gallery is reloading
		is_reloading: function() {
			return g_b_reloading;	
		},
		//-----

		//	wrapper to switch_page() to be used outside of the gallery object
		move:function (distance) {
			switch_page(distance);
		},

		dummy_field: null // so we can have trailing commas on the other fields
	};

	return gallery;

})();

// end of scripts
