/**
* FD.widget.SidePoper
*
* 边界浮出类
* 限制：
* 		1、此类对象限于viewport边界附近的浮出和隐去
* 		2、必须包含js/core/fdev.js(不依赖js/core/yui/animation.js)
* 		3、如果未提供必要的css设置（触点样式）则还需要包含css/widget/sidepoper.css文件
* 调用方法：
FD.widget.SidePoper.init('SidePop-1','http://blog.china.alibaba.com/misc/pop/searchPop.html?keywords=mp3',{dockSide:0,baseline:1,bias:300,expandDir:0,initWidth:353,initHeight:280,remainArea:26});
FD.widget.SidePoper.init('SidePop-2','<div>...</div>',{dockSide:0,baseline:1,bias:300,expandDir:0,initWidth:353,initHeight:280,remainArea:26});
*
*
* @author 	balibell
* @link    http://www.fdev-lib.cn/
*/
FD.widget.SidePop = function (id,cont,cfg){
FYE.on(window,'load',function (){
this.init(id,cont,cfg);
}.call(this));
}
/* 默认参数配置 */
FD.widget.SidePop.defConfig = {
originWidth : null,						/* 对象区域完全宽度 */
originHeight : null,					/* 对象区域完全高度 */
initWidth : null,						/* 对象区域初始宽度 */
initHeight : null,						/* 对象区域初始高度 */
remainArea : 32,						/* 收起后，保留的区域宽度 */
initTop : null,							/* 对象初始的top值 默认为null值情况下，如果baseline==1 则浮出对象从底部弹出*/
btnset : 3,								/* 设置功能按钮 0-无 1-有关闭功能 2-有展开缩小功能 3-有前面两个功能*/
scroll : 1,								/* 是否跟随滚动轴滚动 1-是 0-否*/
initExe : 0,							/* 初始化完毕执行的方法 0-不执行任何方法 1-执行maxIt() 2-执行minIt() 3-执行close()*/
exeDelay : 0,							/* 初始化完毕执行的方法 延迟执行 ms为单位*/
doAfterClose : null,					/* 关闭后执行 */
dockSide : 1,							/* 停靠方向 0-左边停靠  >1-右边停靠*/
departure : 0,							/* 偏离停靠边的距离 值为center时 居中*/
baseline : 0,							/* 0:上基线-viewport上边界；1:下基线-viewport下边界；2:上基线，原位置顶部之下开始随滚动轴滚动 */
bias :0,								/* 偏离基线的距离 值为middle时 居中*/
expandDir : 0,							/* 展开方向 0-上下 1-左右*/
expandSpeed : 0.1,						/* 展开或隐去的速度 */
floatSpeed : 0.2,						/* 滚动跟随的速度 */
defaultShell : 0,						/* 0-无外框 1-使用默认的外框 */
shellBlank : 8,							/* 当defaultShell 生效时，此参数表示外框和内容间非展开方向上的留白 */
zIndex : 1000							/* 浮出层zindex */
};
//SidePop类 purge 函数，可根据对象id purge 对象或，全部 purge
FD.widget.SidePop.purge = function (id){
//实例化该类的purge 对象
var p = new FD.widget.SidePop('sidePop-purge','',{});
var i = p.registry.length;
while( i-- > 0 ){
if(id && p.registry[i].obj.id == id ){ //如果根据id 查找到相应对象
p.registry[i].close(); //目标对象关闭
p.close();	//purge 对象关闭
p.registry.pop(); //对象注册数组弹出 purge 对象
p.registry[i] = p.registry[p.registry.length-1]; //目标对象置换到对象注册数组尾部
p.registry.pop();//弹出目标对象
return;
}else if(!id){
p.registry[i].close(); //如果没有传入特定id，循环关闭所有对象
}
}
p.close();//purge 对象关闭
if( id && i == 0 ){
p.registry.pop(); //有传入id，但未寻获与id对应的对象，则执行 对象注册数组弹出 purge 对象
}else{
p.registry = []; //未传入id，清空对象注册数组。 还有一种情况，传入了id，并且寻找到对象，在之上 return 出去了
}
}
FD.widget.SidePop.prototype = {
registry : [],
init: function (id,cont,cfg){
this.config = FD.common.applyIf(cfg||{}, FD.widget.SidePop.defConfig);
/*************************
功能区字符串生成
*************************/
var btns = ['none','none','none'];
//根据btnset 设置功能区按钮
if(this.config.btnset == 1){
btns[2] = '';
}else if(this.config.btnset == 2){
btns[0] = '';
}else if(this.config.btnset > 2){
btns[2] = '';
btns[0] = '';
}
//浮出控制栏字符串，提供关闭、最小化、还原功能，依赖样式
var strBar = ['<div id="',id,'-bar" class="f-sidebar"><a id="',id,'-min" class="f-sidemin" style="display:',btns[0],'" href="javascript:void(0)" target="_self"></a><a id="',id,'-res" class="f-sideres" style="display:',btns[1],'" href="javascript:void(0)" target="_self"></a><a id="',id,'-close" class="f-sideclose" style="display:',btns[2],'" href="javascript:void(0)" target="_self"></a></div>'].join('');
/*************************/
/*************************
创建对象节点
*************************/
//如果对象id不存在，新建div，为浮出层最外层div，并设置其id
if(!(this.obj = FYG(id))){
//如果未设置初始宽（高）度，则取值100
this.config.initWidth = this.config.initWidth || 100;
this.config.initHeight = this.config.initHeight || 100;
this.config.originWidth = this.config.originWidth || this.config.initWidth;
this.config.originHeight = this.config.originHeight || this.config.initHeight;
this.obj = document.createElement('div');
this.obj.id = id;
//页面加载对象
document.body.appendChild(this.obj);
var d = this.config.defaultShell;
var strShellTop = d ? '<div class="f-sidepop"><div class="tt f-sidepop-tt"><div class="ttl"></div><div class="ttr"></div><div class="ttc">'+d+'<p></p></div><div class="ttr"></div></div><div class="f-sidepop-cont"><div class="f-sidepop-contin">' : '';
var strShellBot =  d ? '' : '</div></div></div>'
var s = d ? this.config.expandDir == 0 ? [this.config.shellBlank,this.config.remainArea] : [this.config.remainArea,this.config.shellBlank] : [0,0];
var cw = [];
cw[0] = this.config.expandDir == 1 && d ? this.config.initWidth : this.config.originWidth;
cw[1] = this.config.expandDir == 0 && d ? this.config.initHeight : this.config.originHeight;
//浮出内容字符串 strCont
//情况1：传入cont 为url地址，调用 iframe 模式
//情况2：传入cont 为html代码，调用非 iframe 模式
var strCont = cont.match(/^http:\/\//g) ?
/*  iframe 模式*/['<iframe id="',id,'-cont" src="',cont,'" frameborder="0" scrolling="no" width="',cw[0] - s[0],'" height="',cw[1]  - s[1],'" ></iframe>'].join('') :
/*非iframe 模式*/['<div id="',id,'-cont" style="overflow:hidden;width:',cw[0] - s[0],'px;height:',cw[1] - s[1],'px;">',cont,'</div>'].join('');
//装载内容，浮出内容字符串 + 浮出控制栏字符串
this.obj.innerHTML = [strShellTop,strCont,strShellBot,strBar].join('');
}else{
if(YAHOO.lang.isString(cont) && cont){
if(cont.match(/^http:\/\//g)){
//iframe 模式
FYG(id+'-cont').src = cont;
}else{
//普通容器模式
FYG(id+'-cont').innerHTML = cont;
}
}
this.obj.style.display = 'block';
//如果未设置初始宽（高）度，则取值offsetWidth（offsetHeight）
var w =  parseInt(0 + FYD.getStyle(this.obj,'borderLeftWidth')) + parseInt(0 + FYD.getStyle(this.obj,'borderRightWidth'))
this.config.initWidth = this.config.initWidth || this.obj.offsetWidth - w;
this.config.initHeight = this.config.initHeight || this.obj.offsetHeight - w;
this.config.originWidth = this.config.originWidth || this.config.initWidth;
this.config.originHeight = this.config.originHeight || this.config.initHeight;
//为已存在的对象添加功能区（最小化、还原、关闭）
var barobj = document.createElement('span');
barobj.innerHTML = strBar;
this.obj.appendChild(barobj);
}
this.expandObj = d ? FYG(id+'-cont') : this.obj;
/*************************/
/*************************
对象基本属性设置
*************************/
this.obj.style.position = 'absolute';
this.obj.style.overflow = 'hidden';
this.obj.style.zIndex = this.config.zIndex;
this.obj.style.width = this.config.initWidth + 'px';
this.obj.style.height = this.config.initHeight + 'px';
/**** config参数调整 ****/
this.config.departure = this.config.departure == 'center' ? ( FYD.getViewportWidth() - this.obj.offsetWidth )/2 : this.config.departure;
this.config.bias = this.config.bias == 'middle' ? ( FYD.getViewportHeight() - this.obj.offsetHeight )/2 : this.config.bias;
if(YAHOO.env.ua.ie == 6 && this.config.baseline == 0 || YAHOO.env.ua.ie == 7 && this.config.baseline == 1 || YAHOO.env.ua.opera && this.config.baseline == 0){
this.config.bias += 2
}else if(YAHOO.env.ua.ie == 6 && this.config.baseline == 1 || YAHOO.env.ua.ie == 7 && this.config.baseline == 0 || YAHOO.env.ua.opera && this.config.baseline == 1){
this.config.bias -= 2
}
this.obj.style.left = this.config.dockSide ? 'auto' : this.config.departure + 'px';
this.obj.style.right = this.config.dockSide ? this.config.departure + 'px' : 'auto';
/*************************/
/*************************
功能区按钮事件绑定
*************************/
//临时对象，方便事件绑定。以下绑定功能区按钮相关事件
var _this = this;
//关闭按钮事件绑定
FYE.on(_this.obj.id+'-close','click',function (){
_this.close();
_this.doAfterClose();
return false;
});
//最小化按钮事件绑定
FYE.on(_this.obj.id+'-min','click',function (){
_this.minIt();
return false;
});
//恢复按钮事件绑定
FYE.on(_this.obj.id+'-res','click',function (){
_this.maxIt();
return false;
});
/*************************/
/*************************
随滚动轴滚动的参数设定
*************************/
//设置初始状态的top 值，之前已设置过 position:absolute;
this.obj.style.top =  (this.config.initTop == null ? this.config.baseline == 0 ? 0 : FYD.getViewportHeight() + FYD.getDocumentScrollTop() : this.config.initTop) + 'px';
this.firstScroll = this.lastScroll = -this.config.bias; //firstScroll lastScroll 在 scrollWidth 方法中使用
if(this.config.baseline == 2){//如果 baseline == 2 当滚动轴滚动至对象原来位置的下方，开始有效浮动
this.obj.style.top = 0;
this.obj.style.position = 'relative';
}else if(this.config.baseline == 1){//如果 baseline == 1 基线为viewport 底部，此时bias 为距离底部的高度
this.lastScroll = this.obj.offsetHeight - FYD.getViewportHeight() -  FYD.getDocumentScrollTop();
this.firstScroll = this.lastScroll - this.config.bias;
}
this.aTop =  YAHOO.env.ua.opera ? FYD.getY(this.obj) + FYD.getDocumentScrollTop() + 2 : FYD.getY(this.obj);
/*************************/
//timer控制器，在最小化、恢复原状过程中起作用
this.expandTimer = null;
//timer控制器，在滚动跟随过程中起作用
this.scrollTimer = null;
//this.expandObj 对象当前高（宽）度，在显示或隐去过程中改变，与对象高度实时保持一致
//当defaultShell 生效时，this.expandObj 指代内容对象，不包括外框。
if(this.config.expandDir == 0){ //垂直方向展开收拢
this.size = d ? this.config.initHeight - this.config.remainArea : this.config.initHeight;
}else if(this.config.expandDir == 1){//水平方向展开收拢
this.size = d ? this.config.initWidth - this.config.remainArea : this.config.initWidth;
}
//根据initExe设置执行相关方法
if(this.config.initExe == 1){
setTimeout(function (){
_this.maxIt();
},this.config.exeDelay)
}else if(this.config.initExe == 2){
setTimeout(function (){
_this.minIt();
},this.config.exeDelay)
}else if(this.config.initExe == 3){
setTimeout(function (){
if(FYD.getStyle(this.obj,'display') == 'none'){return}
_this.close();
_this.doAfterClose();
},this.config.exeDelay)
}
//根据scroll设置执行相关方法
if(this.config.scroll){
this.scrollWith();
}
this.registry.push(this) //将新对象 push 入对象注册数组，即注册新对象
},
/*
功能区功能之 关闭功能
*/
close: function (){
//清除各种timer
clearTimeout(this.expandTimer);
clearInterval(this.scrollTimer);
FYE.purgeElement(this.obj.id+'-res')
FYE.purgeElement(this.obj.id+'-min')
FYE.purgeElement(this.obj.id+'-close')
//将对象设为隐藏
FYD.setStyle(this.obj,'display','none');
var tmp;
if(tmp=FYG(this.obj.id+'-bar')){
FYG(this.obj.id+'-bar').parentNode.removeChild(tmp)
}
},
/*
关闭功能辅助，关闭后执行
*/
doAfterClose: function (){
if(YAHOO.lang.isFunction(this.config.doAfterClose)){
this.config.doAfterClose();
}
},
/*
功能区功能之 最小化功能
*/
minIt: function (){
var _this = this;
//		if(FYU.Anim){
//			var an = _this.config.expandDir ? new FYU.Anim(_this.obj,{
//				width : { from : _this.size , to : _this.config.remainArea }
//			},2*_this.config.expandSpeed) : new FYU.Anim(_this.obj,{
//				height : { from : _this.size , to : _this.config.remainArea }
//			},2*_this.config.expandSpeed)
//			an.animate();
//			an.onComplete.subscribe(function (){
//				//设置最小化、恢复等功能区按钮状态
//				FYD.setStyle(_this.obj.id+'-min','display','none');
//				FYD.setStyle(_this.obj.id+'-res','display','block');
//			});
//			an.onTween.subscribe(function (){
//				_this.size = _this.config.expandDir ? parseInt(_this.obj.style.width) : parseInt(_this.obj.style.height);
//			});
//		}else{
//最小化过程函数，递归调用自身，满足条件跳出递归
(function _minIt(){
var theRemain = _this.config.defaultShell ? 0 : _this.config.remainArea;
var condition = [_this.size <= theRemain];
//满足条件跳出递归，条件1：对象当前高度小于等于对象预留高（宽）度（仅显示标题状态）
if(condition[0]){
window.clearTimeout(_this.expandTimer);
//设置最小化、恢复等功能区按钮状态
FYD.setStyle(_this.obj.id+'-min','display','none');
FYD.setStyle(_this.obj.id+'-res','display','block');
//innerCall(0);
//跳出递归
return;
}
//计算每单位时间内移动的距离，其值等于伪速率乘以对象当前高度
var len = _this.config.expandSpeed * _this.size;
len = len < 1 ? 1 : len;
//对象当前高度数值计算，满足条件1，其值等于对象预留高（宽）度，不满足条件1，其值自减len
_this.size = _this.size - len <= theRemain ? theRemain : _this.size - len;
//设置对象高度
if( _this.config.expandDir ){
_this.expandObj.style.width = _this.size + 'px';
if( _this.config.defaultShell ){
_this.obj.style.width = _this.size + _this.config.remainArea + 'px'
}
}else{
_this.expandObj.style.height = _this.size + 'px';
if( _this.config.defaultShell ){
_this.obj.style.height = _this.size + _this.config.remainArea + 'px'
}
}
//递归调用自身
_this.expandTimer = window.setTimeout(_minIt,10);
})();
//		}
},
/*
功能区功能之 还原功能
*/
maxIt: function (){
var _this = this;
//		if(FYU.Anim){
//			var an = _this.config.expandDir ? new FYU.Anim(_this.obj,{
//				width : { from : _this.size , to : _this.config.originWidth }
//			},2*_this.config.expandSpeed) : new FYU.Anim(_this.obj,{
//				height : { from : _this.size , to : _this.config.originHeight }
//			},2*_this.config.expandSpeed);
//			an.animate();
//			an.onComplete.subscribe(function (){
//				//设置最小化、恢复等功能区按钮状态
//				FYD.setStyle(_this.obj.id+'-min','display','block');
//				FYD.setStyle(_this.obj.id+'-res','display','none');
//			});
//			an.onTween.subscribe(function (){
//				_this.size = _this.config.expandDir ? parseInt(_this.obj.style.width) : parseInt(_this.obj.style.height);
//			});
//		}else{
//最小化过程函数，递归调用自身，满足条件跳出递归
(function _maxIt(){
var theOrigin = _this.config.expandDir ?  _this.config.originWidth : _this.config.originHeight;
theOrigin -= _this.config.defaultShell ? _this.config.remainArea : 0;
var condition = [_this.size >= theOrigin]
//满足条件跳出递归，条件1：对象当前高度大于等于对象原始高度（完全显示状态）
if(condition[0]){
window.clearTimeout(_this.expandTimer);
//设置最小化、恢复等功能区按钮状态
FYD.setStyle(_this.obj.id+'-min','display','block');
FYD.setStyle(_this.obj.id+'-res','display','none');
//					FYD.setStyle(_this.obj,'visibility','hidden');
//					FYD.setStyle(_this.obj,'visibility','visible');
//跳出递归
return;
}
//计算每单位时间内移动的距离，其值等于伪速率乘以对象原始高度，为匀速
var len = _this.config.expandSpeed * theOrigin;
len = len < 1 ? 1 : len;
_this.size = _this.size + len >= theOrigin ? theOrigin : _this.size + len;
//设置对象高度
if( _this.config.expandDir ){
_this.expandObj.style.width = _this.size + 'px';
if( _this.config.defaultShell ){
_this.obj.style.width = _this.size + _this.config.remainArea + 'px'
}
}else{
_this.expandObj.style.height = _this.size + 'px';
if( _this.config.defaultShell ){
_this.obj.style.height = _this.size + _this.config.remainArea + 'px'
}
}
//递归调用自身
_this.expandTimer = window.setTimeout(_maxIt,10);
})();
//		}
},
/*
浮动对象随滚动轴滚动
*/
scrollWith : function(){
var _this = this;
_this.scrollTimer = window.setInterval(function (){
var dscrtop = FYD.getDocumentScrollTop();
var a = _this.config.baseline;
var perlen;
var fall = _this.obj.offsetHeight - FYD.getViewportHeight();
fall  = fall < 0 ? 0 : fall;
if(a == 0){//baseline == 0 以viewport 顶部为基线
perlen = _this.config.floatSpeed*(dscrtop - _this.lastScroll - _this.aTop - fall);
}else if(a == 1){//baseline == 1  以viewport 底部为基线
perlen = _this.config.floatSpeed*(- _this.lastScroll  + _this.firstScroll + FYD.getViewportHeight() + dscrtop - _this.obj.offsetHeight - _this.aTop );
}else{//baseline == 2 特殊处理 以viewport 顶部为基线
var tmpsp = _this.config.floatSpeed*(dscrtop - _this.aTop - _this.lastScroll - fall)
perlen = dscrtop - _this.aTop > 0 || (YAHOO.env.ua.opera ? FYD.getY(_this.obj) + FYD.getDocumentScrollTop()  + 2 : FYD.getY(_this.obj)) > _this.aTop ?  tmpsp  : 0;
}
if( perlen > -0.2 && perlen < 0.2 ){
return
}else{
perlen = perlen>0 ? Math.ceil(perlen) : perlen=Math.floor(perlen)
}
_this.obj.style.top = parseInt(_this.obj.style.top) + perlen + "px"
if(a > 1 && parseInt(_this.obj.style.top) <= 0){//baseline == 2 特殊处理 以viewport 顶部为基线
_this.obj.style.top = 0;
_this.lastScroll = _this.firstScroll;
}else{
_this.lastScroll += perlen;
}
},10);
}
}
/**
* SidePoper 的封装，创建不同的 SidePop 对象
*/
FD.widget.SidePoper = new function() {
this.init = function(id,cont,cfg) {
return new FD.widget.SidePop(id,cont,cfg);
}
}
