/*  Transpose - jQuery-powered plugin that transitions list items automatically, manually on user-demand, or both.
 *  (c) Jeremy Wynn
 *  @merelyjeremy
 *  MIT License
 *
 *  v0.91 - Slight Code Optimization.  Completely made motion type modular.
 *  v0.98 - Major refactoring to JS OOP methodology
 */

var Transpose = function (element, options) {
	"use strict";
	this.element = element;
	this.settings = jQuery.extend({}, this.defaults, options);
	this.launch();
};

// Adding properties and methods to the Transpose class
Transpose.prototype = {
	defaults: {
		automatic: true,
		autoRestart: true,
		motion: 'fade',
		motionTimer: 'fast',
		nextId: 'target-right',
		paginator: false,
		paginatorCurrent: 'current',
		paginatorId: 'paginator',
		paginatorLabel: false,
		prevId: 'target-left',
		prevNext: false,
		timer: 10000
	},
	launch: function () {
		this.chosenMotion = this.motion.determine(this.settings.motion);
		this.targetCount = this.element.children('li').size();
		if (this.chosenMotion === this.motion.fade) {
			this.element.children('li').not(':first').hide().css('opacity', '0');
		}
		else {
			this.element.children('li').not(':first').hide();
		}
		this.element.children('li').first().show().addClass('active');

        this.currentIndex = this.index.initializeIndex();

		if (this.settings.prevNext) {
			this.prevNext.call(this);
		}
		if (this.settings.paginator) {
			this.paginator.buildPaginator(this);
		}
		if (this.settings.automatic) {
			this.startTimer.call(this);
		}
	},
	index: {
        initializeIndex: function () {
            return 0;
        },
		modifyIndex: function (selectedBanner, alteredIndex, direction) {
		
			if (alteredIndex !== undefined) {

				if (jQuery(this.element.selector + " :animated").length > 0) {
					return false;
				}
				else {

					if (alteredIndex === -1) { // Prevents the backward indexing into oblivion
						alteredIndex = this.targetCount - 1;
						selectedBanner = jQuery(this.element.selector + " li").eq(alteredIndex);
					}

                    // Determination of motion based on pagination
                    if (!direction) {
                        if (this.currentIndex < alteredIndex) {
                            direction = 'forward';
                        }
                        else {
                            direction = 'backward';
                        }
                    }

					// Prevent index from being greater than or equal than the number of targets
					if (this.currentIndex > this.targetCount - 1) {
						this.currentIndex = 0;
					}

					else {
						this.currentIndex = alteredIndex;
					}

					// Set the index back to beginning when incrementing it past the last node
					if (this.currentIndex === this.targetCount) {
						this.currentIndex = 0;
						alteredIndex = 0;
						selectedBanner = jQuery(this.element.selector + " li").eq(0);
					}

                    this.chosenMotion.apply(this, [selectedBanner, alteredIndex, direction]);
				}
			} else {
				this.currentIndex += 1;
				if (this.currentIndex === this.targetCount) {
					this.currentIndex = 0;
				}
			}
		}
	},
	motion: {
		chosen: '',
		determine: function (motion) {
			switch (motion) {
			case "fade":
				return this.fade;
			case "slideHorizontal":
				return this.slideHorizontal;
			case "slideVertical":
				return this.slideVertical;
			default:
				return this.fade;
			}
		},
		fade: function (selectedBanner, alteredIndex) {
			var activeTarget = this.element.children('li.active'),
				that = this;
			activeTarget.fadeTo(this.settings.motionTimer, 0, function () {
				activeTarget.hide();  //Necessary or earlier anchor hrefs won't update
				that.updateStatus.target(this);

				if (selectedBanner === undefined) {
				    that.index.modifyIndex.call(that);  //Flagged
					that.element.children('li').eq(that.currentIndex).show().fadeTo(that.settings.motionTimer, 1, function () {
						that.updateStatus.target(this);
					});
				}
				else {
					jQuery(selectedBanner).show().fadeTo(that.settings.motionTimer, 1, function () {
						that.updateStatus.target(this);
						if (that.settings.autoRestart) {
							that.startTimer(that.settings.timer);
						}
					});
				}
				that.updateStatus.paginator.apply(that, [alteredIndex]);
			});
		},
		slideHorizontal: function (selectedBanner, alteredIndex, direction) {
            var activeTarget = this.element.children('li.active'),
				nextTarget,
				that = this,
				tWidth = this.element.width();

            if (selectedBanner === undefined) {
				that.index.modifyIndex.call(that);  //Flagged
				nextTarget = that.element.children('li').eq(that.currentIndex);
				nextTarget.css('left', tWidth).show();
				activeTarget.animate({
					left: '-=' + tWidth
				}, that.settings.motionTimer, function () {
					activeTarget.hide();
				});
				nextTarget.animate({
					left: '0'
				}, that.settings.motionTimer);
				that.updateStatus.target(activeTarget);
				that.updateStatus.target(nextTarget);
				that.updateStatus.paginator.apply(that, [alteredIndex]);
            }

            else {
                nextTarget = jQuery(selectedBanner);
                if (direction === 'forward') {
					// Transition Forward
                    nextTarget.css('left', tWidth).show();
                    activeTarget.animate({
                        left: '-=' + tWidth
                    }, that.settings.motionTimer, function () {
                        activeTarget.hide();
                    });
                    nextTarget.animate({
                        left: '0'
                    }, that.settings.motionTimer, function () {
                        that.updateStatus.target(activeTarget);
                        that.updateStatus.target(nextTarget);
                        that.updateStatus.paginator.apply(that, [alteredIndex]);
                        if (that.settings.autoRestart) {
                            that.startTimer(that.settings.timer);
                        }
                    });
                }
                else {
					// Transition Backward
                    nextTarget.css('left', -tWidth).show();
                    activeTarget.animate({
                        left: '+=' + tWidth
                    }, that.settings.motionTimer, function () {
                        activeTarget.hide();
                    });
                    nextTarget.animate({
                        left: '0'
                    }, that.settings.motionTimer, function () {
                        that.updateStatus.target(activeTarget);
                        that.updateStatus.target(nextTarget);
                        that.updateStatus.paginator.apply(that, [alteredIndex]);
                        if (that.settings.autoRestart) {
                            that.startTimer(that.settings.timer);
                        }
                    });
                }
            }
		},
		slideVertical: function (selectedBanner, alteredIndex, direction) {
		    var activeTarget = this.element.children('li.active'),
				nextTarget,
				tHeight = this.element.height(),
				that = this;
            if (selectedBanner === undefined) {
                that.index.modifyIndex.call(that);  //Flagged
                nextTarget = that.element.children('li').eq(that.currentIndex);
                nextTarget.css('top', tHeight).show();
                activeTarget.animate({
                    top: '-=' + tHeight
                }, that.settings.motionTimer, function () {
                    activeTarget.hide();
                });
                nextTarget.animate({
                    top: '0'
                }, that.settings.motionTimer);
                that.updateStatus.target(activeTarget);
                that.updateStatus.target(nextTarget);
                that.updateStatus.paginator.apply(that, [alteredIndex]);

            }
            else {
                nextTarget = jQuery(selectedBanner);
                if (direction === 'forward') {
                    nextTarget.css('top', tHeight).show();
                    activeTarget.animate({
                        top: '-=' + tHeight
                    }, that.settings.motionTimer, function () {
                        activeTarget.hide();
                    });
                    nextTarget.animate({
                        top: '0'
                    }, that.settings.motionTimer, function () {
                        that.updateStatus.target(activeTarget);
                        that.updateStatus.target(nextTarget);
                        that.updateStatus.paginator.apply(that, [alteredIndex]);
                        if (that.settings.autoRestart) {
                            that.startTimer(that.settings.timer);
                        }
                    });
                }
                else {
                    nextTarget.css('top', -tHeight).show();
                    activeTarget.animate({
                        top: '+=' + tHeight
                    }, that.settings.motionTimer, function () {
                        activeTarget.hide();
                    });
                    nextTarget.animate({
                        top: '0'
                    }, that.settings.motionTimer, function () {
                        that.updateStatus.target(activeTarget);
                        that.updateStatus.target(nextTarget);
                        that.updateStatus.paginator.apply(that, [alteredIndex]);
                        if (that.settings.autoRestart) {
                            that.startTimer(that.settings.timer);
                        }
                    });
                }
            }
        }
	},
	paginator: {
		buildPaginator: function (obj) {
			this.createPanel(obj);
			this.assignNodes(obj);
			jQuery("." + obj.settings.paginatorId + " li a" + ".target0").addClass(obj.settings.paginatorCurrent);
		},
		createPanel: function (obj) {
            var targetController = document.createElement("ul"),
            counter = 0;
            targetController.className = obj.settings.paginatorId;
			for (; counter < obj.targetCount; counter += 1) {
				this.createNode(counter, targetController, obj);
			}
			obj.element.after(targetController);
		},
		createNode: function (counter, targetController, obj) {
			var targetAnchor = document.createElement("a"),
			li = document.createElement("li");
			targetAnchor.setAttribute('href', '#');
			targetAnchor.className = "target" + counter;
			li.appendChild(targetAnchor);
			targetController.appendChild(li);
			if (obj.settings.paginatorLabel) {
				this.labelNodes(targetAnchor, counter);
			}
		},
		labelNodes: function (targetAnchor, counter) {
			var anchorText = document.createTextNode(counter + 1);
			targetAnchor.appendChild(anchorText);
		},
		individualAssigner: function (i) {
            var that = this;
			jQuery("." + this.settings.paginatorId + " li a" + ".target" + i).click(function () {
				if (that.element.hasClass(that.settings.paginatorCurrent)) {
					return false;
				}
				clearInterval(that.timer);
				that.index.modifyIndex.apply(that, [that.element.children('li').eq(i), i]);
				return false;
			});
		},
		assignNodes: function (obj) {
			for (var i = 0; i < obj.targetCount; i += 1) {
                this.individualAssigner.apply(obj, [i]);
			}
		}
	},
	prevNext: function () {
        var that = this,
			prevButton = $(document.createElement('a')).addClass(this.settings.prevId).attr('href', '#').click(function () {
				clearInterval(that.timer);
				that.index.modifyIndex.apply(that, [jQuery(that.element.selector + " li").eq(that.currentIndex - 1), that.currentIndex - 1, 'backward']);
				return false;
			}),
			nextButton = $(document.createElement('a')).addClass(this.settings.nextId).attr('href', '#').click(function () {
				clearInterval(that.timer);
				that.index.modifyIndex.apply(that, [jQuery(that.element.selector + " li").eq(that.currentIndex + 1), that.currentIndex + 1, 'forward']);
				return false;
			});
        this.element.append(prevButton);
        this.element.append(nextButton);
	},
	startTimer: function () {
		var that = this;
		clearInterval(this.settings.timer);
		this.timer = setInterval(function() {that.chosenMotion.call(that);}, that.settings.timer);
	},
	updateStatus: {
		paginator: function (alteredIndex) {
			var contNode = jQuery("." + this.settings.paginatorId + " li a");
			contNode.removeClass(this.settings.paginatorCurrent);
			if (alteredIndex !== undefined) {
				jQuery("." + this.settings.paginatorId + " li a" + ".target" + alteredIndex).addClass(this.settings.paginatorCurrent);
			}
			else {
				jQuery("." + this.settings.paginatorId + " li a" + ".target" + this.currentIndex).addClass(this.settings.paginatorCurrent);
			}
		},
		target: function (target) {
			jQuery(target).toggleClass('active');
		}
	}
};


jQuery.fn.transpose = function(options){
	new Transpose(this, options);
	return this;
};
