(function ($, undefined) {
  var slice = Array.prototype.slice;
  var _cleanData = $.cleanData;
  $.cleanData = function (elems) {
    for (var i = 0, elem;
    (elem = elems[i]) != null; i++) {
      $(elem).triggerHandler("remove");
    }
    _cleanData(elems);
  };
  $.widget = function (name, base, prototype) {
    var namespace = name.split(".")[0],
        fullName;
    name = name.split(".")[1];
    fullName = namespace + "-" + name;
    if (!prototype) {
      prototype = base;
      base = $.Widget;
    }
    // create selector for plugin
    $.expr[":"][fullName] = function (elem) {
      return !!$.data(elem, name);
    };
    $[namespace] = $[namespace] || {};
    // create the constructor using $.extend() so we can carry over any
    // static properties stored on the existing constructor (if there is one)
    $[namespace][name] = $.extend(function (options, element) {
      // allow instantiation without "new" keyword
      if (!this._createWidget) {
        return new $[namespace][name](options, element);
      }
      // allow instantiation without initializing for simple inheritance
      // must use "new" keyword (the code above always passes args)
      if (arguments.length) {
        this._createWidget(options, element);
      }
    }, $[namespace][name]);
    var basePrototype = new base();
    // we need to make the options hash a property directly on the new instance
    // otherwise we'll modify the options hash on the prototype that we're
    // inheriting from
    basePrototype.options = $.widget.extend({}, basePrototype.options);
    $.each(prototype, function (prop, value) {
      if ($.isFunction(value)) {
        prototype[prop] = (function () {
          var _super = function (method) {
            return base.prototype[method].apply(this, slice.call(arguments, 1));
          };
          var _superApply = function (method, args) {
            return base.prototype[method].apply(this, args);
          };
          return function () {
            var __super = this._super,
                __superApply = this._superApply,
                returnValue;
            this._super = _super;
            this._superApply = _superApply;
            returnValue = value.apply(this, arguments);
            this._super = __super;
            this._superApply = __superApply;
            return returnValue;
          };
        }());
      }
    });
    $[namespace][name].prototype = $.widget.extend(basePrototype, {
      namespace: namespace,
      widgetName: name,
      widgetEventPrefix: name,
      widgetBaseClass: fullName
    }, prototype);
    $.widget.bridge(name, $[namespace][name]);
  };
  $.widget.extend = function (target) {
    var input = slice.call(arguments, 1),
        inputIndex = 0,
        inputLength = input.length,
        key, value;
    for (; inputIndex < inputLength; inputIndex++) {
      for (key in input[inputIndex]) {
        value = input[inputIndex][key];
        if (input[inputIndex].hasOwnProperty(key) && value !== undefined) {
          target[key] = $.isPlainObject(value) ? $.widget.extend({}, target[key], value) : value;
        }
      }
    }
    return target;
  };
  $.widget.bridge = function (name, object) {
    $.fn[name] = function (options) {
      var isMethodCall = typeof options === "string",
          args = slice.call(arguments, 1),
          returnValue = this;
      // allow multiple hashes to be passed on init
      options = !isMethodCall && args.length ? $.widget.extend.apply(null, [options].concat(args)) : options;
      if (isMethodCall) {
        this.each(function () {
          var instance = $.data(this, name);
          if (!instance) {
            return $.error("cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'");
          }
          if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
            return $.error("no such method '" + options + "' for " + name + " widget instance");
          }
          var methodValue = instance[options].apply(instance, args);
          if (methodValue !== instance && methodValue !== undefined) {
            returnValue = methodValue.jquery ? returnValue.pushStack(methodValue.get()) : methodValue;
            return false;
          }
        });
      } else {
        this.each(function () {
          var instance = $.data(this, name);
          if (instance) {
            instance.option(options || {})._init();
          } else {
            object(options, this);
          }
        });
      }
      return returnValue;
    };
  };
  $.Widget = function (options, element) {
    // allow instantiation without "new" keyword
    if (!this._createWidget) {
      return new $[namespace][name](options, element);
    }
    // allow instantiation without initializing for simple inheritance
    // must use "new" keyword (the code above always passes args)
    if (arguments.length) {
      this._createWidget(options, element);
    }
  };
  $.Widget.prototype = {
    widgetName: "widget",
    widgetEventPrefix: "",
    defaultElement: "
",
    options: {
      disabled: false,
      // callbacks
      create: null
    },
    _createWidget: function (options, element) {
      element = $(element || this.defaultElement || this)[0];
      this.element = $(element);
      this.options = $.widget.extend({}, this.options, this._getCreateOptions(), options);
      this.bindings = $();
      this.hoverable = $();
      this.focusable = $();
      if (element !== this) {
        $.data(element, this.widgetName, this);
        this._bind({
          remove: "destroy"
        });
      }
      this._create();
      this._trigger("create");
      this._init();
    },
    _getCreateOptions: $.noop,
    _create: $.noop,
    _init: $.noop,
    destroy: function () {
      this._destroy();
      // we can probably remove the unbind calls in version 2
      // all event bindings should go through this._bind()
      this.element.unbind("." + this.widgetName).removeData(this.widgetName);
      this.widget().unbind("." + this.widgetName).removeAttr("aria-disabled").removeClass(
      this.widgetBaseClass + "-disabled " + "ui-state-disabled");
      // clean up events and states
      this.bindings.unbind("." + this.widgetName);
      this.hoverable.removeClass("ui-state-hover");
      this.focusable.removeClass("ui-state-focus");
    },
    _destroy: $.noop,
    widget: function () {
      return this.element;
    },
    option: function (key, value) {
      var options = key,
          parts, curOption, i;
      if (arguments.length === 0) {
        // don't return a reference to the internal hash
        return $.widget.extend({}, this.options);
      }
      if (typeof key === "string") {
        if (value === undefined) {
          return this.options[key];
        }
        // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
        options = {};
        parts = key.split(".");
        key = parts.shift();
        if (parts.length) {
          curOption = options[key] = $.widget.extend({}, this.options[key]);
          for (i = 0; i < parts.length - 1; i++) {
            curOption[parts[i]] = curOption[parts[i]] || {};
            curOption = curOption[parts[i]];
          }
          curOption[parts.pop()] = value;
        } else {
          options[key] = value;
        }
      }
      this._setOptions(options);
      return this;
    },
    _setOptions: function (options) {
      var self = this;
      $.each(options, function (key, value) {
        self._setOption(key, value);
      });
      return this;
    },
    _setOption: function (key, value) {
      this.options[key] = value;
      if (key === "disabled") {
        this.widget().toggleClass(this.widgetBaseClass + "-disabled ui-state-disabled", !! value).attr("aria-disabled", value);
        this.hoverable.removeClass("ui-state-hover");
        this.focusable.removeClass("ui-state-focus");
      }
      return this;
    },
    enable: function () {
      return this._setOption("disabled", false);
    },
    disable: function () {
      return this._setOption("disabled", true);
    },
    _bind: function (element, handlers) {
      // no element argument, shuffle and use this.element
      if (!handlers) {
        handlers = element;
        element = this.element;
      } else {
        // accept selectors, DOM elements
        element = $(element);
        this.bindings = this.bindings.add(element);
      }
      var instance = this;
      $.each(handlers, function (event, handler) {
        element.bind(event + "." + instance.widgetName, function () {
          // allow widgets to customize the disabled handling
          // - disabled as an array instead of boolean
          // - disabled class as method for disabling individual parts
          if (instance.options.disabled === true || $(this).hasClass("ui-state-disabled")) {
            return;
          }
          return (typeof handler === "string" ? instance[handler] : handler).apply(instance, arguments);
        });
      });
    },
    _hoverable: function (element) {
      this.hoverable = this.hoverable.add(element);
      this._bind(element, {
        mouseenter: function (event) {
          $(event.currentTarget).addClass("ui-state-hover");
        },
        mouseleave: function (event) {
          $(event.currentTarget).removeClass("ui-state-hover");
        }
      });
    },
    _focusable: function (element) {
      this.focusable = this.focusable.add(element);
      this._bind(element, {
        focusin: function (event) {
          $(event.currentTarget).addClass("ui-state-focus");
        },
        focusout: function (event) {
          $(event.currentTarget).removeClass("ui-state-focus");
        }
      });
    },
    _trigger: function (type, event, data) {
      var callback = this.options[type],
          args;
      event = $.Event(event);
      event.type = (type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type).toLowerCase();
      data = data || {};
      // copy original event properties over to the new event
      // this would happen if we could call $.event.fix instead of $.Event
      // but we don't have a way to force an event to be fixed multiple times
      if (event.originalEvent) {
        for (var i = $.event.props.length, prop; i;) {
          prop = $.event.props[--i];
          event[prop] = event.originalEvent[prop];
        }
      }
      this.element.trigger(event, data);
      args = $.isArray(data) ? [event].concat(data) : [event, data];
      return !($.isFunction(callback) && callback.apply(this.element[0], args) === false || event.isDefaultPrevented());
    }
  };
  $.each({
    show: "fadeIn",
    hide: "fadeOut"
  }, function (method, defaultEffect) {
    $.Widget.prototype["_" + method] = function (element, options, callback) {
      options = options || {};
      var hasOptions = !$.isEmptyObject(options),
          effectName = options.effect || defaultEffect;
      options.complete = callback;
      if (options.delay) {
        element.delay(options.delay);
      }
      if (hasOptions && $.effects && ($.effects.effect[effectName] || $.uiBackCompat !== false && $.effects[effectName])) {
        element[method](options);
      } else if (effectName !== method && element[effectName]) {
        element[effectName](options.duration, options.easing, callback);
      } else {
        element.queue(function () {
          $(this)[method]();
          if (callback) {
            callback.call(element[0]);
          }
        });
      }
    };
  });
  // DEPRECATED
  if ($.uiBackCompat !== false) {
    $.Widget.prototype._getCreateOptions = function () {
      return $.metadata && $.metadata.get(this.element[0])[this.widgetName];
    };
  }
})(jQuery);
/*
	SlidesJS, let the good times roll
*/
(function($) {
  $.widget("js.slides", {
		options: {
			width: 980, // [Number] Define the slide width
			responsive: false, // [Boolean] slideshow will scale to its container
			height: 250, // [Number] Define the slide height
			navigation: true, // [Boolean] Auto generate the naviagation, next/previous buttons
			pagination: true, // [Boolean] Auto generate the pagination
			effects: {
				navigation: "slide",  // [String] Can be either "slide" or "fade"
				pagination: "slide" // [String] Can be either "slide" or "fade"
			},
			direction: "left", // [String] Define the slide direction: "Up", "Right", "Down", "left"
			fade: {
				interval: 1000, // [Number] Interval of fade in milliseconds
				crossfade: false, // [Boolean] TODO: add this feature. Crossfade the slides, great for images, bad for text
				easing: "" // [String] Dependency: jQuery Easing plug-in 
			},
			slide: {
				interval: 1000, // [Number] Interval of fade in milliseconds
				browserWindow: false, // [Boolean] Slide in/out from browser window, bad ass
				easing: "" // [String] Dependency: jQuery Easing plug-in 
			},
			preload: {
				active: false, // [Boolean] Preload the slides before showing them, this needs some work
				image: "../img/loading.gif" // [String] Define the path to a load .gif, yes I should do something cooler
			},
			startAtSlide: 1, // [Number] What should the first slide be?
			playInterval: 5000, // [Number] Time spent on each slide in milliseconds
			pauseInterval: 8000, // [Number] Time spent on pause, triggered on any navigation or pagination click
			autoHeight: false, // [Boolean] TODO: add this feature. Auto sets height based on each slide
			navigateStart: function( current ){
				// console.log( "navigateStart: ", current );
			},
			navigateEnd: function( current ){
				// console.log( "navigateEnd: ", current );
			},
			loaded: function() {
				// console.log( "loaded" );
			}
		},
    _create: function() {	
			
			// Error correction for only 1 slide
			if (this.element.children().length < 2) {
				return;
			}
			
			if ( this.options.slide.browserWindow ) {
				this.element.css({
					width: window.innerWidth,
					position: "relative",
					left: - (window.innerWidth / 2) + (this.options.width / 2),
					overflow: "hidden"
				});
				
				$(window).resize( $.proxy(function() {
					this.element.css({
						width: window.innerWidth,
						left: - (window.innerWidth / 2) + (this.options.width / 2)
					});
					this.slidesContainer.css({
						left: this.options.slide.browserWindow ?  (window.innerWidth - this.options.width) / 2 : ""
					});
				},this));
			}
		
			this.slidesContainer = this.element.children().not(".slidesNavigation").wrapAll( "
" ).parent().css({
				width: this.options.responsive ? "100%" : this.options.width,
				height: this.options.height,
				overflow: this.options.slide.browserWindow ? "visible" : "hidden",
				position: "relative",
				left: this.options.slide.browserWindow ?  (window.innerWidth - this.options.width) / 2 : ""
			});
			
			this.slidesControl = this.slidesContainer.wrapInner( "
" ).children().css({
				display: "none"
			});
			
			// Define the slides
			this.slides = this.slidesControl.children();
			
			// Set CSS for slidesControl
			this.slidesControl.css({
				position: "relative",
				width: this.options.responsive ? "100%" : this.options.width,
				height: this.options.height,
				left: 0
			});
			// Set CSS for each slide
			this.slides.css({
				position: "absolute",
				top: 0, 
				left: 0,
				zIndex: 0,
				display: "none"
			});
			// Show the starting slide with a fade in
			this.slides.eq( this.options.startAtSlide - 1 ).fadeIn( this.options.fade.interval );
						
			if ( this.options.preload.active ) {
				
/*				TODO: loading image, need to remove on load callback
				
					this.slidesContainer.css({
						backgroundImage: "url(" + this.options.preload.image + ")",
						backgroundPosition: "50% 50%",
						backgroundRepeat: "no-repeat"
					});
*/					
				var preloadImage;
			
				if (this.slides.eq( this.options.startAtSlide - 1 ).is("img")) {
					preloadImage = this.slides.eq( this.options.startAtSlide - 1 ).attr("src");
				} else {
					preloadImage = this.slides.eq( this.options.startAtSlide - 1 ).find("img").attr("src");
				}
			
				this._loadImage( preloadImage ).then( $.proxy(function( url ) {
			  	this.slidesControl.fadeIn( this.options.fade.interval );
					this._trigger( "loaded", this.options.startAtSlide, this );
				},this));
			} else {
				 this.slidesControl.fadeIn( this.options.fade.interval );
			}
			if ( this.options.navigation ) {
				this.prevButton = $("
",{
					"class": "slidesPrevious slidesNavigation",
					href: "#",
					title: "Previous",
					text: "Previous"
				}).appendTo( this.element );
				
				this.nextButton = $("",{
					"class": "slidesNext slidesNavigation",
					href: "#",
					title: "Next",
					text: "Next"
				}).appendTo( this.element );
			} else {
				this.nextButton = $(".slidesNext");
				this.prevButton = $(".slidesPrevious");
			}		
			
			if (this.options.pagination) {
				this._buildPagination();
				// add current class to first pagination
				this.pagination.children().eq( this.options.startAtSlide - 1 ).addClass("slidesCurrent");
			}
			
			this.current = this.options.startAtSlide - 1;
			
			this.element.delegate( ".slidesNavigation", "click", $.proxy(this, "_navigate") );
			
			this.total = this.slides.length;
    },
		_loaded: function() {
			if ( this.options.responsive ) {
				
				// TODO: cleanup and condense
				this.slidesContainer.css({
					height: this.slides.height()
				});
				this.slidesControl.css({
					height: this.slides.height()
				});
				$(window).resize( $.proxy(function() {
					this.slidesContainer.css({
						height: this.slides.height()
					});
					this.slidesControl.css({
						height: this.slides.height()
					});
				},this));
			}
		},
    _buildPagination: function() {
			
			if (this.pagination) {
				// Remove the current paginaiton
				this.pagination.remove();
				// Redefine slides with new children
				this.slides = this.slidesControl.children();
			}
			
			this.pagination = $("",{
				"class": "slidesPagination"
			}).appendTo(this.element);
			
			this.slides.each(
				$.proxy(function(index, element) {
					$("").appendTo(this.pagination);
				},this)
			);
			
    },
		_loadImage: function(imageSrc) {
			var deferred, preloader;
			var loadImageCache = {};
		  if (typeof loadImageCache[imageSrc] === "undefined") {
		    deferred = $.Deferred();
		    preloader = new Image();
		    preloader.onload  = function() {
					deferred.resolve(this.src);
				};
		    preloader.onerror = function() {
					deferred.reject(this.src);
				};
		    preloader.src = imageSrc;
		    loadImageCache[imageSrc] = deferred;
		  }
		  return loadImageCache[imageSrc];
		},
		next: function( effect ) {
			this._navigate("next", effect);
		},
		previous: function( effect ) {
			this._navigate("previous", effect);
		},
		slide: function( slide, effect ) {			
			this.element.data("goto", (slide - 1));
			this._navigate("pagination", effect);
		},
		_navigate: function( event, effect ) {
			var to, position, direction, next, prev, pagination, $target = $(event.target), currentSlide = this.slides.eq( this.current );
			
			/*
				Slide to error correction
			*/
			if ( this.element.data("goto") < 0 ) {
				// If goto is less then 0
				this.element.data("goto",0);
			} else  if ( this.element.data("goto") > this.total ) {
				// If goto is greater then total slides
				this.element.data("goto",(this.total - 1));
			}
			
			/*
				Check if slides is currently animating
			*/
			if ( this.element.data("animated") || $target.data("slidesindex") === this.current || this.element.data("goto") === this.current ) {
				return false;
			}
			
			/*
				Is this event coming from a click?
			*/
			if (typeof(event) === "object") {
				event.preventDefault();
				// Pause on navigation item click
				if ( this.state === "playing" && this.options.pauseInterval ) {
					this.pause();
				}
			} else {
				if (event === "next") {
					next = true;
				} else {
					prev = true;
				}
			}
		
			/*
				Set to animated
			*/
			this.element.data("animated",true);
			
			if ( $target.hasClass( "slidesNext" ) ) {
				// Next button clicked
				next = true;
				
			} else if ( $target.hasClass("slidesPrevious") ) {
				
				// Previous button clicked
				prev = true;		
				
			}	else if ( $target.hasClass("slidesPaginationItem") ||  event === "pagination") {
				// Paginaiton item clicked
				if ( this.current > $target.data("slidesindex") || this.current > this.element.data("goto") ) {
					prev = true;					
				} else {
					next = true;
				}
				
				pagination = true;
				
				effect = effect ? effect : this.options.effects.pagination;
			}
			
			if (pagination) {
				// Get next from data-slidesindex
				to = this.element.data("goto") > -1 ? this.element.data("goto") : $target.data("slidesindex");
			} else {
				// Get next based on curent
				to = next ? (this.current + 1) : (prev ? this.current - 1 : this.current);
			}
			// Pass slide from number
			this._trigger("navigateStart", ( this.current + 1 ), this);
			
			// creat the loop
			if ( to == this.slides.length && !pagination ) {
				// last slide, loop to first
				to = 0;
			} else if ( to == -1 && !pagination ) {
				// first slide, loop to last
				to = this.slides.length - 1;
			}
			
			if (this.options.pagination) {
				// Change the pagination
				this.pagination.children().removeClass("slidesCurrent");
				this.pagination.children().eq( to ).addClass("slidesCurrent");
			}
			
			// Effects methods
			if (effect === "fade") {
				this._fade({
					next: next,
					to: to,
					currentSlide: currentSlide
				});
			} else {
				this._slide({
					next: next,
					to: to,
					currentSlide: currentSlide
				});
			}
		},
		_slide: function (navigateData) {
			/*
				Thanks to Thomas Reynolds 
			*/
			
			var isFlipped = navigateData.next ? 1 : -1;
			var isOpposite = this.options.direction.match(/right|down/) ? -1 : 1;
			var type = this.options.direction.match(/left|right/) ? "horizontal" : "vertical";
			var vector = (type == "horizontal") ? "width" : "height";
			
			vector = this.options.responsive ? this.slides.width() : this.options[vector] ;
			
			var	position = vector * isOpposite * isFlipped;
			
			if (this.options.slide.browserWindow) {
				 if (navigateData.next) {
					position = Math.abs( this.options.width - window.innerWidth - position);
				} else {
					position = this.options.width - window.innerWidth + position;
				}					
			}
			
			var direction = position * -1;
			
			// Setup the "to" slide
			this.slides.eq( navigateData.to ).css({
				left: type === "vertical" ? 0 : position,
				top:  type === "vertical" ? position : 0,
				zIndex: 5,
				display: "block"
			});
			
			// animate control
			this.slidesControl.animate({
				left: type === "vertical" ? 0 : direction,
				top:  type === "vertical" ? direction : 0
			},this.options.slide.interval, this.options.slide.easing, $.proxy(function(){
				// after animation reset control position
				this.slidesControl.css({
					top: 0,
					left:0
				});
				// reset and show next
				this.slides.eq( navigateData.to ).css({
					top: 0,
					left:0,
					zIndex: 5
				});
				
				// reset previous slide
				navigateData.currentSlide.css({
					top: 0,
					left:0,
					display: "none",
					zIndex: 0
				});
				
				this.current = navigateData.to;
				
				this._trigger("navigateEnd", ( this.current + 1 ), this);
			}, this));
		},
		_fade: function (navigateData) {
				// put hidden to slide above current
				this.slides.eq( navigateData.to ).css({
					zIndex: 10
				// fade in next
				}).fadeIn(this.options.fade.interval, this.options.fade.easing, $.proxy(function(){
				
						// hide previous
						navigateData.currentSlide.css({
							display: "none",
							zIndex: 0
						});								
							
						// reset zindex
						this.slides.eq( navigateData.to ).css({
							zIndex: 0
						});					
										
						this.current = navigateData.to;
						this._trigger("navigateEnd", ( this.current + 1 ), this);
					
				}, this));
		},
		play: function( gotoNext ) {
			if (gotoNext !== false) {
				this._navigate("next");
			}
			
			var playInterval = setInterval( $.proxy(function() {
				this._navigate("next");
			}, this), this.options.playInterval);
			
			// Set status
			this.state = "playing";
			
			// Store the unique interval ID
			this.element.data("playIntervalId",playInterval);
		},
		pause: function() {
			clearTimeout( this.element.data("pauseTimeoutId") );
			
			clearInterval( this.element.data("playIntervalId") );
			var pauseTimeout = setTimeout($.proxy(function() {
				this.play();
			 }, this), this.options.pauseInterval);
			
			// Set status
			this.state = "paused";
			
			// Store the unique pause timeout ID
			this.element.data("pauseTimeoutId",pauseTimeout);
		},
		stop: function() {
			clearInterval( this.element.data("playIntervalId") );
			
			// Set status
			this.state = "stopped";
		},
		update: function() {
			this._buildPagination();	
		},
		status: function( key ) {
			if (key) {
				return this[key] ? this[key] : false;
			} else {
				return {
					"state": this.state,
					"current": this.current,
					"total": this.total
				};
			}
			
		},
		_setOption: function(key, value) {
      switch(key) {
				/*
					TODO: This needs work, note status function use of this[key]
					$("#slides").slides("option","pagination", false);
				
        case "pagination":
					if (value !== this.options.pagination ) {
						value ? this._buildPagination() : this.pagination.remove();
					}
          break;
				*/
      }
      $.Widget.prototype._setOption.apply(this,arguments);
    },
    destroy: function() {
			
			this.slidesContainer.contents().unwrap();
			
			this.slidesControl.contents().unwrap();
			
			this.element.unbind();
			
			this.pagination.remove();
			
			this.nextButton.remove();
			
			this.prevButton.remove();
			
			this.slides.attr( "style", "" );
			
      $.Widget.prototype.destroy.call(this);
    },
		_trigger: function( event, current ) {
			if (event != "create") {
				this.options[event]( current );
			}
			if (event === "navigateEnd") {
				this.element.data("animated",false);
			}
			if (event === "loaded") {
				this._loaded();
			}
		}
  });
})(jQuery);