// Namespace object for current site
cTFO = function(){
	
	this.ui = new cUI(this);
	
	this.galleries = {}
	this.timers = {}
	
	this.slideshow_timer_interval = 1000; // Milliseconds
	
	// Initialize function
	this.initPage = function(){
	
		// Convert any contact forms present
		var $this = this;
		$('form.contactform').each(function(){
			$this.convertContactForm(this);
		});
		
		// Init UI
		this.ui.initPage();
		
		return this;
	} // this.initPage()
	
	// Error handling method
	this.showError = function(v_msg){
		alert(v_msg);
		return this;
	} // this.showError()
	
	// Create a new gallery object structure
	var _createGalleryObj = function(){
		return {
			
			'images'		: new Array(),
			'loaded'		: false,
			'initialising'	: false,
			'running'		: false,
			'slideshows'	: new Array(),
			'timer'			: null
		}
	}.bind(this) // _createGalleryObj()
	
	// Create a new gallery object structure
	var _createSlideshowObj = function(){
		return {
			'images'		: new Array(),
			'current_idx'	: 0,
			'domnode'		: null
		}
	}.bind(this) // _createGalleryObj()
	
	// Load an array of images into a gallery object
	this.preloadImages = function(v_gallery_name, o_snippet_data){
		
		// Create gallery 
		if (v_gallery_name.length < 1){return this;}
		var o_gallery = _createGalleryObj();
		
		// Verify snippet call
		if (!o_snippet_data.success){
			alert('ERROR - ' + (o_snippet_data.error ? o_snippet_data.error : 'Unspecified object error'));
			return this;
		}

		// Start a timer to cache each images into cache
		if (o_snippet_data.images.length < 1){return this;}
		for (var i = 0; i < o_snippet_data.images.length; i++){
			var o_img = new Image();
			var o_obj = {'image': o_img, 'loaded': false}
			$(o_obj.image).load(function(){
				this.gallery.loaded = this.image.loaded = true;				
			}.bind({'gallery': o_gallery, 'image': o_obj}));
			o_obj.image.src = o_snippet_data.images[i];			
			o_gallery.images.push(o_obj)
		}
		
		this.galleries[v_gallery_name] = o_gallery;
		return this;
		
	}
	
	// Load an array of images into a gallery object
	this.startSyncSlideshows = function(v_gallery_name, a_slideshows, o_options){
		
		if (!this.galleries[v_gallery_name]){
			alert('ERROR - Image gallery "' + v_gallery_name + '" not initialised.');
			return this;
		} else {
			var o_gallery = this.galleries[v_gallery_name];
		}
	
		// If image cache is loaded, then start the slideshows
		if (o_gallery.loaded){
			
			// Stop the timer
			if (this.timers.slideshow_init){
				clearInterval(this.timers.slideshow_init);
				delete (this.timers.slideshow_init);
			}
			
			// Kick it off..
			return this.startSlideshows(o_gallery, a_slideshows, o_options);
			
		} else {
			
			// Not loaded yet, check if our interval timer has started
			if (!this.timers.slideshow_init){
				this.timers.slideshow_init = setInterval(function(){
					this.startSyncSlideshows(v_gallery_name, a_slideshows, o_options);
				}.bind(this), this.slideshow_timer_interval);
			}			
			
		}

		return this;
	} // this.startSyncSlideshows()
	
	// Syncronise and start the slideshows
	this.startSlideshows = function(o_gallery, a_slideshows, o_options){
		
		// Check we are not running
		if (o_gallery.initialising || o_gallery.running){return this;}
		
		// Start the initialisation
		o_gallery.initialising = true;
		
		// Create the slideshow frames
		$(a_slideshows).each(function(v_idx){
			
			// Create slideshow object and add to the gallery
			var o_ss = _createSlideshowObj();
			o_gallery.slideshows[v_idx] = o_ss;			
			
			// Configure the slideshow
			o_ss.domnode = $(this);
			o_ss.current_idx = 0;
			
		});
		
		// Allocate images from the gallery to each slideshow
		// (Divide equally the images amongst the slideshows)
		var v_ss_count = o_gallery.slideshows.length;
		var v_img_count = o_gallery.images.length;
		var v_img_counter = 0;
		var v_img_per_ss = Math.floor(v_img_count / v_ss_count);
		for (var i = 0; i < v_ss_count; i++){
			for (var j = 0; j < v_img_per_ss; j++){
				o_gallery.slideshows[i].images[j] = o_gallery.images[v_img_counter];
				v_img_counter++;
			}				
		}
		
		// Create the image DOM nodes for each slideshow
		for (var i = 0; i < v_ss_count; i++){
			var o_ss = o_gallery.slideshows[i];
			var a_slides = o_ss.domnode.find('div.slide');
			for (var j = 0; j < o_ss.images.length; j++){
				
				// Is this image already present? (Via page markup)
				a_slides.each(function(){
					console.log(this);
				});
				
				// Create an image slide
				var o_img = $('<img/>').attr('src', o_ss.images[j].image.src);
				var o_slide = $('<div/>').css({'display': 'none'}).addClass('slide').append(o_img);
				o_ss.domnode.append(o_slide);
				
				// Convert the object property to the DOM node
				o_ss.images[j].image = o_img;
				o_ss.images[j].slide = o_slide;
				
			}
		}
		
		o_gallery.running = true;
		
		// Fade in the first images (one after the other)
		for (var i = 0; i < v_ss_count; i++){
			var o_ss = o_gallery.slideshows[i];
			o_gallery.slideshows[i].images[0].slide.fadeIn(1600);
		}
		
		// Start a timer to handled the rest
		o_gallery.timer = setInterval(function(){

			// Start the next animation
			for (var i = 0; i < this.slideshows.length; i++){
				
				var o_ss = this.slideshows[i];
				var v_next_idx = o_ss.current_idx;
				v_next_idx++;
				if (v_next_idx == o_ss.images.length){v_next_idx = 0;}
				
				// Fade out
				o_ss.images[o_ss.current_idx].slide.fadeOut(400, function(){
				
					// When the image has faded out, start the next one back in
					this.ss.images[this.next_idx].slide.fadeIn(1600);
					
				}.bind({'ss': o_ss, 'next_idx': v_next_idx}));
				
				// Increment the slide counter
				o_ss.current_idx = v_next_idx;
				
			}
			
		}.bind(o_gallery), 4500);
		
		return this;
	} // this.startSlideshows ()
	
	/*
		Convert (ajaxify) a given contact form
	*/
	this.convertContactForm = function(o_form){

		if (o_form){
		
			var $this = $(o_form);
			$this.attr('autocomplete', 'off');
		
			// Capture the form submit event
			$this.submit(function(e){
				e.preventDefault();
			
				// Update UI
				var o_loading = $('<div/>').addClass('loading').attr('id', 'loading-notice').append(
						$('<div/>').addClass('image')
					).append(
						$('<div/>').addClass('message ').html('Sending your message..')
					);
				$(this).hide().after(o_loading.show());
		
				// Post form to server
				$.ajax({
					type		: "POST",
					url			: $(this).attr('action'),
					cache		: false,
					data		: $.param($(this).find(':input[name]')),
					dataType	: "json",
					success		: function(o_data){

						// Check for errors and alert user if failed
						if (o_data.error.length == 0){
							
							// Show the message
							$('#loading-notice').html(o_data.message);
							
							// Set timer to clear message and reset form
							setTimeout(function(){
								$('#loading-notice').remove();
								$this.fadeIn();
								$this.find(':input').each(function(v_index){
									$(this).removeClass('failed');
									_tfo.ui.removeTooltip(this);
								});
								$('#' + $this.attr('id') + '-error').hide();
								$(':input', $this)
									.not(':button, :submit, :reset, :hidden')
									.val('')
									.removeAttr('checked')
									.removeAttr('selected');
							}, 3000);
								
						} else {
					
							// Update UI to show errors						
							if (!$.isEmptyObject(o_data.failedfields)){
						
								// Remove previous validation errors and add new ones
								$this.find(':input').each(function(v_index){
									
									// Remove previous validation
									$(this).removeClass('failed');
									
									// Does this field have an error message?
									var v_fieldname = $(this).attr('id');
									for (var i in o_data.failedfields){
					
										if (i == v_fieldname){
										
											// Highlight the failed field
											var o_fld = $this.find('#' + v_fieldname);
											o_fld.addClass('failed').attr('title', o_data.failedfields[i]);
											_tfo.ui.makeTooltipFromTitle(o_fld.get(0));
											
											// Show general error
											$('#' + $this.attr('id') + '-error').html('Please complete the form accurately.<br />' +
												'Mistakes are highlighted.').show();
												
											// Show form and focus first failed field
											$this.show(); 
											$('#loading-notice').remove();
											if ($this.find('input.failed').length > 0){
												$this.find('input.failed').get(0).focus();
											}
												
										}
									}
									
								});
	
							} else {
							
								// General failure				
								$('#' + $this.attr('id') + '-error').html(o_data.error).show();
								$this.show(); 									
								$('#loading-notice').remove();
							
							}
						
						}
					},
					error		: function(o_ajax, v_status, o_error){
						_tfo.showError("An error occurred sending your request (" + 
							o_ajax.statusText + ").  Please refresh the page and try again.");
					}
				});
			
				return false;
			});
		
		}	
	} // this.convertContactForm()
	
} // cTTF()

// Scope bind function - allows binding of external objects as "this" in functions
if (!Function.prototype.bind){
	Function.prototype.bind = function(obj) {
		var method = this,
		temp = function() {
			return method.apply(obj, arguments);
		};
		return temp;
	}
}
