<!DOCTYPE html>
<html>

  <head>
  <script data-require="underscore.js@1.5.1" data-semver="1.5.1" src="//cdn.jsdelivr.net/underscorejs/1.5.1/underscore-min.js"></script>
  <script data-require="angular.js@1.2.5" data-semver="1.2.5" src="http://code.angularjs.org/1.2.5/angular.js"></script>
  <script src="http://code.angularjs.org/1.2.5/angular-animate.min.js"></script>
  <script src="http://code.angularjs.org/1.2.5/angular-touch.min.js"></script>
  <script src="ArrayIterator.js"></script>
  <script src="app.js"></script>
  <link href='http://fonts.googleapis.com/css?family=Exo+2' rel='stylesheet' type='text/css'>
  <style type="text/css">
	html, body { font-family: 'Exo 2', sans-serif; padding: 0; margin: 0;}
	.slider_container { 
		position: relative; width: 800px; height: 600px; background: black; -webkit-border-radius: 10px;
		-moz-border-radius: 10px;
		border-radius: 10px; border: 20px solid #000; margin: 0 auto; 
		-webkit-box-shadow: 0px 0px 8px rgba(50, 50, 50, 0.75);
		-moz-box-shadow:    0px 0px 8px rgba(50, 50, 50, 0.75);
		box-shadow:         0px 0px 8px rgba(50, 50, 50, 0.75);
	}
	.slide {
		background: white;  width: 800px; height: 600px;  position: absolute; top: 0; left: 0; color: red; z-index: 999;
	}
	.slide.ng-enter, .slide.ng-move {
	  -webkit-transition:0.5s all;
	  -moz-transition:0.5s all;
	  -o-transition:0.5s all;
	  transition:0.5s all;
	  opacity:0;
	}
	.slide.ng-enter.ng-enter-active,
	.slide.ng-move.ng-move-active {
	  opacity:1;
	}
	h1 { 
		text-align: center; background: black;  padding: 20px; color: white;
	}
	h2, h3 {
		background: #FFF;
		color: #999;
		padding: 20px;
		text-align: center; text-transform: uppercase;
	}
</style>
  </head>

  <body>
    <h1>Slider Fade In/Out CSS3 Animation - AngularJS</h1>
    <div class="slider_container" ng-controller="mainCtrl" ng-app="app">
      <div ng-swipe-left="swipeLeft($event)" ng-swipe-right="swipeRight($event, $index, slide)" class="slide" ng-if="slide.visible" ng-repeat="slide in slides" style="background: url('http://www.iksurfmag.com/magcore/images/swipe_left_right.png') center center no-repeat; background-color: {{slide.background}}; ">
      	<h2>{{slide.title}}</h2>
      </div>
    </div>
  </body>
</html>
var app = angular.module("app", ['ngAnimate', 'ngTouch']);

app.controller("mainCtrl", function($scope, $animate, sliderManager) {

  $scope.slides = [
		{ title: "Slide 1", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: true  },
		{ title: "Slide 2", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false },
		{ title: "Slide 3", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false },
		{ title: "Slide 4", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false },
		{ title: "Slide 5", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false },
		{ title: "Slide 6", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false },
		{ title: "Slide 7", background: '#'+Math.floor(Math.random()*16777215).toString(16), visible: false }
	];

  $scope.swipeLeft = function(e, index, slide) {
    sliderManager.slideTo($scope.slides, "next");
  }

  $scope.swipeRight = function(e, index, slide) {
    sliderManager.slideTo($scope.slides, "previous");
  }

});

app.factory("sliderManager", function() {
    return  {
        /**
         * Slide to item based on the interator current position and user's direction
         * @param {Array} The array containing the slider items
         * @param {String} The direction you which to navagite to
         */ 
        slideTo: function(slides, direction) {
          var iterator = new ArrayIterator(slides, true);
          var visible_slide_index = null;
          var visible_slide = _.findWhere(slides, {visible: true});
          // which index is visible right now?
          _.each(slides, function(item, index) {
             if(item === visible_slide) 
                visible_slide_index = index;
          });  
          iterator.skipToItemByIndex(visible_slide_index);
          iterator[direction]();
          var next_slide = iterator.getCurrentItem();
          // reset all the slides, set it to visible = false
          _.map(slides, function(item, index) {
              item.visible = false;
          });
          // slide that need to be shown, set visible = true
          next_slide.visible = true;
        }
    }
});

