/*
 * @System Call: 
 * 	jQuery(selector).resourceBrowser(pData)
 * 		where:
 * 			pData: an Object containing--
 * 				requestHandler: string (default: current Location) 
 * 				The url and/or path to the server-side script which delivers our results
 * 				
 * 				directoryRequest: Object (default: empty Object)
 * 				The Post Data needed to get the folder list
 * 				
 * 				directoryContentRequest: Object (default empty Object)
 * 				The Post Data needed to get the content of a folder
 * 				NOTE: The plugin will put the selected folder in a variable called select_dir, so you should check for that variable in
 * 				the POST Object the server receives.
 * 				
 * 				resourceLocation: string (default: '/')
 * 				This location determines where to look for files. This is useful if you want to restrict resourceBrowser the a 
 * 				specific Path
 * 				
 * 				lockedIconImageSrc:	string (default: '/osr/icons/kde/crystalclear/16x16/actions/encrypted.png')
 * 				icon for a .htaccess-protected folder
 * 
 * 				unlockedIconImageSrc: string (default: '/osr/icons/kde/crystalclear/16x16/actions/decrypted.png')
 * 				icon for a .htaccess-proteced folder which was unlocked by a password
 * 				
 * 				expandedArrowSrc: string (default: '/osr/icons/kde/crystalclear/16x16/actions/arrow_down.png')
 * 				Icon which shows that a folder is expanded and where users click on to collapse it
 * 
 * 				collapsedArrowSrc: string (default: '/osr/icons/kde/crystalclear/16x16/actions/tab_right.png'
 * 				Icon which shows that a folder is collapsed and where users click on to expand it
 * 
 * 				ajaxLoaderSrc: string (default: '/osr/giflib/ajax-loader.gif')
 * 				Icon which indicates that resourceBrowser is loading
 * 
 * 				onFolderSuccess: function (default: '')
 * 				a JavaScript expression to be executed when this plugin loaded the folder list successfully.
 * 				The following structure is expected:
 * 					a JSON object. Each folder should have its own entry. Each entry has 2 keys, one called access, the other dir.
 * 					access defines if a folder has htaccess, so you should check for that on the server backend. If it is protected,
 * 					then the value of access should be 'denied', else 'granted'.
 * 					The value for dir should be the FULL DIRECTORY PATH like 'a/b/c'. The GUI will only display c, but needs a and b
 * 					to build the correct link afterwards. It also needs the full path to correctly display sub directories.
 * 					Example:
 * 						1 -> access -> granted
 * 							 dir 	-> resources
 * 						2 -> access -> denied
 * 							 dir 	-> resources/private
 * 						3 -> access -> granted
 * 							 dir 	-> locations
 * 
 * 				onFolderError: function (default: '')
 * 				a JavaScript expression to be executed when this plugin encountered an error while loading the folder list
 * 
 * 				onFolderComplete: function (default: '')
 * 				a JavaScript expression to be executed when this plugin finishes loading the folder list, regardless if it was successfull or not
 * 
 * 				onContentLoadSuccess: function (default: '')
 * 				a JavaScript expression to be executed when this plugin finishes loading the folder content successfully
 * 				The following structure is expected:
 * 					a JSON Object. Each entry contains a string, which is the name of the file with extension.
 * 					Example:
 * 						1 -> movie.avi
 * 						2 -> music.mp3
 * 						3 -> archive.zip
 * 
 * 				onContentLoadError: function (default: '')
 * 				a JavaScript expression to be executed when this plugin encountered an error while loading the folder content
 * 
 * 				onContentLoadComplete: function (default: '')
 * 				a JavaScript expression to be executed when this plugin finishes loading the folder content, regardless if it was successfull or not
 * 
 * 				onImageSelected: function (default: '')
 * 				a JavaScript expression to be executed when the user selects a file
 * 				
 * 				onFolderSelected: function (default: '')
 * 				a JavaScript expression to be executed when the user selects a folder
 * 
 * 				usePreviews: boolean (default: true)	
 * 				if set to true, this plugin will display pictures instead of their respective icons.
 * 
 * 				mimeBase: string (default: '/osr/icons/kde/crystalclear/64x64/mimetypes/')
 * 				the folder from where the mimetypes should be taken
 * 
 * 				mimetypes: Object (default: mimetypes[default] = 'empty.png')
 * 				an Object, holding one entry for each extension. The Object key is the extension while the value is the file within mimeBase
 * 
 * 				viewMode: string (default: 'icons')
 * 				a string, defining the view mode. Icon and list are currently available. This overrides usePreviews.
 * 
 * @Synopsis:
 * 	This Plugin generates a GUI from which files can be selected from the server. 
 * 
 * @Author: 
 * 	Ferreira Esteves Mike
 * 	http://sulfura3.blogspot.com
 * 	sulfura3@gmail.com
 * 
 * @Developed for:
 *  EducDesign S.A.
 *  68 rue Michel Hack
 *  Bettembourg, Luxembourg
 * 
 * @Info:
 * 	Please send any suggestions you might have to sulfura3+jquery@gmail.com
 * 	as I have a filter set on it.
 */


