function Slider (configFile, domNode) {
	
	// Configuration
	this.slideDuration = 4; // In Seconds.
	this.transitionSpeed = 0.75; // Seconds, for fade out, again for fade in.
	this.directFade = true; // true=fade direclty between slides, false=fade through a colour.
	
	// Initialization
	this.slides = new Array ();
	this.currentSlideIndex = 0;
	this.container = domNode;
	
	// Load slides.
	this.loadSlides (configFile);
	if (this.slides.length == 0) {
		// Error: no slides loaded.
		return;
	}
	
	var self = this;
	jQuery(document).ready (function () {
		self.initialize ();
	});
}

// --- Function Definitions ------------------------------------------------

Slider.prototype.setTimer = function () {
	this.stop ();
	this.start ();
};

Slider.prototype.stop = function () {
	if (this.timer != undefined) {
		clearInterval (this.timer);
		this.timer = undefined;
	}
};

Slider.prototype.start = function () {
	// Save this ref for closure.
	var self = this;
	this.timer = setInterval (function () {
		self.next ();
	}, this.slideDuration * 1000);
}

Slider.prototype.previous = function () {
	// Wrap if overflow
	if (this.currentSlideIndex > 0) {
		this.changeSlide ((this.currentSlideIndex - 1) % this.slides.length, true);
	} else {
		this.changeSlide (this.slides.length - 1, true);
	}
};

Slider.prototype.currentSlide = function () {
	return this.slides[this.currentSlideIndex];
};

Slider.prototype.next = function () {
	// Wrap if overflow
	this.changeSlide ((this.currentSlideIndex + 1) % this.slides.length, true);
};

//Transition to another slide
Slider.prototype.changeSlide = function (slideIndex, transition) {
	var toSlide = this.slides[slideIndex];
	
	var speed = 0;
	if (transition) {
		speed = this.transitionSpeed * 1000;
	}
	
	// For closure to access the current slide
	var fadeOutSlide = jQuery (this.container).find (".slider-slide-" + this.currentSlideIndex);
	var fadeInSlide = jQuery (this.container).find (".slider-slide-" + slideIndex);
	var oldButton = jQuery (this.container).find (".slider-link-" + this.currentSlideIndex);
	var newButton = jQuery (this.container).find (".slider-link-" + slideIndex);
	
	// Fade directly between slides or fade through black
	if (this.directFade) {
		// Raise the z-index of the next slide, then start.
		
		// Start the fadein transition
		fadeInSlide.css ("zIndex", 20).fadeIn (speed, function () {
			// Change active button
			oldButton.removeClass ("active");
			newButton.addClass ("active");
			// Hide the old slide.
			fadeOutSlide.hide ();
			
			// And lower the z-index back to normal.
			fadeInSlide.css ("zIndex", 10);
		});
	} else {
		// Do the transition.  Also transition the "active" button.
		jQuery (this.container).find (".slider-slide-" + this.currentSlideIndex).fadeOut (speed, function () {
			// Change active button
			oldButton.removeClass ("active");
			newButton.addClass ("active");
			// Start the fadein transition
			fadeInSlide.fadeIn (speed);
		});
	}
	// Reset the timer in case we're halfway through.
	this.setTimer ();
	
	this.currentSlideIndex = slideIndex;
};

//Load slides from URL
Slider.prototype.loadSlides = function (fromUrl) {
	
	var self = this;
	
	jQuery.ajax ({
		async: false,
		dataType: "text",
		url: fromUrl,
		success: function (data) {
			
			var slideSections = data.split (/^\[slide\]$/mi);
			for (var slideSection in slideSections) {
				
				if (slideSections[slideSection] == "") {
					continue;
				}
				
				var values = {};
				
				var slideInfo = slideSections[slideSection].split (/\r\n|\n\r|\n|\r/m);
				for (var slideSetting in slideInfo) {
					
					if (slideInfo[slideSetting] == "") {
						continue;
					}
					
					var items = slideInfo[slideSetting].split (/ *= */);
					
					var key = items.shift ();
					var value = items.shift ();
					switch (key) {
						case "link":
							values.link = value;
						break;
						
						case "image":
							values.image = value;
						break;
						
						case "headline":
							values.headline = value;
						break;
						
						case "summary":
							values.summary = value;
						break;
					}
				}

				var slide = new Slide ();
				slide.setValues (values);
				slide.preLoad ();
				
				self.slides.push (slide);
				
			}
			
		}
	});
};

// Set up the widget.
Slider.prototype.initialize = function () {
	// Add link+image, heading+subheading, buttons+prev/next to domNode.

	// Allow onclick events access to this.
	var self = this;
	
	var containerNode = jQuery (this.container);
	
	for (var slide in this.slides) {
		var slideHTML = this.slides[slide].toHTML ();
		slideHTML.className = "slider-slide inactive slider-slide-" + slide;
		jQuery (slideHTML).hide ();
		
		containerNode.append (slideHTML);
	}
	
	// Buttons
	var buttonContainer = document.createElement ("div");
	buttonContainer.className = "slider-button-container";
	
	var nextButton = document.createElement ("a");
	nextButton.className = "slider-next-button";
	nextButton.title = "Next feature";
	nextButton.href = "#";
	nextButton.innerHTML = "&nbsp;";
	jQuery (nextButton).click (function () {
		self.next ();
		return false;
	});
	
	buttonContainer.appendChild (nextButton);
	
	var prevButton = document.createElement ("a");
	prevButton.className = "slider-prev-button";
	prevButton.title = "Previous feature";
	prevButton.href = "#";
	prevButton.innerHTML = "&nbsp;";
	jQuery (prevButton).click (function () {
		self.previous ();
		return false;
	});
	
	buttonContainer.appendChild (prevButton);
	
	containerNode.append (buttonContainer);
	
	var slideButtonList = document.createElement ("ul");

	for (var i = this.slides.length - 1; i >= 0 ; i--) {
		var slideButton = document.createElement ("li");
		slideButton.className = "slider-link slider-link-" + i;
		var slideButtonLink = document.createElement("a");
		slideButtonLink.href = "#";
		slideButtonLink.title = "Change to feature " + (i + 1);
		slideButtonLink.innerHTML = "&nbsp;";
		// Crazy closure time!  Wrap the click closure in another self-executing
		// closure in order to capture the current value of i, not the final
		// value.
		jQuery (slideButtonLink).click (function (toSlide) {
			return function () {
				self.changeSlide (toSlide, true);
				return false;
			};
		}(i));
		
		slideButton.appendChild (slideButtonLink);
		slideButtonList.appendChild (slideButton);
	}

	buttonContainer.appendChild (slideButtonList);
	
	this.changeSlide (this.currentSlideIndex, false);
	
};

// --- End Function Definitions --------------------------------------------