var HSlideMenu=function(_containerEl_){
	var $=function(s){return(typeof(s)=="string"?document.getElementById(s):s);},
		uA=navigator.userAgent.toLowerCase(),
		msie=/msie/.test(this.uA)&&!/opera/.test(this.uA),
		rmCls=function(el,c){
			if(el=$(el)){
				var _c=(el.className || "").split(/\s+/),str="";
				for(var i in _c){if(_c[i]!=c) str+=" "+_c[i];}
				el.className=str;
			}
			return el;
		},
		addCls=function(el,c){
			if(el=$(el)){rmCls(el,c).className+=" "+c};
			return el;
		},
		hasCls=function(el,_c){
			var el=$(el),c=(el.className || "").split(/\s+/), l=c.length;
			while(l--){if(c[l]==_c) return true;};
			return false;
		},
		$C=function(dom,c){
			if(typeof(c)!="string") return c;
			var cObject=$(dom || document.body).childNodes,i=0,rsArray=new Array();
			for(;i<cObject.length;i++)if(cObject[i].nodeType==1 && hasCls(cObject[i],c)){rsArray=rsArray.concat(cObject[i]);}
			return rsArray;
		},
		$T=function(dom,t){
			if(typeof(t)!="string") return t;
			return $Dom($(dom || document.body).getElementsByTagName(t));
		},
		$Dom=function(o){
			var i,rsArray=new Array();
			for(i in o){if(o[i] && o[i].nodeType && o[i].nodeType==1){rsArray=rsArray.concat(o[i]);}}
			return rsArray;
		},
		addEvent=function(element,type,handler){
			if (element.addEventListener) {
				element.addEventListener(type, handler, false);
			}else{
				var old=element["on" + type];
				element["on" + type]=function(event){
					if (typeof(old)=="function") old.call(this,event);
					handler.call(this,event);
				}
			}
			return element;
		};
	var util={"$":$,"uA":uA,"msie":msie,"rmCls":rmCls,"addCls":addCls,"hasCls":hasCls,"$C":$C,"$T":$T,"$Dom":$Dom,"addEvent":addEvent};
		
	return{
		util:util,
		_durationInt:10,_intervalTime:10,
		_containerEl:$(_containerEl_),_boxListEl:null,
		_boxCount:0,
		_conWidth:0,_maxBoxWidth:0,_minBoxWidth:0,_theoryWidth:0,_averangeWidth:0,
		_currIndexInt:0,_firstIndexInt:0,
		_onClass:'on',_evenType:'mouseover',
		_unMinBox:{},
		ID:"ID"+Math.random(),
		FRONT:"statePosFront"+this.ID,
		BACK:"statePosBack"+this.ID,
		MID:"statePosMid"+this.ID,
		setDuration:function(n){
			this._durationInt=parseInt(n) || this._durationInt;
			return this;
		},
		setIntervalInt:function(n){
			this._intervalTime=parseInt(n) || this._intervalTime;
			return this;
		},
		setContainer:function(s){
			this._containerEl=$(s || this._containerEl);
			return this;
		},
		setFirst:function(f){
			this._firstIndexInt=parseInt(f) || this._firstIndexInt;
			return this;
		},
		setEvent:function(e){
			this._evenType=e || this._evenType;return this;
		},
		setOnClass:function(s){
			this._onClass=s || this._onClass;return this;
		},
		_getElements:function(s,from){
			if(typeof(s)!="string") return s;
			from=$(from || this._containerEl);
			return s.substr(0,1)=="." ? $C(from,s.substr(1)) : $T(from,s);
		},
		setBoxList:function(s,from){
			this._boxListEl=this._getElements(s || this._boxListEl || "li",from);
			return this;
		},
		getWidth:function(){
			with(this){
				var max=parseInt((_boxListEl && _boxListEl[0])?_boxListEl[0].offsetWidth:0),
				min=Math.floor(max*0.25);
				return [max,min];
			}
		},
		maxWidth:function(w){
			this._maxBoxWidth= parseInt(w) || this._maxBoxWidth;
			if(this._maxBoxWidth<=0) this._maxBoxWidth=this.getWidth()[0];
			return this;
		},
		minWidth:function(w){
			this._minBoxWidth= parseInt(w) || this._minBoxWidth;
			if(this._minBoxWidth<=0) this._minBoxWidth=this.getWidth()[1];
			return this;
		},
		callback:function(fn,state){
			state="callback"+(state || "after");
			this[state]=typeof(fn)=="function" ? fn : false;
			return this;
		},
		extend:function(obj){
			obj=typeof(obj)=="object"? obj : {};
			for(var i in obj){
				this[i]=obj[i];
			}
			return this;
		},
		build:function(con,_first_,du,time,max,min,box,nw){
			this.setContainer(con).setDuration(du).setIntervalInt(time)
				.setBoxList().maxWidth(max).minWidth(min);
			if(typeof(this["callbackbefore"])!="function") this["callbackbefore"]=false;
			if(typeof(this["callbackafter"])!="function") this["callbackafter"]=false;
			if(typeof(this["callbacksliding"])!="function") this["callbacksliding"]=false;
			if(typeof(this["callbackbeforebuild"])=="function") this["callbackbeforebuild"].call(this);
			var i=0;
			with(this){
				_containerEl.style.position="relative";
				_boxCount=_boxListEl.length;//item count
				if(_first_ && _first_>_boxCount) _first_=1;
				setFirst(_first_);
				_theoryWidth=_maxBoxWidth+_minBoxWidth*(_boxCount-1);
				//for _firstIndexInt==0
				// average width of each item.
				_averangeWidth=Math.floor(_theoryWidth/_boxCount);
				
				for(i=0;i<_boxCount;i++){
					var el=_boxListEl[i],pos=i==0?0:i-1;
					el["index"+ID]=i;
					el[FRONT]=_minBoxWidth*i;
					el[BACK]=_minBoxWidth*pos+_maxBoxWidth;
					el[MID]=_averangeWidth*i;
					el.style.position="absolute";
					el.style.zIndex=(i+1)*20;
					
					if(_firstIndexInt>0){
						_currIndexInt=_firstIndexInt-1;
						if(i<=_currIndexInt){
							if(i==_currIndexInt) addCls(el,_onClass);
							el.style.left=el[FRONT]+"px";
						}else{
							el.style.left=el[BACK]+"px";
						}
					}else{
						el.style.left=el[MID]+'px';
					}
					attachElementEvent(i);
				}
				if(typeof(callbackbuild)=="function") callbackbuild.call(this);
			}
			return this;
		},
		attachElementEvent:function(_indexInt_){
			var that=this,
			actionFn=function(event){
				that.timer.call(that,_indexInt_);
			}
			addEvent(this._boxListEl[_indexInt_],this._evenType,actionFn);
		},
		timer:function(_indexInt_){
			with(this){
				if(_currIndexInt==_indexInt_) return;
				if(this["callbackbefore"]) this["callbackbefore"].call(this,_indexInt_);
				rmCls(_boxListEl[_currIndexInt],_onClass);
				_currIndexInt=_indexInt_;
				addCls(_boxListEl[_indexInt_],_onClass);
				var that = this;
				clearInterval(_containerEl["timer"+ID]);
				_containerEl["timer"+ID]=setInterval(function(){that.slide(_indexInt_);},that._intervalTime);		
			}		
		},
		slide:function(_indexInt_){
			var el=this._boxListEl[_indexInt_],
			FRONT=this.FRONT,
			BACK=this.BACK,
			MID=this.MID,
			runTimeLeft=parseInt(el.style.left,'10'),
			currEndLeft=el[FRONT],
			//the one at the right of _indexInt_
			rightEl=this._boxListEl[_indexInt_+1],
			rightElRunTimeLeft=rightEl?parseInt(rightEl.style.left,'10'):0
			rightElEndLeft=rightEl?rightEl[BACK]:0;

			if(runTimeLeft>currEndLeft || rightElRunTimeLeft<rightElEndLeft || this.unFinish(this._unMinBox)!=null){
				if(this["callbacksliding"]) this["callbacksliding"].call(this,_indexInt_); 
				var i=0;
				for(i=0;i<this._boxCount;i++){
					var scrollStep=1,otherBox=this._boxListEl[i],
					otherBoxLeft=parseInt(otherBox.style.left,'10'),
					otherBoxEndLeft=0;
					//the one at the left of last slide
					if(i<=_indexInt_){
						otherBoxEndLeft=otherBox[FRONT];
						if(otherBoxLeft>otherBoxEndLeft){
							scrollStep=Math.floor((otherBoxLeft-otherBoxEndLeft)/this._durationInt);
							scrollStep=(scrollStep>0)?scrollStep:1;
							otherBoxLeft-=scrollStep;
							if(otherBoxLeft<otherBoxEndLeft) otherBoxLeft=otherBoxEndLeft;
							otherBox.style.left=otherBoxLeft+'px';
						}
						this._unMinBox["u"+i] =otherBoxLeft>otherBoxEndLeft ? otherBox : null;
						if(this._unMinBox["u"+i]==null) delete(this._unMinBox["u"+i]);
					//the one at the right of last slide
					}else{
						otherBoxEndLeft=otherBox[BACK];
						if(otherBoxLeft<otherBoxEndLeft){
							scrollStep=Math.floor((otherBoxEndLeft-otherBoxLeft)/this._durationInt);
							scrollStep=(scrollStep>0)?scrollStep:1;
							otherBoxLeft+=scrollStep;
							if(otherBoxLeft>otherBoxEndLeft) otherBoxLeft=otherBoxEndLeft;
							otherBox.style.left=otherBoxLeft+'px';						
						}
						this._unMinBox["u"+i] =otherBoxLeft<otherBoxEndLeft ? otherBox : null;
						if(this._unMinBox["u"+i]==null) delete(this._unMinBox["u"+i]);
					}
				}
			}else{
				clearInterval(this._containerEl["timer"+this.ID]);
				if(this["callbackafter"]) this["callbackafter"].call(this,_indexInt_);
			}
		},
		unFinish:function(u){
			for(var i in u){
				if(u[i]!=null) return [i,u[i]];
			}
			return null;
		},
		hashLength:function(u){
			var i=0;
			for(var j in u){i++}
			return i;
		},
		index:function(o){
			if(typeof(o["index"+this.ID])!="undefined") return o["index"+this.ID];
			var l=this._boxCount;
			while(l--){if(this._boxListEl[l]==o) return l;}
		}
	}
};
