(function($){
	$.snowfall = function(element, options){
		var	defaults = {
				flakeCount : 35,
				flakeColor : '#ffffff',
				flakeIndex: 999999,
				minSize : 1,
				maxSize : 3,
				minSpeed : 2,
				maxSpeed : 3,
				flakeImg : ''
			},
			options = $.extend(defaults, options),
			random = function random(min, max){
				return Math.round(min + Math.random()*(max-min)); 
			};
			
			$(element).data("snowfall", this);			
			
			options.flakeCount = parseInt(options.flakeCount);
			options.minSize = parseInt(options.minSize);
			options.maxSize = parseInt(options.maxSize);
			options.minSpeed = parseInt(options.minSpeed);
			options.maxSpeed = parseInt(options.maxSpeed);
			
			// Snow flake object
			function Flake(_x, _y, _size, _speed, _id, html_tag)
			{				
				// Flake properties
				this.id = _id; 
				this.x  = _x;
				this.y  = _y;
				this.size = _size;
				this.speed = _speed;
				this.step = 0,
				this.stepSize = random(1,10) / 100;
				
				var flakeMarkup = $(document.createElement("span")).attr({'class': 'snowfall-flakes', 'id' : 'flake-' + this.id})
				.css({'color' : options.flakeColor, 'position' : 'absolute', 'top' : this.y, 'left' : this.x, 'fontSize' : this.size, 'zIndex' : options.flakeIndex}).html(html_tag);
				
				if($(element).get(0).tagName === $(document).get(0).tagName){
					$('body').append(flakeMarkup);
					element = $('body');
				}else{
					$(element).append(flakeMarkup);
				}
				
				this.element = document.getElementById('flake-' + this.id);
				
				// Update function, used to update the snow flakes, and checks current snowflake against bounds
				this.update = function(){
					this.y += this.speed;
					
					if(this.y > (elHeight) - 6){
						this.reset();
					}
					
					this.element.style.top = this.y + 'px';
					this.element.style.left = this.x + 'px';
					
					this.step += this.stepSize;
					this.x += Math.cos(this.step);
					
					if(this.x > (elWidth) - 6 || this.x < 6){
						this.reset();
					}
				}
				
				// Resets the snowflake once it reaches one of the bounds set
				this.reset = function(){
					this.y = 0;
					this.x = random(0, elWidth);
					this.stepSize = random(1,10) / 100;
					this.size = random((options.minSize * 100), (options.maxSize * 100)) / 100;
					this.speed = random(options.minSpeed, options.maxSpeed);
				}
			}
		
			// Private vars
			var flakes = [],
				flakeId = 0,
				i = 0,
				elHeight = $(element).height(),
				elWidth = $(element).width();
			
			// Bind the window resize event so we can get the innerHeight again
			$(window).bind("resize", function(){  
				elHeight = $(element).height();
				elWidth = $(element).width();
			});			

			// initialize the flakes
			var html_tag = '&#8226;';	
			if(options.flakeImg != '')
			{
				var all_img = options.flakeImg;
				var img_split = all_img.split(',');
				var img_count = img_split.length-1;
			}
			var j = 0;
			
			for(i = 0; i < options.flakeCount; i+=1)
			{
				
				if(options.flakeImg != '')
				{
					html_tag = img_split[j];
					if(j == img_count)
						j = 0;
					else
						j+=1;					
				}
				
				flakeId = flakes.length;
				flakes.push(new Flake(random(0,elWidth), random(0, elHeight), random((options.minSize * 100), (options.maxSize * 100)) / 100, random(options.minSpeed, options.maxSpeed), flakeId, html_tag));
			}
		
			// this controls flow of the updating snow
			function snow(){
				for( i = 0; i < flakes.length; i += 1){
					flakes[i].update();
				}
				
				setTimeout(function(){snow()}, 30);
			}
			
			snow();
		
		// Public Methods
		
		// clears the snowflakes
		this.clear = function(){
						$(element).children('.snowfall-flakes').remove();
						flakes = [];
					};
	};
	
	// Initialize the options and the plugin
	$.fn.snowfall = function(options){
		if(typeof(options) == "object" || options == undefined){		
				 return this.each(function(i){
					(new $.snowfall(this, options)); 
				});	
		}else if (typeof(options) == "string") {
			return this.each(function(i){
				var snow = $(this).data('snowfall');
				if(snow){
					snow.clear();
				}
			});
		}
	};
})(jQuery);
