StepTimingFunction = {
	timingFunctionForStepCount: function(stepCount) {
		return function(pos){
			return ((pos * (stepCount-1)) >> 0) / ((stepCount-1));
		}
	}
};

/*
	Delegate methods:
		counterDidStop(this),
		counterDidStart(this),
		counterDidReachValue(this, this._currentCount),
		
*/


DownloadCounter = Class.create();
Object.extend(DownloadCounter.prototype, {


	initialize: function(url) {
		this._url = url;
		this.loadData();
		this._isCounting = true;
    },
	setIsCounting: function(value) {
		this._isCounting = value;
	},
	stop: function() {
		if(this._isCounting) {
			if(this._drawTimeout) {
				window.clearTimeout(this._drawTimeout);
			}
			this.setIsCounting(false);
			if(this._delegate && typeof this._delegate.counterDidStop === "function") {
				this._delegate.counterDidStop(this);
			}
		}
	},
	start: function() {
		if(!this._isCounting) {
			this.loadData();
			this.setIsCounting(true);
			if(this._delegate && typeof this._delegate.counterDidStart === "function") {
				this._delegate.counterDidStart(this);
			}
		}
	},
	isCounting: function() {
		return this._isCounting;
	},
	_delegate: null,
	setDelegate: function(value) {
		this._delegate = value;
	},
	delegate: function() {
		return this._delegate;
	},
	loadData: function() {
		if(this._nextUpdateTimeout) {
			window.clearTimeout(this._nextUpdateTimeout);
			this._nextUpdateTimeout = null;
		}
		
		new Ajax.Request((this._url+"?r="+Math.random()), {
			method:'get',
			onSuccess: this.dataRequestDidFinishLoading.bind(this)
		});
	},
	dataRequestDidFinishLoading: function(result) {
		var responseArray = result.responseText.split("|"), dateParts, time, year, month, day, referenceDate, now, ellapsed, nextUpdateDate, timeToNextUpdate, referenceDateTime, referenceCount, serverDate/*, localServerBasedReferenceTime*/;
		
		//The Date header is unfortunately unreliable as it is back in time several minutes
		localServerBasedReferenceTime = Date.parse(result.getResponseHeader("Date"));
		if(responseArray.length === 3) {
			dateParts = responseArray[0].split(" ");
			time =  dateParts[1];
			date = dateParts[0].split("-");
			this.setRate(parseInt(responseArray[2])/3600000);
			
			day = date[0];
			month = date[1];
			year = date[2];
			
			referenceDateTime = Date.parse(month+" "+day+", "+year+" "+time+" GMT-0700");
			//referenceDateTime = referenceDate.getTime();
			//1 hour from referenceDate
			nextUpdateDate = new Date(referenceDateTime+3600000) 
			timeToNextUpdate = nextUpdateDate.getTime() - referenceDateTime + 1000;//Adding 10seconds more to be sure to catch an update;
			
			//Setup timeout to trigger next update
			this._nextUpdateTimeout = setTimeout(this.loadData.bind(this),timeToNextUpdate);
			
			if(typeof localServerBasedReferenceTime === "number") {
				this._lastReferenceTime = localServerBasedReferenceTime;
			}
			else {
				now = new Date();
				this._lastReferenceTime = now.getTime();
			}
			ellapsed = this._lastReferenceTime - referenceDateTime;
			
			referenceCount = Math.floor(parseInt(responseArray[1]) + ellapsed*(this._rate));
			
			this.setCurrentCount(referenceCount);
			
			this.setNeedsDisplayIfNeeded();
						
		}
	},
	setNeedsDisplayIfNeeded: function() {
		if(!this._drawTimeout) {
			this._drawTimeout = setTimeout(this.draw.bind(this), this._drawRefreshRate); //pledit
		}
	},
	setElement: function(value) {
		this._element = value;
		
		var digitGroupSeparators = this._element.getElementsByClassName("digitGroupSeparator");
		if(digitGroupSeparators.length > 0) {
			var template = digitGroupSeparators[0];
			this._element.removeChild(template);
			this.setDigitGroupSeparatorTemplateElement(template);
		}
		this._element.empty();
		this.createDigitElementsIfNeeded();
		this.setNeedsDisplayIfNeeded();
		
	},
	setDigitGroupSeparatorTemplateElement: function(value) {
		this._digitGroupSeparatorTemplateElement = value;
	},
	_currentCount: 0,
	setCurrentCount: function(value) {
		if(value !== this._currentCount) {
			this._currentCount = value;
			this.createDigitElementsIfNeeded();
		}
	},
	digitTemplateElement: function() {
		if(!this._digitTemplateElement) {
			this._digitTemplateElement = document.createElement("span");
			$(this._digitTemplateElement).addClassName("digit");
			var digitText = document.createElement("div"), digitImageContainer = document.createElement("div"), digitImageStrip = document.createElement("div");
			$(digitText).addClassName("digitText");
			$(digitImageContainer).addClassName("digitImage");
			this._digitTemplateElement.appendChild(digitText);
			this._digitTemplateElement.appendChild(digitImageContainer);
			$(digitImageStrip).addClassName("digitImageElement");
			digitImageContainer.appendChild(digitImageStrip.cloneNode(true));
			digitImageContainer.appendChild(digitImageStrip);
		}
		return this._digitTemplateElement;
	},
	createDigitElementsIfNeeded: function() {
		if(this._element && (!this._digitElements || this._digitElements.length !== this._currentCount.toString().length)) {
			this._element.empty();
			this._createDigitElements();
		}
	},
	_createDigitElements: function() {
		if(!this._digitElements) {
		this._digitElements = [];
		}
		var i=0, 
			countI=(this._maxCount && this._currentCount >= this._maxCount) ? this._maxCount.toString().length : this._currentCount.toString().length, 
			documentFragment = document.createDocumentFragment(), 
			iDigit, digitTemplate = this.digitTemplateElement(), 
			digitGroupSeparator = this._digitGroupSeparatorTemplateElement,
			currentCountString = (this._maxCount && this._currentCount >= this._maxCount) ? String(this._maxCount) : String(this._currentCount),
			iDigitValue;

			if(!digitGroupSeparator) {
				digitGroupSeparator = document.createElement("span");
				$(digitGroupSeparator).addClassName("digitGroupSeparator");
			}

		for(i=0+this._digitElements.length;i<countI;i++) {
			iDigit = digitTemplate.cloneNode(true);
			iDigitValue = parseInt(currentCountString.charAt(countI-(i+1)));
			iDigit.lastChild.style.top = "-"+(iDigitValue*(this._digitImageAnimationCount*this._digitImageHeight))+"px";
			//Stored in reverse visual order
			this._digitElements[i] = iDigit;
			if(i>0 && ((i) % 3 == 0)) {
				documentFragment.insertBefore(digitGroupSeparator.cloneNode(true),documentFragment.firstChild);
			}
			documentFragment.insertBefore(iDigit,documentFragment.firstChild);
		}
		this._element.insertBefore(documentFragment,this._element.firstChild);
	},
	currentCount: function() {
		return this._currentCount;
	},
	setRate: function(value) {
		this._rate = value;
	},
 	rate: function() {
		return this._rate;
	},
	_drawRefreshRate: 50,//In ms
	_digitImageHeight: 38,
	setDigitImageHeight: function(value) {
		this._digitImageHeight = value;
	},
	_digitImageAnimationCount: 6,
	setDigitImageAnimationCount: function(value) {
		this._digitImageAnimationCount = value;
	},
	_maxCount: false,
	setMaxCount: function(value) {
		this._maxCount = value;
	},
	draw: function() {
		window.clearTimeout(this._drawTimeout);
		this._drawTimeout = null;
		var ellapsed = this._drawRefreshRate, 
			currentCountString, 
			countI, 
			countILess1, 
			i, 
			iDigitElement, 
			iDigit, 
			iPreviousDigit, 
			iDigitPosition, 
			iPreviousDigitPosition, 
			iPreviousDigitPositionPx, 
			previousCountString,
			digitAnimatedHeight = this._digitImageHeight*this._digitImageAnimationCount,
			iDigitSteps,
			digitElements = this._digitElements,
			effect;
			
			
		if(this._element) {
			
			previousCountString = String(this._currentCount);
			this._currentCount = this._currentCount + Math.floor(this._rate*ellapsed);
			
			if(this._delegate && typeof this._delegate.counterDidReachValue === "function") {
				this._delegate.counterDidReachValue(this,this._currentCount);
			}
			
			if(this._maxCount && this._currentCount >= this._maxCount) {
				this._isCounting = false;
			}
			
			if(!this._isCounting) return;
			
			currentCountString = (this._maxCount && this._currentCount >= this._maxCount) ? String(this._maxCount) : String(this._currentCount);
			countI = currentCountString.length;
			countILess1 = countI-1;
			for(i=countILess1;i>=0;i--) {
				iDigit = parseInt(currentCountString.charAt(i));
				iPreviousDigit = parseInt(previousCountString.charAt(i));
				
				//Build animation to go from iPreviousDigit to iDigit
				if(iDigit !== iPreviousDigit) {
					
					if(!((countILess1-i) < digitElements.length )) {
						this._createDigitElements();
					}
					
					iDigitElement = digitElements[countILess1-i].lastChild;
					if(iDigitElement.___animating !== true) {
					
						//3 -> 9
						iPreviousDigitPosition = iPreviousDigit*digitAnimatedHeight;
						if(iDigit > iPreviousDigit) {
							iDigitPosition = iDigit*digitAnimatedHeight;
						}
						//5 -> 1
						else {
							iDigitPosition = (iPreviousDigit+(10-iPreviousDigit)+iDigit)*digitAnimatedHeight;
						}
					
						if(iDigitElement.style.top !== (iPreviousDigitPositionPx = "-"+iPreviousDigitPosition+"px")) {
							iDigitElement.style.top = iPreviousDigitPositionPx;
						}
						iDigitSteps = 1+((iDigitPosition-iPreviousDigitPosition)/this._digitImageHeight);
										
					
							iDigitElement.___animating = true;
							effect = new Effect.Move(iDigitElement, {x:0,y:(-1*iDigitPosition),
								duration: 0.4,
								mode: 'absolute',
							    transition: StepTimingFunction.timingFunctionForStepCount(iDigitSteps)
							});
							//effect.superFinish = effect.finish;
							effect.__element = iDigitElement;
							//Added an umload handler to workaround a bug in Safari 4.0.4 Leopard where this.__element.___animating = false; 
							//would never been executed when leaving the page
							//Leading a non-functionning counter when using the back button 
							effect.finish = function(event) {
								if(window.removeEventListener) {
									window.removeEventListener("unload",arguments.callee,false);
								}
								this.__element.___animating = false;
							};
							
							if(window.addEventListener) {
								window.addEventListener("unload",effect.finish,false);
							}
							
						
					}
				}
			}
		}
		this._lastReferenceTime = (this._lastReferenceTime+ellapsed);
		this.setNeedsDisplayIfNeeded();
	}
   
        
});


