var args = {}; 
// Enable dev mode by uncommenting the following line
// args.dev = true;

var Carousel = (function ($, args) {

/* crCarousel Module
 *
 * Creation Republic 2011
 * Matthew Evans 
 *
 * Plugin Map
 * 
 * carousel.elements        --> a collection of HTML DOM elements
 *   object  elements.trunk  --> div#crCarousel-container
 *   object  elements.branch --> ul#crCarousel
 *   object  elements.leaves --> ul#crCarousel li   
 * carousel.properties      --> a collection of properties (dimensions, etc)
 *	 property  properties.imageHeight --> width of a gallery image
 *	 property  properties.imageWidth  --> height of a gallery image
 * carousel.methods         --> a collection of functions for the plugin
 *   function  methods.init     --> initialisation method, performs test, builds carousel
 *   function  methods.selftest --> tests for required JS libraries and DOM elements
 *   function  methods.fancybox --> initialises the fancybox plugin on carousel links
 *   function  methods.next     --> skips to next carousel element
 *   function  methods.previous --> skips to previous carousel element
 */

	// Create main carousel object
	var carousel = {};

	// Carousel properties
	carousel.properties = {};
	
	// Carousel methods
	carousel.methods = {};	
	
	// Begin caching HTML elements
	carousel.elements = {};	

	carousel.instantiated = false;
	
	// The init() function runs when Carousel() is called
	// It calls the selftest function, and if the selftest function succeeds,
	// it then initialises the Carousel
	carousel.methods.init = function () {	

		// Cache the container, list, and its nodes
		carousel.elements.trunk  = $('div#crCarousel-container');
		carousel.elements.branch = $('ul#crCarousel');
		carousel.elements.leaves = $('ul#crCarousel li');
		
		// Development mode test
		if (args && args.dev === true) {

			console.log(carousel);

		}
	
		// Run selftest
		if (carousel.methods.selftest() === true) {
			
			// Selftest passed, build carousel and run it
			if (args && args.dev === true) {	
				console.log('Building carousel...');
			}
			
			// Cache element dimensions
			carousel.properties.imageHeight = carousel.elements.leaves.first().height();
			carousel.properties.imageWidth  = carousel.elements.leaves.first().width();

			// Set container and list dimensions
			carousel.elements.trunk.height((carousel.properties.imageHeight + 10) * 3 );			
			carousel.elements.trunk.width((carousel.properties.imageWidth + 10) * 3);
			//carousel.elements.branch.width(carousel.properties.imageWidth * (carousel.elements.leaves.length + 15));

			// Initialise fancybox on the gallery items
			carousel.methods.fancybox();	

			// Build controls
			var controlPrevious = '<a class="control previous" href="#"> </a>',
				controlNext		= '<a class="control next" href="#"> </a>';
			carousel.elements.controls = $('<div> ' + controlPrevious + controlNext + '</div>');
			
			// Inject controls
			carousel.elements.trunk.parent().append(carousel.elements.controls);
			
			// We only want to bind these event handlers once
			if(carousel.instantiated === false){
			
				if (args && args.dev === true) {	
			
					console.log('>> STATUS: Binding event handlers...');
				}
			
				// Bind control event handlers
				$('a.next').live('click', carousel.methods.next);
				$('a.previous').live('click', carousel.methods.previous);
				
				carousel.instantiated = true;
			
			} else {
			
				if (args && args.dev === true) {
					console.log('>> STATUS: Carousel already instantiated, deferring event bindings.');
			
				}
			}
			
			// Add 'current' class to first image
			carousel.elements.leaves.eq(3).addClass('current');
			
	    } else { 

			if (args && args.dev === true) {

			// Selftest failed, log to console.
				console.log('>> ERROR: Selftest failed! crCarousel cannot initialise: ' + carousel.error);

			}
		}
		

	};

	// The selftest() function checks for integrity of cached elements and 
	// the existence of required files. It returns true or false, of course.
	carousel.methods.selftest = function () {
	
		// Make sure fancybox is available
		if (typeof $.fancybox !== 'function') { 
			
			// Fancybox failed, set error and return false.
			carousel.error = 'Fancybox is not available.';

			return false; 

		}

		// Make sure scrollTo is available
		if (typeof $.scrollTo !== 'function') {
		
			// ScrollTo failed, set error and return false.
			carousel.error = 'ScrollTo is not available.';

			return false;

		}

		// Make sure the container element exists
		if (carousel.elements.trunk.length < 1) {

			// crCarousel-container not found, set error and return false.
			carousel.error = 'div#crCarousel-container not found.';

			return false;
	
		}

		// Make sure the carousel element exists
		if (carousel.elements.branch.length < 1) { 

			// crCarousel element not found, set error and return false.
			carousel.error = 'ul#crCarousel element not found.';

			return false; 

		}
		
		// Pass the test as true
		return true;

	};

	// Since the Carousel() method could be called at any time in the page's
	// life cycle, we require a function to implement fancybox on dynamic elements.
	// This function fulfills that requirement for us.
	carousel.methods.fancybox = function () {
		
		// Check that there is no error
		if (!(carousel.error)) {

			// Initialise fancybox on gallery items, as a gallery, and as images.		
			carousel.elements.leaves.find('a').attr('rel', 'gallery').fancybox({'type' : 'image'});

		}

	};

	// Spin the carousel forward an item
	carousel.methods.next = function (e) {
 
		// No navigation
		e.preventDefault();
		
		// If the last slide is not current, proceed
		if(!(carousel.elements.leaves.slice(-6, -1).hasClass('current'))){  

		  carousel.elements.branch.find('.current').removeClass('current').nextAll().eq(5).addClass('current');
		  carousel.elements.branch.animate({ top : '-=' + (carousel.properties.imageHeight + 10) * 2});
		  
		}
 
	};

	// Spin the carousel back an item
	carousel.methods.previous = function (e) {
	
		// No navigation
		e.preventDefault();
	
		if(!(carousel.elements.leaves.slice(0, 5).hasClass('current'))){  

			carousel.elements.branch.find('.current').removeClass('current').prevAll().eq(5).addClass('current');  
			carousel.elements.branch.animate({ top : '+=' + (carousel.properties.imageHeight + 10) * 2});      
        }	
	
	};
	
	return carousel;
	
}($, args));

/* End crCarousel */
