(function($, undefined) {
	
	var tween = {
		target: 15
	};
	
	var tweener = {
		tweens: [],
		addTween: function(o, tween) {
			//console.log('  addTween start', o.element);
			var tf;
			
			tf = tween.target;
			
			if (!o._tween && tf == o.currentFrame) return;
			
			tween.targetFrame = tf;
			tween.startTime = new Date();
			tween.startFrame = o.currentFrame;
			if (!tween.easing) {
				tween.easing = 'easeInOutExpo';
			}
			tween.easingFn = $.easing[tween.easing];
			o._tween = tween;
			if (tweener.tweens.indexOf(o) == -1) tweener.tweens.push(o);
			
			setTimeout(tweener.startTweening, 0);
		},
		startTweening: function() {
			var tweens = tweener.tweens;
			for (var i = 0 ; i < tweens.length ; i++) {
				var o = tweens[i];
				var tw = o._tween;
				var tf = tw.targetFrame;
				var nf;
				var efn = tw.easingFn;
				var now = new Date();
				var timer = now - tw.startTime;
				if (timer >= tw.duration) {
					nf = tf;
					if (tw.mode == 'oneshot') {
						tweens.splice(i, 1);
						delete o._tween;
					} else if (tw.mode == 'extended') {
						var extend = tw.extend;
						tw.mode = extend.mode;
						tw.duration = extend.duration;
						tw.targetFrame = extend.target;
						tw.startFrame = nf;
						tw.startTime = now;
					} else if (tw.mode == 'yoyo') {
						tw.targetFrame = tw.startFrame;
						tw.startFrame = tf;
						tw.startTime = now;
					}
				} else {
					nf = efn(null, timer, tw.startFrame, tf - tw.startFrame, tw.duration);
				}
				nf = Math.round(nf);
				o.setFrame(nf);
			}
			if (tweens.length > 0) {
				setTimeout(tweener.startTweening, 0);
			}
		}
	};
	
	$.widget('ui.pmSprite', {
		
		widgetEventPrefix: "pmsprite",
		
		options: {
			imageUrl: null,
			imageWidth: 15,
			imageHeight: 15,
			frameCount: 15,
			frameDirection: 'horizontal',
			horizontalOffset: 0,
			verticalOffset: 0,
			defaultDuration: 1000,
			defaultFrame: 0
		}, 
		
		_create: function() {
			var el = this.element;
			el.width(this.options.imageWidth);
			el.height(this.options.imageHeight);
			el.css('background-image', "url('"+this.options.imageUrl+"')");
			this.currentFrame = this.options.defaultFrame;
			if (this.options.frameDirection == 'horizontal') {
				this._setFrame = this._setFrameH;
			} else if (this.options.frameDirection == 'vertical') {
				this._setFrame = this._setFrameV;
			}
			//el.css('background-position', this.options.horizontalOffset+'px ' + this.options.verticalOffset+'px');
			this._setFrame(this.currentFrame);
		},
		
		setFrame: function(f) {
			f = Math.abs(f);
			var d = this.options.frameCount - 1;
			f = f % (2*d);
			if (f > d) {
				f = (2*d - f) % this.options.frameCount;
			}
			this._setFrame(f);
			this.currentFrame = f;
			//console.log(f);
		},
		
		_setFrame: function(f) {},
		
		_setFrameH: function(f) {
			this.element.css('background-position', (this.options.horizontalOffset-this.options.imageWidth*f) + 'px ' + this.options.verticalOffset + 'px');
		},
		
		_setFrameV: function(f) {
			this.element.css('background-position', this.options.horizontalOffset + 'px ' + (this.options.verticalOffset-this.options.imageHeight*f) + 'px');
		},
		
		playToPosition: function(p, duration, easing) {
			if (duration === undefined) duration = this.options.defaultDuration;
			var tf = Math.round(p * (this.options.frameCount-1));
			this.playToFrame(tf, duration, easing);
		},
		
		playToFrame: function(f, duration, easing, then) {
			if (duration === undefined) duration = this.options.defaultDuration;
			var opts = {target:f, duration:duration, easing:easing};
			if (then) {
				var spl = then.split(':');
				var cmd = spl[0];
				var frm = spl[1];
				var dur = spl[2];
				opts.mode = 'extended';
				opts.extend = {mode:cmd, target:frm, duration:dur};
			} else {
				opts.mode = 'oneshot';
			}
			tweener.addTween(this, opts);
		},
		
		setPosition: function(p) {
			var tf = Math.round(p * (this.options.frameCount-1));
			this.setFrame(tf);
		},
		
		getPosition: function() {
			return this.currentFrame / (this.options.frameCount - 1);
		},
		
		toggle: function(duration, easing) {
			if (this.currentFrame != 0) {
				this.playToFrame(0, duration, easing);
			} else {
				this.playToFrame(this.options.frameCount-1, duration, easing);
			}
		}
	});
})( jQuery );
