(function( parent ) {
	'use strict';

	/** parent object, set in the end of the selfcalling function **/
	var parent = parent || window,
		/** instance of File Reader **/
		reader,
		readFile,
		/**
		*	Removes class from element
		*	@param htmlObject	target element
		*	@param	string	"class to be removed"
		**/
		removeClass	= function( el, value ) {
			if ( !el.className ) return false;
			var classes = el.className.split(' '),
				ret = [];
			for( var i = 0, l = classes.length; i < l; ++i )
				if( classes[i] != value )
					ret.push( classes[ i ] );
			el.className = ret.join(' ');
		};
		
	if( !window.FileReader || !document.addEventListener ) {
		throw( "File API not supported" );
		readFile = function(){ throw( "File API not supported" ); };
	}
	else {
		reader = new FileReader();
		readFile = function ( file, callback, method ) {
			/** Error handler (throws error at the console) **/
			reader.onerror = function( e ) {
				var message,
					lut = [ "File not found.", "File coulnot be opened",  
						"File couldnot be uploaded", "Couldnot read File", "File too large" ];
				// http://www.w3.org/TR/FileAPI/#ErrorDescriptions
				throw( lut[ ( e.target.error.code - 1 ) ] );
			},
			/** Success, calling the callback **/
			reader.onloadend = function( e ) {
				callback && callback( e.target.result, file.name );
				reader.onloadend = null;
			};
			
			// the method is specified in the beginning of the file
			reader[ method ]( file );
			return false;
		};
	}
	
	/**
	*	Drag n Drop Files module
	*	@param	HTMLElement, could be the Body
	*	@param	DOMElement/String, if a string is specified then a div will be built and appended to the body
	*			with that String as its id. If a dom element is passed, that will be used instead. This object
	*			acts as an overlay and the file should be droped to this object. If this object is null, then the first argument
	*			will be used as the overlay.
	*	@param	Function,	will be called with the file data, and the filename as its arguments
	*	@param	String,	possible values "text, binarytext, arrabuffer" decides how the file will be read
	*			if let null, defaults to text
	*	@param	String,	class name to be added to the overlay (default is '__fadingIn')
	**/
	parent.dragNDrop = function( body, overlay_id, callback, method, _clss ) {
		var win = window;
		// check to see if we are using a mobile device - no need for dragNdrop in devices
		// that do not support it somehow yet
		if( ( 'ontouchstart' in window ) )
			return "mobile";
		
			/** JS Object, used to define the file-reading method **/
		var method_lut = {
				'text'		 :	'readAsText',
				'binary'	 :	'readAsBinaryText',
				'arrayBuffer':	'readAsArrayBuffer'
			},
			/** class added/removed from overlay object **/
			clss = _clss ? _clss : "__fadingIn",
			method = method ? method_lut[ method ] : 'readAsText',
			/** how many events cast (dragenter/dragleave) **/
			entered = 0,
			/** 
			* DOMElement sink for the drag events 
			* if left unspecified then the body inherits the role
			**/
			overlay = !!overlay_id ? overlay_id : body,
			/**
			*	(void) if the overlay_id specified is a string, then a div with that id is built
			*	and appended to the body. Else the default is used
			**/
			_overlayBuilder = function() {
				if( typeof overlay_id === "string" )
				{
					var tmp = document.createElement( 'div' );
					overlay = document.createElement( 'div' );
					overlay.id = overlay_id;
					
					tmp.innerHTML = "Drag n drop Files!";
					overlay.appendChild( tmp );

					body.appendChild( overlay );
					tmp = null;
				}
			},
			/**
			*	JS Object
			*	The events Object contains various functions that control 
			*	the behavior of the events fired
			**/
			events = {
				/**
				*	(void) Prevents default action and bubbling up
				**/
				silencer	:	function( e ) {
					e.preventDefault();
					e.stopPropagation()
				},
				
				/**
				*	Shows message to drop file
				**/
				onDragEnter	:	function( e ) {
					// overlay.className += " " + clss;
					++entered;
					
					setTimeout(function() {
						if( entered > 1 )
							entered = 1;
					}, 10 )
				},
				/**
				*	Hides the overlay... twist included!
				**/
				onDragLeave	:	function( e ) {
					--entered;
					
					if( entered <= 0 )
					{
						removeClass( overlay, clss );
						entered = 0;
					}
				},
				/**
				* Files dropped
				**/
				onDrop	:	function( e ) {
					// prevent the event from bubbling/firing default
					events.silencer( e );
					
					// Hide the overlay
					removeClass( overlay, clss );
					entered = 0;
					
					/** dropped files. **/
					var files = e.dataTransfer.files,
						len;
					
					// If anything is wrong with the dropped files, exit.
					if(	!files || !files.length )
						return false;
					
					len = files.length;
					while( len-- )
						// iterate files array and load them
						readFile( files[ len ], callback, method );
				}
			};
		
		(function init() {
			//_overlayBuilder();
			// events initialization
			body.parentNode.addEventListener( "dragenter", events.onDragEnter, false );
			body.addEventListener( "dragleave", events.onDragLeave, false );
			body.addEventListener( "dragover", events.silencer, false);
			body.addEventListener( "drop", events.onDrop, false);
			return false;
		})( body );
	};
})( window );