DEBUG = false
parse_title = function(title, defaults) {
	if (typeof defaults == 'undefined') var defaults = {}
	if (title) {
		params = title.split(';')
		for (i in params) {
			var param = params[i].split('=')
			defaults[param[0]] = param[1]
		}
	}
	return defaults
}
setupScrollable = function (scrollable) {
	if (scrollable.setup === true) {
		if (DEBUG) log('setup already done ... leaving')
		return
	} else {
		if (DEBUG) log('starting setup...')
	}

	scrollable.scroll = bind(function(amount, delay, units, with_mochikit) {
		if (typeof with_mochikit == 'undefined') with_mochikit = false
		if (DEBUG) log('scroll: ' + amount)
		if (!this.isVerticalBounded()) return
		try {
			if (this.scrollTimer) clearTimeout(this.scrollTimer)	//	stop timers if there are some
			if (typeof units == 'undefined') units = 'px'
			if (this.style.top == "") this.style.top = 0
			new_pos = parseInt(this.style.top) + parseInt(amount)
			bottom = this.clientHeight + new_pos - this.offsetParent.clientHeight
			if (bottom < 0) {
				new_pos -= bottom
				bottom = this.clientHeight + new_pos - this.offsetParent.clientHeight
			}
			if (new_pos > 0) {
				new_pos = 0
			}
			if (bottom >= 0 && new_pos <= 0) {
				if (with_mochikit) Morph(this, {'duration': .15,fps: 50, 'style':{'top':parseInt(new_pos) + units}})
				else this.style.top = parseInt(new_pos) + units
				this.scrollTimer = setTimeout(partial(this.scroll, amount, delay, units, with_mochikit), delay)
			}
		} catch(e) {
			alert(e.description)
		}
	}, scrollable)
	scrollable.stopScroll = bind(function() {
		if (this.scrollTimer) clearTimeout(this.scrollTimer)
	}, scrollable)
	scrollable.scrollDown = bind(function(units, delay) {
		this.scroll(units, delay)
	}, scrollable)
	scrollable.scrollUp = bind(function(units, delay) {
		this.scroll(units, delay, true)
	}, scrollable)
	scrollable.scrollTo = bind(function(new_pos, units) {
		if (this.scrollTimer) clearTimeout(this.scrollTimer)	//	stop timers if there are some
		if (typeof units == 'undefined') units = 'px'
		this.style.top = parseInt(new_pos) + units
	}, scrollable)
	scrollable.isVerticalBounded = bind(function(){
		if (DEBUG) log('isVerticalBounded x < 0: ' + (this.offsetParent.clientHeight - this.clientHeight))
		return this.offsetParent.clientHeight < this.clientHeight
	}, scrollable)
	scrollable.autoStop = bind(function(delay) {
		clearTimeout(this.autoStopTimer)
		this.autoStopTimer = setTimeout(bind(function() {
			this.stopScroll()
			clearTimeout(this.autoStopTimer)
		}, scrollable), delay)
	}, scrollable)
	scrollable.__init__ = bind(function(){
		// checking for special title
		values = parse_title(getNodeAttribute(this, 'title'))
		if ((show = $(values.show)) && this.isVerticalBounded()) {
			if (DEBUG) log('show the scroller')
			appear(show)
		}
		if (typeof values.title != "undefined") {
			setNodeAttribute(this, 'title', values.title)
		}
		scrollable.setup = true
	}, scrollable)
	scrollable.__init__()
}

setupScroller = function(scroller, target, values) {
	//	setup target
	setupScrollable(target)
	if (DEBUG) log('connecting...')
	//	connect handler
	connect(scroller, 'onmousedown', bind(partial(function(amount, delay, units, ev){
		if (DEBUG) log('down')
		this.scroll(amount, delay, units)
	}, values.amount, values.delay, values.units), target))
	connect(scroller, 'onmouseup', bind(function(ev){
		if (DEBUG) log('up')
		this.stopScroll()
	}, target))
	connect(scroller, 'onmouseout', bind(function(ev){
		if (DEBUG) log('out')
		this.stopScroll()
	}, target))
}

/**
 * boot the scrollers
 * we trigger controll over the title attribute of the scroller
 * parameters are seperated by ";" and values are applied by "="
 * @param target:<the id of the target element to be scrolled>
 * @param amount:+/-number of units
 * @param delay:ms of time between next scroll
 * @param units:px|pt|em ...
 * @param title:"the title after successful setup"
 */
addLoadEvent(function() {
	if (DEBUG) log('starting scroll interface')
	forEach(getElementsByTagAndClassName(null, 'scrollable'), function(target){
		setupScrollable(target)
		var values = {
			delay: 1,
			amount: 20,
			title: "",
			autoStop: 150
		}
		var title = getNodeAttribute(target, "title")
		if (title) {
			params = title.split(';')
			for (i in params) {
				var param = params[i].split('=')
				values[param[0]] = param[1]
			}
		}
		//setNodeAttribute(target, 'title', 'use your mouse wheel to scroll')

		connect(target, 'onmousewheel', bind(partial(function(amount, delay, units, autoStop, ev){
			if (DEBUG) log('wheel')
			this.scroll(-(ev.mouse().wheel.y / 3) * amount, delay, units)
			this.autoStop(autoStop)
			ev.stopPropagation()
			ev.stop()
		}, values.amount, values.delay, values.units, values.autoStop), target))
	})

	forEach(getElementsByTagAndClassName(null, 'scroller'), function (scroller) {
		var values = {
			delay: 20,
			title: ""
		}
		var title = getNodeAttribute(scroller, "title")
		if (title) {
			params = title.split(';')
			for (i in params) {
				var param = params[i].split('=')
				values[param[0]] = param[1]
			}
		}
		if (typeof values.target != 'undefined' && (target = $(values.target))) {
			//	setup target
			setupScroller(scroller, target, values)
			setNodeAttribute(scroller, 'title', values.title)
		}
	})
})