﻿/**
 * FD.widget.Scroll
 *
 * 滚动类
 * 限制：
 * 		1、container 必须是一个<ul>
 * 		2、必须包含js/core/fdev.js和js/core/yui/animation-min.js两个js文件
 * 调用方法：
 * 		……
 *		<ul id="scroll1">
 *			<li><a href="#">内容1内容1内容1内容1内容1</a></li>
 *			<li><a href="#">内容2内容2内容2内容2内容2</a></li>
 *			<li><a href="#">内容3内容3内容3内容3内容3</a></li>
 *		</ul>
 *		……
 *		<script type="text/javascript">
 *			FD.widget.Scroll.init('scroll1',{});
 *		</script>
 *
 */

FD.widget.Scroll = new function() {
		var defConfig = {
		delay: 2,			
		speed: 20,
		startDelay: 2,
		direction: 'vertical',	/* 'horizontal(h)' or 'vertical(v)'. defaults to vertical. */		
		disableAutoPlay: false, 
		distance: 'auto',
		scrollItemCount: 1  	/* 随同一行滚动的li数量，默认1 */		
	}
	
	/**
	 * decorate 开始滚动
	 * @param {Object} container 必须是一个ul
	 * @param {Object} config
	 */
	this.init = function(container, config) {
		container = $(container);
		config = FD.common.applyIf(config||{}, defConfig);
		var step = 2;
		if (config.speed < 20) {
			step = 5;
		}
		if (config.lineHeight) {
			config.distance = config.lineHeight;
		}
		
		var scrollTimeId = null, startTimeId = null, startDelayTimeId = null;
		/* 是否横向滚动 */
		var isHorizontal = (config.direction.toLowerCase() == 'horizontal') || (config.direction.toLowerCase() == 'h'); 
		
		/* 返回给调用者的控制器，只包含对调用者可见的方法/属性 */	
		var handle = {};
		handle._distance = 0;
		/* 空间上能否还可以滚动 */
		handle.scrollable = true;
		/* 本次预计滚动的距离 */
		handle.distance = config.distance;
		/* 每次滚动的距离 */
		handle._distance = 0;
		/* 鼠标移动上去时暂停 */
		handle.suspend = false;
		/* 暂停 */
		handle.paused = false;
	
		
		/* 内部使用事件 */
		var _onScrollEvent = new $Y.CustomEvent("_onScroll", handle, false, $Y.CustomEvent.FLAT);
		_onScrollEvent.subscribe(function() {
			var curLi = container.getElementsByTagName('li')[0];
			if (!curLi) { 
				this.scrollable = false;
				return;
			}
			this.distance = (config.distance == 'auto')?curLi[isHorizontal?'offsetWidth':'offsetHeight']:config.distance;
			with(container) { 
				if (isHorizontal)
					this.scrollable = (scrollWidth - scrollLeft - offsetWidth) >= this.distance;
				else 
					this.scrollable = (scrollHeight - scrollTop - offsetHeight) >= this.distance;
			}
		});
		
		/* 公开事件 */
		var onScrollEvent = new $Y.CustomEvent("onScroll", handle, false, $Y.CustomEvent.FLAT);
		if (config.onScroll) {
			onScrollEvent.subscribe(config.onScroll);
		} else {
			onScrollEvent.subscribe(function() {
				for (var i = 0; i < config.scrollItemCount; i++) {
					container.appendChild(container.getElementsByTagName('li')[0]);
				}
				container[isHorizontal?'scrollLeft':'scrollTop'] = 0;
			});
		}
		
		var scroll = function() {
			if (handle.suspend) return;
			handle._distance += step;
			var _d; 
			if ((_d = handle._distance % handle.distance) < step) {
				container[isHorizontal?'scrollLeft':'scrollTop'] += (step - _d);
				clearInterval(scrollTimeId);
				onScrollEvent.fire();
				_onScrollEvent.fire();
				startTimeId = null;
				if (handle.scrollable && !handle.paused) handle.play();
			}else{
				container[isHorizontal?'scrollLeft':'scrollTop'] += step;
			}
		}
		
		var start = function() {
			if (handle.paused) return;
			handle._distance = 0;
			scrollTimeId = setInterval(scroll, config.speed);
		}

		$E.on(container, 'mouseover', function(){handle.suspend=true;});
		$E.on(container, 'mouseout', function(){handle.suspend=false;});
		
		FD.common.apply(handle, {
			subscribeOnScroll: function(func, override) {
				if (override === true && onScrollEvent.subscribers.length > 0)
					onScrollEvent.unsubscribeAll();
				onScrollEvent.subscribe(func);
			},
			pause: function() {
				this.paused = true;
				clearTimeout(startTimeId);
				startTimeId = null;
			},
			play: function() {
				this.paused = false;
				if (startDelayTimeId) {clearTimeout(startDelayTimeId);}
				if (!startTimeId) {
					startTimeId = setTimeout(start, config.delay*1000);	
				}
			}
		});
		handle.onScroll = handle.subscribeOnScroll;
		
		/** 初始化移动距离并判断是否可滚动 */
		_onScrollEvent.fire();
		/** 自动开始滚动 */		
		if (!config.disableAutoPlay) {
			startDelayTimeId = setTimeout(function(){handle.play();}, config.startDelay*1000);
		}		
		return handle;
	}
};