/**
 * jQuery Plugin Flipblock
 *
 * @author Keithamus
 *
 * Licensed under the ___ License
 *
 * Usage:
 *
 * $('#flipclock').flipclock({
	*		number: i, //Defaults to 0
	* 	something: this,
	* 	onFlip: function() {
	* 		//do Something
	* 	}
	* });
	*
	*
 */
(function($) {

	var PROP_NAME = 'flipclock';

	function FlipClock()
	{
		this._defaults = {
			animateIntro: true,
			animatedFrames: 5,
			autoStart: true,
			digitSelector : 'li',
			frameDelay: 25,
			frameHeight: null,
			imageHeight: null,
			maxDigits: 10,
			setFromInnerHTML: true,
			speed : 1000,
			timerFinished: null,
			type: 'increase'
		};
	}

	$.extend(FlipClock.prototype,
	{
		markerClassName: 'isFlipClock',

		setDefaults: function(settings) {
			$.extend(this._defaults, settings || {});
			return this;
		},

		getOptions: function(e, settings, value)
		{
			//Are we starting with any extra data?
			if(typeof settings == 'string') {
				var name = settings;
				settings = {};
				settings[name] = value;
   }
			inst = $.data(e[0], PROP_NAME);
			inst.settings = $.extend(inst.settings, settings || {});
			return inst.settings;
		},

		setVar: function(e, name, value)
		{
			inst = $.data(e[0], PROP_NAME) || {};
			inst[name] = value;
			$.data(e[0], PROP_NAME, inst);
		},

		getVar: function(e, name)
		{
			return $.data(e[0], PROP_NAME)[name] || null;
		},

		animateFlip: function(e, options, multiplier, down, i)
		{
			//Is I empty? Is multiplier empty? Set them to 0 then
			if(i == null) { i = 0; }
			if(multiplier == null) { multiplier = 1; }

			//Get the background position numbers
			if( $.browser.msie ){
				background = [ e.css('background-position-x'), e.css('background-position-y') ];
			} else {
				background = e.css('background-position').split(' ');
			}
			
			//Change our background position to the next frame
			background[1] = down?
				(parseInt(background[1]) + options.frameHeight)+ 'px':
				(parseInt(background[1]) - options.frameHeight)+ 'px';

			if(down && parseInt(background[1])==options.frameHeight)
			{
				background[1] = '-'+ (options.imageHeight - options.frameHeight) + 'px';
			}

			//Check to see if our position is out of range
			if(
			//Is the background the at the lowest position it can be?
			parseInt(background[1]) <= ('-'+ options.imageHeight) && !down ||
			//Or is the background somehow above the top of the image
			parseInt(background[1]) > 0 && !down)
			{
				background[1] = '0px';
			}

			//Join the background string, to apply to our element.
			background = typeof background == 'object'?background.join(' '):background;

			//Set out CSS.
			e.css('background-position',background);

			//Do we still have more frames to go through?
			if(i< ((options.animatedFrames * multiplier) + (multiplier - 1)) )
			{
				parentThis = this;
				//Lets set a timeout of our framedelay to animate the next frame.
				setTimeout(function()
				{
					parentThis.animateFlip(e, options, multiplier, down, ++i);
				}, options.frameDelay);
			}

			if( $.browser.msie ){
				bg = [ e.css('background-position-x'), e.css('background-position-y') ];
			} else {
				bg = e.css('background-position').split(' ');
			}

			//If we're at the end of our digit run for this li, then we should
			// incriment the nearest left digit.
			if(parseInt(bg[1]) ==
				'-'+ (options.imageHeight - (options.frameHeight *
				Math.round(options.animatedFrames / 2))) && !down ||
				down && parseInt(bg[1]) ==
				'-'+ (options.imageHeight - options.frameHeight))
			{
				this.incrimentPrevious(e, down, options);
			}

		},

		incrimentPrevious: function(e, down, options)
		{
			preve = e.prevAll(options.digitSelector).first();
			if(preve.length > 0) {
				i = $.data(preve[0], PROP_NAME);
				new_i = down?--i:++i;
				new_i = i>=0 && i<=10?new_i:9;
				$.data(preve[0], PROP_NAME, new_i);

				tmpmax = !options.maxDigits.length?options.maxDigits:
					options.maxDigits[preve.index('#'+ options.thisId+ ' '+ options.digitSelector)];

				if(down && tmpmax<10 && new_i>tmpmax)
				{
					new_i = tmpmax;
					new_i = new_i<0?0:new_i-1;
					$.data(preve[0], PROP_NAME, new_i);
					this.animateFlip(preve, options, (10 - new_i), down);
				}
				else if(tmpmax<10 && new_i>=tmpmax)
				{
					$.data(preve[0], PROP_NAME, 0);
					multi = 10 - (new_i-1);
					this.animateFlip(preve, options, multi, down);
				}
				else
				{
					this.animateFlip(preve, options, 1, down);
				}
			}
			else if(typeof options.timerFinished == 'function')
			{options.timerFinished();}
		},

		_initFlipClock: function(e, settings, value)
		{
			if(this.getVar(e, 'started')==true) {return;}
			this.setVar(e, 'started', true);
			options = this.getOptions(e, settings, value);
			parentThis = this;
			if(options.setDigits) {
				var digitarray = [];
				for(i=0;i<options.setDigits.length;++i)
				{
					digitarray[i] = options.setDigits[i];
				}
			}
			e.children(options.digitSelector).each(function(i)
			{
				number = (digitarray && digitarray[i])?digitarray[i]:this.innerHTML;
				if(parseInt(number) > 0 && parseInt(number) < 10)
				{
					if(options.animateIntro) {
						parentThis.animateFlip($(this), options, number);
					}
					else
					{
						$(this).css('background-position', '0 '+
							'-'+ ((options.frameHeight * (options.animatedFrames + 1)) * number) + 'px');
					}
					$.data($(this)[0], PROP_NAME, number);
				}
				else
				{
					$.data($(this)[0], PROP_NAME, 0);
				}
			});
			//this._startFlipClock(e);
		},

		_increaseFlipClock: function(e, settings, value)
		{
			if(!e.length) e = $(e);
			multiplier = parseInt(settings)>0?parseInt(settings):1;
			options = this.getOptions(e, settings, value);
			el = $(e).children(options.digitSelector).last();
			i = $.data(el[0], PROP_NAME);
			$.data(el[0], PROP_NAME, i>0 && i<10?i+1:1);

			//Are we increasing over our maximum?
			tmpmax = !options.maxDigits.length?options.maxDigits:
					options.maxDigits[el.index('#'+ options.thisId+ ' '+ options.digitSelector)];

			if(tmpmax<10 && (i+1)>=tmpmax)
			{
				$.data(el[0], PROP_NAME, 0);
				multi = 10 - (i+1);
				this.animateFlip(el, options, multi);
			}

			//Animate our element
			this.animateFlip(el, options, multiplier);
		},

		_decreaseFlipClock: function(e, settings, value)
		{
			if(!e.length) e = $(e);
			multiplier = parseInt(settings)>0?parseInt(settings):1;
			options = this.getOptions(e, settings, value);
			el = $(e).children(options.digitSelector).last();
			i = $.data(el[0], PROP_NAME);
			$.data(el[0], PROP_NAME, i>0 && i<=10?--i:9);
			//Animate our element
			this.animateFlip(el, options, multiplier, true);
		},

		_startFlipClock: function(e, settings, value)
			{
				if(!e.length) e = $(e);
				options = this.getOptions(e, settings, value);

				parentThis = this;
				this.setVar(e, 'flipTimer', setTimeout(function(){
					options = parentThis.getOptions(e);
					type = '_'+ options.type+ 'FlipClock';
					parentThis[type](e);
					parentThis._startFlipClock(e);
				}, options.speed));
		},

		_stopFlipClock: function(e) {
			if(!e.length) e = $(e);
			clearTimeout(this.getVar(e, 'flipTimer'));
		},

		_attachFlipClock: function(e, settings) {
			if(!e.length) e = $(e);
			if(e.hasClass(this.markerClassName)) {return;}
			e.addClass(this.markerClassName);

			options = $.extend({}, this._defaults);

			options = $.extend(options, settings || {});

			//Set some good defaults for certain options, based on the data we've been given
			if(options.frameHeight == null)
			{
				options.frameHeight =
					e.children(options.digitSelector).first().height();
			}
			if(options.imageHeight == null)
			{
				options.imageHeight =
					(options.frameHeight+ (options.frameHeight * options.animatedFrames)) * 10;
			}
			if((options.frameRate * options.animatedFrames)>options.speed)
			{
				options.speed = (options.frameRate * options.animatedFrames);
			}

			options.thisId = e.attr('id');

			this.setVar(e, 'settings', options);

			if(options.autoStart == true)
			{
				this._initFlipClock(e, settings);
			}
		},



	});

	$.fn.flipclock = function(options) {
		var otherArgs = Array.prototype.slice.call(arguments, 1);

		return this.each(function()
		{
			if (typeof options == 'string')
			{
				if($(this).hasClass($.flipclock.markerClassName)) {
					$.flipclock['_' + options + 'FlipClock'].
						apply($.flipclock, [this].concat(otherArgs));
				}
			}
			else
			{
				$.flipclock._attachFlipClock(this, options || {});}
		});
	};

	$.flipclock = new FlipClock();

	return jQuery;

})(jQuery);
