 function Observer(doJob, bindType){
   this.eventType = bindType || "click";
   this.doJob = doJob;
   this.list = [];
}
Observer.prototype = {
	bind: function(obj){
           var o = this;
		   $(obj)[this.eventType](function(){
		      o.carry(this);
			  return false;
		   });
	},
	carry: function(obj){
	   //if(obj == this.list[0]) return;
	   this.list.unshift(obj);
	   this.doJob && this.doJob();
	   if(this.length > 2) this.length = 2;
	}
}
/*read url*/
function ReadUrl(url){
	this.isCheckedLink = false;
	this.xhr = null;
	this.url = url||"";
}
ReadUrl.prototype.readHandler = function(startFunc, endFunc){
	var _this = this;
	if(!this.url || this.url == "http://") return false;
    if(!/^https?:\/\//i.test(this.url)){
	     this.url = "http://" + this.url;
	}
    if(this.url){
    	this.isCheckedLink = true;
    	if(startFunc) startFunc();
    	this.xhr = $.get("/dd/url_catch.ajax", {url: this.url, v: new Date().valueOf()}, function(reply){
    		  _this.xhr = null;
	          reply = reply || _this.url;
	          _this.isCheckedLink = false;
	          if(endFunc) endFunc(reply);
	          _this.reset();
	    });    	
    }
}
ReadUrl.prototype.reset = function(){
    this.xhr = null;
    this.url ="";	
    this.isCheckedLink = false;
}
function ScrollClass(manipObj, iDistance, iSpeed, bDirection){
	 var speeds = {
			slow: 600,
			fast: 200,
			_default: 400
	    }
       this.manipObj = manipObj;
		this.distance = iDistance;
		if(typeof iSpeed == "string")
		    this.speed = speeds[iSpeed] || speeds[_default];
		else
		    this.speed = iSpeed;
		this.direction = bDirection;//true:left->right,false: right->left
		this.timer  = 0;
		this.startScrollLeft = this.manipObj.scrollLeft;
		this.finished = true;
}
ScrollClass.prototype = {
       run: function(){
		      if(!this.finished) return;
		      if(this.canScroll()){
			             this.finished = false;
					     var sTime = new Date().valueOf();
						 var _this = this;
						 var obj = this.manipObj;
						 this.startScrollLeft = obj.scrollLeft ;
					     this.timer = setInterval(function(){
						      var p = (new Date().valueOf() - sTime)/_this.speed;
							  if(p >= 1){
							      clearInterval(_this.timer);
                                  _this.gotoEnd();
							  }else{
							      if(_this.direction)
								      obj.scrollLeft = _this.startScrollLeft +  _this.distance*(-Math.cos(p*Math.PI)/2 + 0.5);
								  else
								     obj.scrollLeft = _this.startScrollLeft - _this.distance*(-Math.cos(p*Math.PI)/2 + 0.5);
							  }
						 }, 16);
			  }
		},
		stop: function(){
		       if(this.timer){
			        clearInterval(this.timer);
					this.gotoEnd();
			   }
		},
		converselyRun: function(){
		     this.stop();
			 this.direction = !this.direction;
		},
		gotoEnd: function(){
		       var obj = this.manipObj;
			   if(this.direction) 
					  obj.scrollLeft = this.startScrollLeft +  this.distance;
			   else{
					  if(!this.direction && this.startScrollLeft -  this.distance < 0)
					       obj.scrollLeft = 0;
					  else
					      obj.scrollLeft = this.startScrollLeft -  this.distance;		
			   }
			   this.finished = true;
		},
		canScroll: function(){
		    var obj = this.manipObj;
			if(this.direction && obj.offsetWidth + obj.scrollLeft >= obj.scrollWidth) {
			     return false;
			}
			 if(!this.direction &&  obj.scrollLeft <= 0){
			     return false;
		     }
			 return true;
		}
}
function DataStack(config){
	config = config || {};
	this.fields = config.fields || [];
	this.data = config.records || [];
	this.pointer = 0;
	this.refresh();
}
DataStack.prototype = {
	refresh: function(){
	   this.count = this.data.length;	
    },
	go: function(idx){
    	if(idx >= 0 && idx <= this.count - 1 && this.pointer != idx){
    		this.pointer = idx;
    		this.onPointerChange && this.onPointerChange();
    	}
    },
    pos: function(fieldName, val){
    	for(var i = 0, ret = -1, l = this.count; i < l; i++){
    		if(this.data[i][fieldName] == val){
    			ret = i;
    			break;
    		}
    	}
    	if(ret != -1) this.go(ret);
    	return ret;
    },
    load: function(data){
    	if(Object.prototype.toString.call(data) !== "[object Array]") return;
    	this.data = data;
    	this.refresh();
    	this.onLoad && this.onLoad();
    },
    read: function(s){
    	if(this.count == 0) return null;
    	if(typeof s == "string") return this.data[this.pointer][s];
    	if(typeof s == "number") return this.data[s];
    	return this.data[this.pointer];
    },
    append: function(rd){
    	this.data.push(rd);
    	this.refresh();
    	this.onAppend && this.onAppend(rd);
    },
    prepend: function(rd){
    	this.data.unshift(rd);
    	this.refresh();
    	this.onPrepend && this.onPrepend(rd);
    },
    insertBefore: function(rd, idx){
    	if(idx !== 0) idx = idx || this.pointer;
    	if(idx < 0 || idx > this.count-1) return;
    	this.data.splice(idx, 0, rd);
    	this.refresh();
    	this.onInsertBefore && this.onInsertBefore(rd);
    },
    insertAfter: function(rd, idx){
    	if(idx !== 0) idx = idx || this.pointer;
    	if(idx < 0 || idx > this.count-1) return;
    	this.data.splice(idx+1, 0, rd);
    	this.refresh();
    	this.onInsertAfter && this.onInsertAfter(rd);
    },
    del: function(idx){
    	if(idx !== 0) idx = idx || this.pointer;
    	if(idx < 0 || idx > this.count-1) return;
    	this.data.splice(idx, 1);
    	this.refresh();
    	if(idx == this.count - 1) this.pointer = 0; 
    	this.onDel && this.onDel();
    },
    edit: function(fieldName, val){
    	this.data[this.pointer][fieldName] = val;
    	this.onEdit && this.onEdit(fieldName, val);
    },
    search: function(fieldName, keyword, isfromHd){
    	var ret = [];
		for(var i = (isfromHd ? 0 : this.pointer), l = this.count; i < l; i++){
		    this.go(i);
			if(this.read(fieldName).toString().toLowerCase().indexOf(keyword.toString()) > -1)
				ret.push(i);
		}
    	return ret;
    },
    sortBy: function(fieldName, way){
    	way = way || "asc";
    	switch(way){
    	   case "asc": 
    		   this.data.sort(function(a, b){
    			   return a[fieldName] - b[fieldName];
    		   });
    	   break;
    	   case "desc": 
    		   this.data.sort(function(a, b){
    			   return b[fieldName] - a[fieldName];
    		   });
    	    break;    	    
    	}
    }
};