/*
 * Initializing the div tag for first use
 */
jQuery.fn.extend({
	resourceBrowser: function(pData) {
		if (typeof(pData) == 'undefined') {
			pData = new Object();
		}
		pData.root = this;
		jQuery.__resourceBrowser__defaultValues(this, pData);
		var requestHandler = pData.requestHandler;
		var ajaxData = pData.directoryRequest
		jQuery.__resourceBrowser__prepareResourceBrowser(this, pData);
		jQuery.ajax({
			url: requestHandler,
			dataType: 'json',
			data: ajaxData,
			success: function(json) {
				jQuery.__resourceBrowser__eventFolderListLoadSuccess(this, pData, json);
			},
			error: function() {
				jQuery.__resourceBrowser__eventFolderListLoadError(this, pData)
			},
			complete: function() {
				jQuery.__resourceBrowser__eventFolderListLoadComplete(this, pData)
			}
		});
		return this;
	}
});

jQuery.extend({
	/*
	 * Sets default values so that the user does not need to fill them all out
	 */
	__resourceBrowser__defaultValues: function(caller, pData) {
		if (pData.requestHandler == undefined) {
			pData.requestHandler = window.location;
		};
		if (pData.directoryRequest == undefined) {
			pData.directoryRequest = {};
		};
		if (pData.directoryContentRequest == undefined) {
			pData.directoryContentRequest == {};
		};
		if (pData.resourceLocation == undefined) {
			pData.resourceLocation = '/';
		};
		if (pData.lockedIconImageSrc == undefined) {
			pData.lockedIconImageSrc = '/osr/icons/kde/crystalclear/16x16/actions/encrypted.png';
		};
		if (pData.unlockedIconImageSrc == undefined) {
			pData.unlockedIconImageSrc = '/osr/icons/kde/crystalclear/16x16/actions/decrypted.png';
		};
		if (pData.expandedArrowSrc == undefined) {
			pData.expandedArrowSrc = '/osr/icons/kde/crystalclear/16x16/actions/arrow_down.png';
		};
		if (pData.collapsedArrowSrc == undefined) {
			pData.collapsedArrowSrc = '/osr/icons/kde/crystalclear/16x16/actions/tab_right.png';
		};
		if (pData.ajaxLoaderSrc == undefined) {
			pData.ajaxLoaderSrc = '/osr/giflib/ajax-loader.gif';
		};
		if (pData.onFolderSuccess == undefined) {
			pData.onFolderSuccess = function(){};
		};
		if (pData.onFolderError == undefined) {
			pData.onFolderError = function(){};
		};
		if (pData.onFolderComplete == undefined) {
			pData.onFolderComplete = function(){};
		};
		if (pData.onContentLoadSuccess == undefined) {
			pData.onContentLoadSuccess = function(){};
		};
		if (pData.onContentLoadError == undefined) {
			pData.onContentLoadError = function(){};
		};
		if (pData.onContentLoadComplete == undefined) {
			pData.onContentLoadComplete = function(){};
		};
		if (pData.onImageSelected == undefined) {
			pData.onImageSelected = function(){};
		};
		if (pData.onFolderSelected == undefined) {
			pData.onFolderSelected = function(){};
		}
		if (pData.usePreviews == undefined) {
			pData.usePreviews = true;
		};
		if (pData.mimeBase == undefined) {
			pData.mimeBase = '/osr/icons/kde/crystalclear/64x64/mimetypes/';
		};
		if (pData.mimetypes == undefined) {
			pData.mimetypes = {};
		};
		if (pData.mimetypes['default'] == undefined) {
			pData.mimetypes['default'] = 'empty.png';
		};
		if (pData.viewMode == undefined) {
			pData.viewMode = 'icon';
		}
	},

	/*
	 * Builds up the resource browser's HTML body from which everything is done.
	 */
	__resourceBrowser__prepareResourceBrowser: function(caller, pData) {
		var root = pData.root;
		var ajaxLoaderIcon = pData.ajaxLoaderSrc;
		jQuery(root).empty();
		jQuery(root).append(
				'<div class="resourceBrowser-folders"><ul>' +
					'<img class="ajaxLoader" src="'+ajaxLoaderIcon+'"></img>' +
				'</ul></div>' +
				'<div class="resourceBrowser-content"><ul></ul></div>'
		)
		jQuery(root).find('div.resourceBrowser-folders .dir_div').die('click').live('click', function() {
			jQuery.__resourceBrowser__updateList(this, pData)
		})
		
		//Here, we decide if we want to fold or collapse the children of an item, based on the alt attribute of the triangle
		jQuery(root).find('div.resourceBrowser-folders .dir_img').die('click').live('click', function() {
			if (this.alt == 'closed') {
				jQuery(this).attr('alt', 'open');
		 		jQuery.__resourceBrowser__foldChild(jQuery(this).parent('li').attr('title'), pData);
		 	} else {
				jQuery(this).attr('alt', 'closed');
		 		jQuery.__resourceBrowser__collapseChild(jQuery(this).parent('li').attr('title'), pData);
			}
		})
		
		jQuery(root).find('div.resourceBrowser-content img.preview, li.preview_text').die('click').live('click', function() {
			pData.selectedFile = this.title;
			pData.onImageSelected(pData.selectedFile, pData.currentDirectory);
		})
	},
	
	/*
	 * Folds a folder's sub-folders so they become visible
	 */
	__resourceBrowser__foldChild: function(pParent, pData) {
		var root = pData.root;
		//Get the current depth of the folder inside the tree
		var currentIndent = jQuery.__resourceBrowser__getIndent(pParent);
		
		//For every immediate child this item has, show it 
		jQuery.each(jQuery.find('li[title^="' + pParent + '"]'), function(i, item){
			if (jQuery.__resourceBrowser__getIndent(item.title) == (currentIndent + 1)) {
				jQuery(item).show('blind', 'slow');
			}
		});
		
		//Update the triangle
		var arrowDown = pData.expandedArrowSrc;
		jQuery(root).find('li[title="' + pParent + '"]').children('img.dir_img').attr('src', arrowDown);	
	},
	
	/*
	 * Collapses a folder's sub-folders so they aren't visible anymore
	 */
	__resourceBrowser__collapseChild: function(pParent, pData) {
		var root = pData.root;
		//Get the current depth of the folder inside the tree
		var currentIndent = jQuery.__resourceBrowser__getIndent(pParent);
		
		//Now, for every child this item has, hide it, then collapse their children too so they stay collapsed correctly after refolding it
		jQuery(root).find('li[title^="' + pParent + '"]:visible').each(function(i, item){
			if (jQuery.__resourceBrowser__getIndent(item.title) > (currentIndent)) {
				jQuery(item).hide('blind', 'slow');
				jQuery(item).children('img.dir_img').attr('alt', 'closed');
				jQuery(item).children('img.dir_img').attr('src', '/osr/icons/kde/crystalclear/16x16/actions/tab_right.png')
			}
		});
		
		//Update the triangle
		var arrowRight = pData.collapsedArrowSrc;
		jQuery(root).find('li[title="' + pParent + '"]').children('img.dir_img').attr('src', arrowRight);
	},
	
	/*
	 * Creates the folder list once it receives them from the server
	 */
	__resourceBrowser__eventFolderListLoadSuccess: function(caller, pData, json) {
		var root = pData.root;
		pData.directories = json;
		jQuery.each(json, function(i, option) {
			var folder = jQuery.__resourceBrowser__getFolder(option.dir);
			var protected_folder = '';
			var lockedIcon = pData.lockedIconImageSrc;
			var arrowDown = pData.collapsedArrowSrc;
			if (option.access == 'denied') {
				protected_folder = '<img src="'+lockedIcon+'" class="dir_lock">'
			}
			
			//Here we create the option for the list
			jQuery(root).find('div.resourceBrowser-folders ul').append('<li title="' + option.dir + 
				'" class="preview_dir"><img class="dir_img" alt="closed" src="'+arrowDown+'"/>'+
				'<div class="dir_div">' + folder + ''+protected_folder+'</div></li>'
			);
			
			//Now we make the triangle visible for every option which has at least one child and indent every child accordingly.
			jQuery(root).find('div.resourceBrowser-folders ul li[title="' + jQuery.__resourceBrowser__getPath(option.dir) + '"]').find('.dir_img').css({'visibility':'visible'});
			jQuery(root).find('div.resourceBrowser-folders ul li[title="' + option.dir + '"]').css({'padding-left':jQuery.__resourceBrowser__getIndent(option.dir)*16});
			
			//If the option is not immediatly below root (ergo. has a parent), hide it.
			if (jQuery.__resourceBrowser__getIndent(option.dir) > 0) {
				jQuery(root).find('div.resourceBrowser-folders ul li[title="' + option.dir + '"]').hide();
			}
		});
		pData.onFolderSuccess(json);
	},
	
	/*
	 * Calls the onFolderError Event and empties the folder list
	 */
	__resourceBrowser__eventFolderListLoadError: function (caller, pData) {
		pData.folders = new Array();
		pData.onFolderError();
	},
	
	/*
	 * Calls the onFolderComplete Event and removes the ajax loader
	 */
	__resourceBrowser__eventFolderListLoadComplete: function (caller, pData) {
		var root = pData.root;
		jQuery(root).find('img.ajaxLoader').remove();
		pData.onFolderComplete();
	},
	
	/*
	 * Filters the innermost folder from the rest of the path e.g. a/b/c -> c
	 */
	__resourceBrowser__getFolder: function (string) { 
		var folderArray = new Array();
		folderArray = string.split('/');
		return folderArray[folderArray.length - 1];
	},

	/*
	 * Gets the depth of a given path e.g. a/b/c -> 0/1/2 -> 2
	 */
	__resourceBrowser__getIndent: function (string) {
		var folderArray = new Array();
		folderArray = string.split('/');
		return folderArray.length - 1;
	},

	/*
	 * Filters the path from a chosen directory e.g. a/b/c -> a/b
	 */
	__resourceBrowser__getPath: function (path) {
		var folderArray = new Array();
		var pathString = "";
		folderArray = path.split('/');
			if (folderArray.length > 1) {
				pathString = folderArray[0];
				for (var i = 1; i < folderArray.length - 1; i++) {
						pathString = pathString + '/' + folderArray[i];
				}
			}
		return pathString;
	},
	
	/*
	 * Creates the files list. Note that the plugin always tries to load a file called htaccess, even if it does not exist.
	 * This is done so that it can detect a .htaccess proteced folder based on the Server's returned Error Code (401 = proteced).
	 */
	__resourceBrowser__updateList: function (caller, pData) {
		//For conveniance, we redefine the caller as being the parent <li> of the caller, as all the needed info is there rather than in the div who caused the function call
		var root = pData.root;
		var caller = jQuery(caller).parents('li:first');
		
		//We remove the selected visual Feedback from every item and add it to the caller 
		jQuery(root).find('.preview_dir').removeClass('selected_dir');
		jQuery(caller).addClass('selected_dir');
		
		var directory = jQuery(caller).attr('title');
		pData.currentDirectory = directory;
		pData.onFolderSelected(directory);
		
		var resourceLocation = pData.resourceLocation;
		var lockedIcon = pData.lockedIconImageSrc;
		var unlockedIcon = pData.unlockedIconImageSrc;
		jQuery.ajax({
			//vars
			type: 'POST',
			url: resourceLocation+'/'+directory+'/htaccess',
			dataType: 'text',
			async: true,
			error: function(request) {
				if (request.status == 401) {
					jQuery(caller).find('img.dir_lock').attr('src',lockedIcon);
				} else {                                                             
					jQuery(caller).find('img.dir_lock').attr('src',unlockedIcon);
					var requestHandler = pData.requestHandler;
					var data = pData.directoryContentRequest;
					data.select_dir = pData.currentDirectory;
					jQuery.ajax({
						//vars
						type: 'POST',
						url: requestHandler,
						dataType: 'json',
						async: true,
						data: data,
						//events
						success: function(json) {
							pData.files = json;
							pData.onContentLoadSuccess();
							var root = pData.root;
							jQuery(root).find('div.resourceBrowser-content ul').unbind().empty();
							jQuery.each(json, function(i, item){
								jQuery.__resourceBrowser__appendFile(item, pData);
							})
						},
						error: function() {
							pData.files = new Array();
							pData.onContentLoadError();
						},
						complete: function() {
							pData.onContentLoadComplete();
						}
					});
				};
			}
		});
	},
	
	/*
	 * Appends the single files from the server to the files container. The look how files are shown is primarily determined by
	 * mimeBase, mimetypes, viewMode and usePreviews
	 */
	__resourceBrowser__appendFile: function(item, pData) {
		var directory = pData.currentDirectory;
		if (pData.viewMode == 'list') {
			var extension = jQuery.__resourceBrowser__getExtension(item);
			var mime = jQuery.__resourceBrowser__selectMime(pData, extension);
			mime = '<img class="mini_preview" src="'+mime+'">';
			jQuery(pData.root).find('div.resourceBrowser-content ul').append('<li title="'+item+'" class="preview_list preview_text">'+mime+item+'</li>');
		} else {
			var extension = jQuery.__resourceBrowser__getExtension(item);
			var mime = jQuery.__resourceBrowser__selectMime(pData, extension);
			mime = '<img class="preview" title="' + item + '" src="'+mime+'" style="position: relative; left:0; top:0;">';
			var content = '<img title="' + item + '" src="'+pData.resourceLocation+ '/' + directory + '/' + item + '" class="preview">';
			if ((pData.usePreviews) && (jQuery.__resourceBrowser__isPicture(extension))) {
				jQuery(pData.root).find('div.resourceBrowser-content ul').append('<li class="preview_list">'+content+'</li>');
			} else {
				jQuery(pData.root).find('div.resourceBrowser-content ul').append('<li class="preview_list">'+mime+'</li>');
			}
		}
	},
	
	/*
	 * Gets the extension of a given file e.g. file.ext -> ext
	 */
	__resourceBrowser__getExtension: function(file) {
		var fileArray = new Array();
		fileArray = file.split('.');
		return fileArray[fileArray.length - 1];
	},
	
	/*
	 * Gets a given file's graphical representation based on its extension. If the extension has no representation 
	 * and none is given by the user, it defaults to a dummy icon.
	 */
	__resourceBrowser__selectMime: function(pData, extension) {
		var mimeBase = pData.mimeBase;
		if (pData.mimetypes[extension] != undefined) {
			return mimeBase + '/' + pData.mimetypes[extension]
		} else {
			return mimeBase + '/' + pData.mimetypes['default'];
		}
	},
	
	/*
	 * Determines if a file's content can be represented as picture based on the file's extensions
	 */
	__resourceBrowser__isPicture: function(extension) {
		if (extension.match(/(jpe?g)|(png)|(gif)/)) {
			return true;
		} else {
			return false;
		};
	},
	
	/*
	 * destroys the resource browser
	 */
	__resourceBrowser__destroy: function(root) {
		jQuery(root).find('div.resourceBrowser-folders .dir_div').die();
		jQuery(root).find('div.resourceBrowser-folders .dir_img').die();
		jQuery(root).find('img.preview').die();
		jQuery(root).unbind().empty();
	}
});


