
/*
 * Sequence provides an index into an array and throws an event when 
 * changes occur.
 */
function Sequence(myArray, onFirst, onLast, onChange) {
	this.myArray = myArray;
	this.currentIndex = 0;
	this.wrapBehavior = "wrap";
	this.onFirst = onFirst;
	this.onLast = onLast;
	this.onChange = onChange;
	this.getSize = function() {
		if(this.myArray) {
			return this.myArray.length;
		} else {
			return 0;
		}
	}
	this.getLastIndex = function() {
		if(this.myArray) {
			return this.myArray.length - 1;
		} else {
			return 0;
		}
	}
	this.getNextIndex = function() {
		var nextInd = 0;
		if(this.wrapBehavior == "wrap") {
			if(this.currentIndex < this.getLastIndex()) {
				nextInd = this.currentIndex + 1;
			} else {
				nextInd = 0;
			}
		} else if(this.wrapBehavior == "nowrap") {
			if(this.currentIndex < this.getLastIndex()) {
				nextInd = this.currentIndex + 1;
			} else {
				nextInd = this.currentIndex;
			}
		}
		return nextInd;
	}
	this.getPreviousIndex = function() {
		var prevInd = 0;
		if(this.wrapBehavior == "wrap") {
			if(this.currentIndex > 0) {
				prevInd = this.currentIndex - 1;
			} else {
				prevInd = this.getLastIndex();
			}
		} else if(this.wrapBehavior == "nowrap") {
			if(this.currentIndex > 0) {
				prevInd = this.currentIndex - 1;
			} else {
				prevInd = this.currentIndex;
			}
		}
		return prevInd;
	}
	this.getCurrent = function() {
		if(this.myArray) {
			return this.myArray[this.currentIndex];
		} else {
			alert('Sequence.myArray was empty when calling getCurrent()!');
		}
	}
	this.getNext = function() {
		if(this.myArray && this.myArray.length > 0) {
			return this.myArray[this.getNextIndex()];
		} else {
			alert('Sequence.myArray was empty when calling getNext()!');
		}
	}
	this.getPrevious = function() {
		if(this.myArray && this.myArray.length > 0) {
			return this.myArray[this.getPreviousIndex()];
		} else {
			alert('Sequence.myArray was empty when calling getPrevious()!');
		}
	}
	this.get = function(index) {
		if(this.myArray && this.myArray.length > 0) {
			if(index >= 0 && index < this.getSize()) {
				return this.myArray[index];
			} else {
				alert('Sequence.get -> Index out of bounds: '+index+' (0'+this.getSize());
			}
		} else {
			alert('Sequence.myArray was empty when calling get()!');
		}
	}
	
	this.next = function() {
		var newInd = this.getNextIndex();
		// Make sure this is a change - otherwise do nothing.
		if(this.currentIndex != newInd) {
			// Build the change event
			var event = new this.changeEvent(this.currentIndex, newInd, this.getCurrent(), this.getNext());
			// Move to the next index
			this.currentIndex = this.getNextIndex();
			
			if(this.wrapBehavior == "nowrap") {
				// Check for the onLast function
				if(this.currentIndex == this.getLastIndex() && this.onLast) {
					this.onLast();
				}
			}
			
			// Fire the change event
			if(this.onChange) {
				this.onChange(event);
			}
		}
	}
	
	this.previous = function() {
		var newInd = this.getPreviousIndex();
		// Make sure this is a change - otherwise do nothing.
		if(this.currentIndex != newInd) {
			// Build the change event
			var event = new this.changeEvent(this.currentIndex, newInd, this.getCurrent(), this.getPrevious());
			// Move to the previous index
			this.currentIndex = this.getPreviousIndex();

			if(this.wrapBehavior == "nowrap") {
				// Check for the onFirst function
				if(this.currentIndex == 0 && this.onFirst) {
					this.onFirst();
				}
			}

			// Fire the change event
			if(this.onChange) {
				this.onChange(event);
			}
		}
	}
	
	this.random = function() {
		if(this.getSize() > 1) {
			var largeNumber = Math.round(Math.random()*10000000);
			var newInd = largeNumber % this.getSize();
			
			if(newInd != this.currentIndex) {
				// Build the change event
				var event = new this.changeEvent(this.currentIndex, newInd, this.getCurrent(), this.get(newInd));
				
				// Move to the random item.
				this.currentIndex = newInd;
				
				// Fire the change event
				if(this.onChange) {
					this.onChange(event);
				}
			} else {
				// try again until we make a change.
				this.random();
			}
		}
	}
	
	// The change event object will be passed to change event listeners
	this.changeEvent = function(oldIndex, newIndex, oldValue, newValue) {
		this.oldIndex = oldIndex;
		this.newIndex = newIndex;
		this.oldValue = oldValue;
		this.newValue = newValue;
	}
}