(function() {
 
	 /**
	 * Provide an interface for navigating through array items. 
	 * @constructor
	 * @class
	 * @classdesc
	 * @param {Array} items Any datatype is acceptable in Array form.
	 * @param {Boolean} infinite If set to true: we can navigate from last to first index like an infinite loop. If it set to false infinite loop is impossible.
	 */ 
	ArrayIterator = function(items, infinite) {
		this.infinite = (infinite == undefined || infinite == "undefined" || infinite == null) ? false : infinite;
		this.items = items;
		this.current_index = -1;
		// start off at index of 0
		this.next();
	};
 
	/**
	 * Reset current_index. Set the value to -1
	 */ 
	ArrayIterator.prototype.reset = function() {
		this.current_index = -1;
	}
 
	/**
	 * Go to the next item based on the current item index. If infinite is set to true, inifite loop is posisible.
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.next = function() {
		
		if(this.infinite)
		{
			if(this.getCurrentIndex() >= this.getLastIndex())
			{
				return this.first();
			}
			else
			{
				this.current_index += 1;
				return this.items[this.current_index];
			}
		}
		else
		{	
			var old_index = this.current_index;
 
			if(!this.hasNext())
			{
				this.current_index = old_index;
				throw new Error("Not allowed to moved to the next item when infinite is set to false. The current index is at the end of the array");
			}
			else
			{
				
				this.current_index += 1;
				return this.items[this.current_index];
			}
		}
	}
 
	/**
	 * Go to the previous item based on the current item index. If infinite is set to true, inifite loop is posisible.
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.previous = function() {
		if(this.infinite)
		{
			if(this.getCurrentIndex() <= 0)
			{
				return this.last();
			}
			else
			{
				this.current_index -= 1;
				return this.items[this.current_index];
			}
		}
		else
		{	
			var old_index = this.current_index;
 
			if(!this.hasPrevious())
			{
				this.current_index = old_index;
				throw new Error("Not allowed to moved to the previous item when infinite is set to false. The current index is at the beginning of the array");
			}
			else
			{
				
				this.current_index -= 1;
				return this.items[this.current_index];
			}
		}
	}
 
	/**
	 * Ask whether it is possible to go to the next item based on the current index
	 * @returns {Boolean}
	 */ 
	ArrayIterator.prototype.hasNext = function() {
		if(this.infinite)
			return true;
		return this.current_index < this.items.length - 1;
	}
 
	/**
	 * Ask whether it is possible to go to the previous item based on the current index
	 * @returns {Boolean} 
	 */ 
	ArrayIterator.prototype.hasPrevious = function() {
		if(this.infinite)
			return true;
		return this.current_index > 0;
	}
 
	/**
	 * Set the current index at the first item and return the first item
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.first = function() {
		this.current_index = this.getFirstIndex();
		return this.items[this.current_index];
	}
 
	/**
	 * Set the current index at the last item and return the last item
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.last = function() {
		this.current_index = this.getLastIndex();
		return this.items[this.current_index];
	}
 
	/**
	 * Get item by the index number
	 * @params {Number} index
	 * @returns {*} the item where the current_index is pointing to 
	 */ 
	ArrayIterator.prototype.getItemByIndex = function(index) {
		if(this.items[index] == undefined)
			return this.last();
			//throw new Error("Item does not exist in array");
		return this.items[index];
	}
	
	/**
	 * Skip the pointer to the given index
	 * @params {Number} index
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.skipToItemByIndex = function(index) {
		this.current_index = index;
		return this.items[index];
	}
 
	/**
	 * @returns {Array} All the items 
	 */ 
	ArrayIterator.prototype.getItems = function() {
		return this.items;
	}
 
	/**
	 * @returns {Number} Get the current index 
	 */ 
	ArrayIterator.prototype.getCurrentIndex = function() {
		return this.current_index;
	}
 
	/**
	 * @returns {*} the item where the current_index is pointing to
	 */ 
	ArrayIterator.prototype.getCurrentItem = function() {
		return this.items[this.current_index];
	}
 
	/**
	 * @returns {Number} Get the index number of the last item.  
	 */ 
	ArrayIterator.prototype.getLastIndex = function() {
		return this.items.length - 1;
	}
 
	/**
	 * @returns {Number} Get the index number of the first item.  
	 */ 
	ArrayIterator.prototype.getFirstIndex = function() {
		return 0;
	}
 
})();