/**
 * Object scrolls subcontainer of $container in desired direction
 * You can define youre own buttons, just pass them to the construtor
 * within the settings object
 * You can specify Callbacks for scrollstart and stop, fps,
 * events that trigger start and stop and the amount of pixels
 * to be scrolled at once
 *
 * @author Henning Künne
 * @version 1.0
 * @license feel free
 */

/**
 * Constructor
 *
 * @param OBJECT settings
 * example:
 *
 {
        container:container,              				// Reference to container to scroll (mandatory)
        startEvent:'mousedown',                         // Trigger scrollstart whithin this event (mandatory)
        stopEvent:'mouseup',                            // Trigger scrollstop whithin this event (mandatory)
        buttons:{
            left:scrollLeftButton,			            // References to the elements to be used as buttons (minimum 1 is obviously mandatory)
            right:scrollRightButton, 		            // does not trigger an error when empty
            up:scrollUpButton,
            down:scrollDownButton
        },
        hideScrollBars:true,                            // Hide scrollbars (optional)
        onscrollstart:console.log,                      // Reference to function to be triggered on start of scrolling (optional)
        onscrollstop:console.log,                       // Reference to function to be triggered on stop of scrolling (optional)
        fps:25,                                         // Frames per second (optional, defaults to 25)
        step:20                                         // Width of the Animationsteps in Pixel (optional, defaults to 20)
 }
 */
var RemoteScroller = function (settings) {
	if (typeof settings == 'undefined') {
		throw('No settings given');
	}
	if (typeof settings.container == 'undefined') {
		throw('No id given. Specify id of container to be scrolled');
	}
	if (typeof settings.buttons == 'undefined') {
		throw('Specify buttons')
	}
	if (typeof settings.startEvent == 'undefined') {
		throw('Specify startevent')
	}
	if (typeof settings.stopEvent == 'undefined') {
		throw('Specify stopevent')
	}
	this.container = settings.container; // fetch container to scroll
	if (typeof settings.hideScrollBars != 'undefined' && settings.hideScrollBars === true) {
		this.container.style.overflow = 'hidden';
	}
	this.maxScrollLeft = this.container.scrollWidth - this.container.clientWidth;
	this.maxScrollTop = this.container.scrollHeight - this.container.clientHeight;
	this.startEvent = settings.startEvent || 'mousedown';
	this.stopEvent = settings.stopEvent || 'mouseup';
	this.fps = settings.fps || 25;
	this.step = settings.step || 20;

	var that = this;	// closure
	for (var i in settings.buttons) {
		settings.buttons[i].RemoteScrollButtonDir = i;
		if (typeof settings.buttons[i].addEventListener != 'undefined'){
			settings.buttons[i].addEventListener(this.startEvent, function () {
				that.startScroll(this);
			}, false);
			settings.buttons[i].addEventListener(this.stopEvent, function () {
				that.stopScroll(this);
			}, false);
		}
		else {
			settings.buttons[i].attachEvent('on'+this.startEvent, function (e) {
				that.startScroll(e.srcElement);
			});
			settings.buttons[i].attachEvent('on'+this.stopEvent, function (e) {
				that.stopScroll(e.srcElement);
			});
		}
	}

	this.callbacks = {};
	this.callbacks.start = function (button) {
		if (typeof settings.onscrollstart == 'function') {
			settings.onscrollstart(button);
		} else return
	}
	this.callbacks.stop = function (button) {
		if (typeof settings.onscrollstop == 'function') {
			settings.onscrollstop(button);
		} else return
	}

    this.buttons = settings.buttons;
	this.scrollable = this.getScrollable();
    var e = {
        button:false,
        buttons:this.buttons,
        scrollableButtons:this.scrollable
    };
    this.callbacks.start(e);
}

/**
 * Invoke the scrolling process by setting an interval
 *
 */
RemoteScroller.prototype.startScroll = function (button) {
	var that = this;
	this.callbacks.start({button:button,scrollableButtons:this.getScrollable(),buttons:this.buttons});
	this.scrollInterval = window.setInterval(function (){
		that.scroll(button);
	}, Math.round(1000/this.fps))
}

/**
 * scroll the container
 */
RemoteScroller.prototype.scroll = function (button) {
	switch (button.RemoteScrollButtonDir) {
		case 'left':
			if (this.scrollInterval && this.container.scrollLeft >= this.maxScrollLeft) {
				this.stopScroll(button, true);
			} else {
				this.container.scrollLeft = this.container.scrollLeft+this.step;
			}
			break;
		case 'right':
			if (this.scrollInterval && this.container.scrollLeft <= 0) {
				this.stopScroll(button, true);
			} else {
				this.container.scrollLeft = this.container.scrollLeft-this.step;
			}
			break;
		case 'up':
			if (this.scrollInterval && this.container.scrollTop <= 0) {
				this.stopScroll(button, true);
			} else {
				this.container.scrollTop = this.container.scrollTop-this.step;
			}
			break;
		case 'down':
			if (this.scrollInterval && this.container.scrollTop >= this.maxScrollTop) {
				this.stopScroll(button, true);
			} else {
				this.container.scrollTop = this.container.scrollTop+this.step;
			}
			break;
	}
}

/**
 * Stop scrolling by clearing the Interval
 */
RemoteScroller.prototype.stopScroll = function (button, stopPropagation) {
	if (!stopPropagation)
		this.callbacks.stop({button:button,scrollableButtons:this.getScrollable(),buttons:this.buttons});
	if (this.scrollInterval) window.clearInterval(this.scrollInterval);
}

/**
 * Get scrollable directions
 *
 * @return OBJECT
 */
RemoteScroller.prototype.getScrollable = function () {
	var that = this;	// closure
	var buttons = {};
	if (this.buttons.left) {
		buttons.left = that.container.scrollLeft < that.maxScrollLeft ? true : false;
	}
	if (this.buttons.right) {
		buttons.right = that.container.scrollLeft > 0 ? true : false;
	}
	if (this.buttons.up) {
		buttons.up = that.container.scrollTop > 0 ? true : false;
	}
	if (this.buttons.down) {
		buttons.down = that.container.scrollTop < that.maxScrollTop ? true : false;
	}
	return buttons;
}

