/**
 * AS4ResourceManager
 * AJAX powered file and resources manager for the AS4 application
 */

// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
// Document-load events

document.observe('dom:loaded', function() 
{
	// If we are not a lightbox!
	if ($('resource_manager') && $('folder_contents')) 
		AS4ResourceManager.getInstance().refresh();
	
	// If we are a full render
	if ($('quick_search_terms')) 
	{
		$('quick_search_terms').observe('keyup', function()
		{
			AS4ResourceManager.getInstance().setTerms($F('quick_search_terms'));
			AS4ResourceManager.getInstance().search.bind(AS4ResourceManager.getInstance()).delay(2); // Delay the search by 2 seconds, allow typing to catch up
		});

		$('quick_search_terms').observe('blur', function() {
			AS4ResourceManager.getInstance().setTerms($F('quick_search_terms'));
			AS4ResourceManager.getInstance().search.bind(AS4ResourceManager.getInstance()).delay(2); // Delay the search by 2 seconds, allow typing to catch up
		});

		AS4FormMethods.applyPlaceholders(null, $A([$('quick_search_terms')]));
	}
})


// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
// Class declaration

var AS4ResourceManager = Class.create({
	
	/**
	 * @type {string} Constant for the list display mode
	 */
	LIST_DISPLAY: 0,

	/**
	 * @type {string} Constant for the list display mode
	 */
	THUMB_DISPLAY: 1,

	/**
	 * @type {string} Constant for the root 'My Channels' path. Should match that of the AS4ResourceManagerComponentController::ROOT_PATH
	 */
	ROOT_PATH: '/',

	/**
	 * @type string Psuedo-path to the current user's media items
	 */
	MY_MEDIA: '*',

	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

	/**
	 * Inline browser mode - folders or resources
	 */
	browseTypes: 'resources',

	/**
	 * @type {Array} Stores an array of resource types for which the results of a search will be filtered. An empty array returns all types
	 */
	filters: $A(),

	/**
	 * @type {Function} Stores the checkbox toggler event handler, so it can be bound and unbound as required
	 */
	filesSelectAllClickHandler: null,

	/**
	 * @type {string} The current display mode for the resource manager
	 */ 
	displayMode: null,

	/**
	 * @type integer Indicates if the resource manager is being output inline rather than as a full render
	 */
	outputMode: null,

	/**
	 * @type {integer} currentChannel The currently loaded channel/folder id. Null will load the ROOT_PATH.
	 */
	currentChannel: null,
	
	/**
	 * @type {integer} page The currently loaded file list page 
	 */
	filePage: 1,
	
	/**
	 * @type {integer} page The currently loaded folder list page 
	 */
	folderPage: 1,
	
	/**
	 * @type {integer} limit The number of items currently returned
	 */
	folderLimit: 5,
	
	/**
	 * @type {integer} limit The number of items currently returned
	 */
	fileLimit: 5,	

	/**
	 * @type string Store the current search terms entered by the user
	 */
	terms: '',
	
	/**
	 * @type string Store a reference to the last terms that were successfully searched
	 */
	previousTerms: null,

	/**
	 * @type {boolean} Indicate if other users' public media should be listed in the media library
	 */
	showOthersMedia: false,
	
	/**
	 * @type {CoverFlow}
	 */
	coverFlow: null,
	/**
	 * @type {boolean} Indicate if resources should be draggable from the list. Default is true.
	 */
	allowDragging: true,

	/**
	 * @type {Element} A clone of the element currently being dragged
	 */
	draggableClone: null,

	/**
	 * @type {boolean} Indicate if the JSON coverflow interface should be used
	 */
	usesCoverFlow: false,

	// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
	
	/**
	 * @constructor
	 */
	initialize: function()
	{
		this.currentChannel = this.ROOT_PATH;
		this.displayMode = this.LIST_DISPLAY;
		this.outputMode = AS4ResourceManager.OUTPUT_MODE_FULL;
	},
	
	/**
	 * Refresh the currently displayed files panel 
	 */
	refresh: function() 
	{
		this.loadFolderContents(null, false);
		
		if($('folders_list'))
			this.loadFolderListing(null, true);
	},
	
	/**
	 * Load a specific folder, refreshing both the folders tree and contents
	 * @param {integer} [id] Optional id of the folder to load
	 */
	reload: function(id)
	{
		if(id)
			this.currentChannel = id;
			
		this.refresh();
	},
	
	// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
	// AJAX methods
	
	/**
	 * Create a new folder from the information in the create_folder_panel
	 */
	createSubFolder: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			AS4Shell.exception('Current path is not applicable');
		
		var url = '/resource_manager/create_sub_folder';
		
		var params = {
			renderMode: 'update',
			channelId: this.currentChannel,
			folderName: $F('folder_name')
		};
		
		// Hide the create folder panel
		AS4Shell.getInstance().toggle(['create_folder_panel'])

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.refresh.bind(this)]), {message:'Creating folder...'});
	},
	
	/**
	 * Creates a new web link resource within the current folder
	 */
	createWebLink: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			AS4Shell.exception('Current path is not applicable');
		
		var url = '/resource_manager/create_web_link';
		
		var params = {
			renderMode: 'update',
			channelId: this.currentChannel,
			linkUrl: $F('link_url'),
			linkText: $F('link_text')
		};
		
		// Hide the create folder panel
		AS4Shell.getInstance().toggle(['create_web_link'])

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.loadFolderContents.bind(this, null, false)]), {message: 'Creating web link...'} );
	},	

	/**
	 * Creates a new blog resource within the current folder
	 */
	createBlog: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			AS4Shell.exception('Current path is not applicable');
		
		var url = '/resource_manager/create_blog';
		
		var params = {
			renderMode: 'update',
			folderId: this.currentChannel
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateResourceComplete.bind(this)]), {message: 'Creating blog...'});
	},	

	/**
	 * Creates a new blog entry for the given blog, ensuring that the accessing user is the blog owner. The generated blog entry will be
	 * placed in the same location as the containing blog.
	 * 
	 * @param {integer} blogId Identifier of the blog for which an entry will be created. Only the blog owner can create an entry. 
	 */
	createBlogEntry: function(blogId)
	{
		if(!blogId)
			AS4Shell.exception('No blog supplied');
			
		var url = '/resource_manager/create_blog_entry';
		
		var params = {
			renderMode: 'update',
			blogId: blogId
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateResourceComplete.bind(this)]), {message: 'Creating blog entry...'});
	},	

	/**
	 * Creates a new slideshow resource within the current folder
	 */
	createSlideshow: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			AS4Shell.exception('Current path is not applicable');
		
		var url = '/resource_manager/create_slideshow';
		
		var params = {
			renderMode: 'update',
			folderId: this.currentChannel
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateResourceComplete.bind(this)]), {message: 'Creating slideshow...'} );
	},	

	/**
	 * Creates a new slideshow link for the given slideshow, ensuring that the accessing user is the slideshow owner. The generated slideshow link will be
	 * placed in the same location as the containing slideshow.
	 * 
	 * @param {integer} slideshowId Identifier of the slideshow for which a link will be created. Only the slideshow owner can create a link. 
	 */
	createSlideshowItem: function(slideshowId)
	{
		if(!slideshowId)
			AS4Shell.exception('No slideshow supplied');
			
		var url = '/resource_manager/create_slideshow_item';
		
		var params = {
			renderMode: 'update',
			slideshowId: slideshowId
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateResourceComplete.bind(this)]));
		//AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateSlideshowItemComplete.bind(this)]));
	},	


	/**
	 * Create a new folder from the information in the create_folder_panel
	 */
	uploadRedirect: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			AS4Shell.exception('Current path is not applicable');
		
		// Redirect to the upload form
		AS4Shell.getInstance().redirect('/resource_editor/upload_files/channel_id/' + this.currentChannel);

	},
		
	insertFileUploadForm: function(targetID)
	{
		AS4Shell.getInstance().insertFileUploadForm(targetID,this.currentChannel);

	},	
	
	setCurrentChannel: function(channelID)
	{
		this.currentChannel = channelID;
	},		
	
	/**
	 * Attempt to delete the given folder
	 * 
	 * @param {integer} id Id of the folder to delete 
	 */
	deleteFolder: function(id)
	{
		if(!id)
			return;
			
		if(!confirm('Are you sure you want to delete this folder?'))
			return;
		
		var url = '/resource_manager/delete_folder';
		
		var params = {	
			renderMode: 'update',
			folderId: id
		}
		
		AS4Shell.getInstance().closeLightbox();
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.refresh.bind(this)]), {message: 'Deleting folder...'});
	},
	
	/**
	 * Display the properties lightbox for the given folder
	 * 
	 * @param {integer} id Id of the folder to delete 
	 */
	showFolderProperties: function(id)
	{
		if(!id)
			return;
			
		var params = {
			callback: this.onShowFolderProperties.bind(this, id),
			width: 400,
			height: 400
		};
			
		AS4Shell.getInstance().showLightbox(params);
	},
	
	/**
	 * Delete the current folder's thumbnail if it exists
	 */
	deleteThumbnail: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			return;
			
		if(!confirm('Are you sure you want to delete this folder\'s thumbnail?'))
			return;
		
		AS4Shell.getInstance().toggle(['folder_properties_panel']);
		
		var url = '/resource_manager/delete_thumbnail';
		
		var params = {
			renderMode: 'update',
			folderId: this.currentChannel
		}
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.loadContextActions.bind(this)]), {message:'Removing thumbnail...'});
	},
	
	/**
	 * Attempt to delete the given resource
	 * 
	 * @param {integer} id Id of the resource to delete 
	 */
	deleteResource: function(id)
	{
		if(!id || !this.currentChannel || this.currentChannel == this.ROOT_PATH)
			return;
			
		if(!confirm('Are you sure you want to delete this resource?'))
			return;
		
		var url = '/resource_manager/delete_resource';
		
		var params = {
			renderMode: 'update',
			folderId: this.currentChannel,
			resourceId: id
		}
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.loadFolderContents.bind(this, null, false)]), {message: 'Deleting resource...'});
	},
	
	/**
	 * Create a new web page resource in the current folder
	 */
	createWebPage: function()
	{
		if(!this.currentChannel || this.currentChannel == this.ROOT_PATH)
			return;
			
		var url = '/resource_manager/create_web_page';
		
		var params = {
			renderMode: 'update',
			folderId: this.currentChannel
		}
		
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCreateResourceComplete.bind(this)]), {message: 'Creating Web Page...'});
	},
	
	/**
	 * Loads the specified file contents chosen via pagination
	 */
	loadFilePage: function(filePage)
	{
		this.filePage = filePage;
		this.loadFolderContents(null, false);
	},
	/**
	 * Wrapper to loadFolderContents used to load my media, resets folder page and files page
	 */
	loadMyMedia: function(){
		
		this.folderPage = 1;
		this.filePage = 1;
		this.loadFolderContents(this.MY_MEDIA);
	},
	/**
	 * Loads the specified folder contents chosen via pagination
	 */
	loadFolderPage: function(folderPage)
	{
		this.folderPage = folderPage;
		this.loadFolderListing(null, false);
	},
	/**
	 * Loads the specified folder contents chosen via pagination for an inline render
	 */
	loadInlineFolderPage: function(folderPage)
	{
		this.folderPage = folderPage;
		this.loadFolderContents(null, false);
	},
	/**
	 * Resets folder and files pagination when loading new folder or channel
	 */	
	loadFolderReset: function(id){
		this.folderPage = 1;
		this.filePage = 1;
		this.loadFolderContents(id);
	},		
	/**
	 * Changes the limit of folder items to display per a page
	 */	
	changeFolderLimit: function(limit){
		this.folderPage = 1;
		this.filePage = 1;			
		this.folderLimit = limit;
		this.loadFolderContents(null, false);
	},
	/**
	 * Changes the limit of folder items to display per a page
	 */	
	changeFileLimit: function(limit){
		this.folderPage = 1;
		this.filePage = 1;		
		this.fileLimit = limit;
		this.loadFolderContents(null, false);
	},	
	/**
	 * Call a folder listing for the currentChannel
	 *
	 * @param {integer} [id] Optional id of the channel to load. If null, the currentChannel id is used. Default is null.
	 * @param {boolean} [updateActions] Optional boolean to trigger an update of the context actions after the folder has been loaded. Default is false.
	 */
	loadFolderContents: function(id, updateActions)
	{
		if(updateActions == null)
			updateActions = $('context_actions') ? true : false;

		var url = '/resource_manager/load_folder_contents';
		if(id)
			this.currentChannel = id;
				
		var params = {
			renderMode: 'update',
			displayMode: this.displayMode,
			outputMode: this.outputMode,
			channelId: this.currentChannel,
			filePage: this.filePage,
			folderPage: this.folderPage,
			folderLimit: this.folderLimit,
			fileLimit: this.fileLimit,
			terms: this.terms,
			show_others_media: this.showOthersMedia,
			show_types: this.browseTypes,
			filters: Object.toJSON(this.filters),
			uses_cover_flow: this.usesCoverFlow
		};
		
		this.onBeginLoadFolderContents(id, updateActions);
		
		if (updateActions) 
			AS4Shell.getInstance().ajaxUpdate(url, params, 'folder_contents', $A([this.loadContextActions.bind(this), this.onLoadFolderContents.bind(this)]), {showIndicator: false, updateCondition: function(transport, target) { return transport.headerJSON.meta.search_terms == this.terms; }.bind(this)});
		else 
			AS4Shell.getInstance().ajaxUpdate(url, params, 'folder_contents', $A([this.onLoadFolderContents.bind(this)]), {showIndicator: false, updateCondition: function(transport, target) { return transport.headerJSON.meta.search_terms == this.terms; }.bind(this)});
	},

	/**
	 * Call a folder listing for the currentChannel
	 *
	 * @param {integer} [id] Optional id of the channel to load. If null, the currentChannel id is used. Default is null.
	 * @param {boolean} [updateActions] Optional boolean to trigger an update of the context actions after the folder has been loaded. Default is true.
	 */
	loadFolderListing: function(id, updateActions)
	{
		if(updateActions == null)
			updateActions = $('context_actions') ? true : false;

		var url = '/resource_manager/load_folder_listing';
		if(id)
			this.currentChannel = id;
				
		var params = {
			renderMode: 'update',
			displayMode: this.displayMode,
			outputMode: this.outputMode,
			channelId: this.currentChannel,
			filePage: this.filePage,
			folderPage: this.folderPage,
			folderLimit: this.folderLimit,
			fileLimit: this.fileLimit,
			terms: this.terms,
			show_others_media: this.showOthersMedia,
			filters: Object.toJSON(this.filters)
		};
		
		this.onBeginLoadFolderListing(id, updateActions);
		
		if (updateActions) 
			AS4Shell.getInstance().ajaxUpdate(url, params, 'folders_list', $A([this.loadContextActions.bind(this), this.onLoadFolderContents.bind(this)]), {showIndicator: false, updateCondition: function(transport, target) { return transport.headerJSON.meta.search_terms == this.terms; }.bind(this)});
		else 
			AS4Shell.getInstance().ajaxUpdate(url, params, 'folders_list', $A([this.onLoadFolderContents.bind(this)]), {showIndicator: false, updateCondition: function(transport, target) { return transport.headerJSON.meta.search_terms == this.terms; }.bind(this)});
	},
	
	/**
	 * Call to update the available folder actions based on the current state of the file browser
	 */
	loadContextActions: function()
	{
		var url = '/resource_manager/load_context_actions';
		
		var params = {
			renderMode: 'update',
			channelId: this.currentChannel
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, 'context_actions', $A([this.onLoadContextActions.bind(this)]), {showIndicator: false});
		$('context_actions').update('Updating...');
	},
	
	/**
	 * Perform a tag/title search for resources matching the given terms. Calls the
	 * onSearchComplete AJAX callback. Note that this method makes singleton calls to
	 * the current resource manager because the delay method does not bind its call to
	 * the correct context
	 *
	 * @param {String} terms Search terms to use
	 * @return void
	 */
	search: function(terms)
	{
		// If we have been triggered by a delayed 'quick search', check the value we are searching for
		// matches what is in the search box; otherwise, discard the search request.
		if ($('quick_search_terms')) 
		{
			if ((terms == null && $F('quick_search_terms') != this.terms) || this.terms == this.previousTerms) 
				return;
		}
		else if(terms)
			this.terms = terms;
			
		var url = '/resource_manager/tag_search';
		
		this.filePage = 1;
		
		if(this.outputMode == this.THUMB_DISPLAY)
			this.currentChannel = this.MY_MEDIA;
		
		this.loadFolderContents(null, false);
	},
	
	/**
	 * Save the currently displayed properties (in the folder properties lightbox) to the database
	 * @param {integer} id The id of the folder to be updated
	 */
	saveFolderProperties: function(id)
	{
		if(!id)
			return;
		
		// Attempt to update the folder's properties
		var url = '/resource_manager/save_folder_properties';
		
		var params = {
			folder_id: id,
			name: $F('properties_folder_name'),
			is_hidden: $('properties_is_hidden').checked,
			linked_resource_id: $F('properties_linked_resource_id')
		};

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onSaveFolderPropertiesComplete.bind(this)]));
	},
	
	/**
	 * Updates the selected resources with the current action. Any resources that are not applicable for the current action
	 * will be ignored.
	 */
	updateResources: function()
	{
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		// Confirm actions
		if($F('action') == 'delete' && !confirm('Are you sure you want to delete the selected resources?'))
			return;

		var url = '/resource_manager/update_resources';

		var params = {
			renderMode: 'update',
			action: $F('action'),
			channelId: this.currentChannel,
			filePage: this.filePage,
			folderPage: this.folderPage,
			folderLimit: this.folderLimit,
			fileLimit: this.fileLimit,	
			terms: this.terms
		}
		
		AS4Shell.getInstance().ajaxUpdate(url, $H(params).toQueryString() + '&' + $('files_list_form').serialize(), 'folder_contents', $A([this.onLoadFolderContents]));
	},
	
	// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
	// AJAX callback methods
	
	/**
	 * Callback method triggered by the successful creation of a resource
	 *
	 * @param {Transport} transport
	 * @param {HTMLElement} target
	 */
	onCreateResourceComplete: function(transport, target)
	{
		if(!transport.headerJSON)
			return;

		if(transport.headerJSON.new_resource_id)
			AS4Shell.getInstance().redirect('/resource_editor/edit/id/' + transport.headerJSON.new_resource_id);
		else
			this.loadFolderContents(null, false);
	},

	/**
	 * Callback for the show folder properties lightbox
	 * @param {integer} id Folder id of the folder whose properties to load 
	 */
	onShowFolderProperties: function(id)
	{
		var url = '/resource_manager/show_folder_properties';

		var params = {
			renderMode: 'lightbox',
			folder_id: id
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, 'folder_properties_container', $A(), {showIndicator: false});
		
		return	'<div id="folder_properties_container">' +
					'<div class="centre" style="padding-top: 40%">' +
						'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
					'</div>' +
				'</div>';
	},
	
	/**
	 * Event called when the media library is about to perform a load
	 * 
	 * @param {integer} id Id of the channel being loaded
	 * @param {boolean} updateActions Indicate if the actions panel will be updated.
	 */
	onBeginLoadFolderContents: function(id, updateActions)
	{
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Update spinners
		$('folder_contents').update('<div class="centre">' +
		'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
		'</div>');
		
		// Execute the AJAX request
		if (updateActions && $('context_actions')) 
		{
			$('context_actions').update('<div class="centre">' +
			'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
			'</div>');
		}
	},

	/**
	 * Event called when the media library is about to perform a folder listing
	 * 
	 * @param {integer} id Id of the channel being loaded
	 * @param {boolean} updateActions Indicate if the actions panel will be updated.
	 */
	onBeginLoadFolderListing: function(id, updateActions)
	{
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Update spinners
		$('folders_list').update('<div class="centre">' +
		'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
		'</div>');
		
		// Execute the AJAX request
		if (updateActions && $('context_actions')) 
		{
			$('context_actions').update('<div class="centre">' +
			'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
			'</div>');
		}
	},

	/**
	 * Event triggered after a successful folder update
	 */
	onSaveFolderPropertiesComplete: function(transport, target)
	{
		if(transport.headerJSON && transport.headerJSON.success && transport.headerJSON.success == 'true')
		{
			AS4Shell.getInstance().closeLightbox();
			this.loadFolderListing();
		}
	},		
	
	/**
	 * Event triggered when the loadFolderContents returns content
	 */
	onLoadFolderContents: function(transport, target)
	{
		if(transport.headerJSON && transport.headerJSON.exception)
		{
			AS4Login.getInstance().showLoginLightbox();
			return;
		}

		if($('current_path_main') && transport.headerJSON.meta)
		{			
			var output = '';
			//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
			// Update the current path breadcrumb trail
			$H(transport.headerJSON.meta.path_components).each(function(pair){			
				if(pair[0] != '/')
					output += '/<strong><a href="/channel/index/id/' +  pair[0] + '">'  +  pair[1] + '</a></strong>';
			}.bind(this));
						
			if(output==''){
				output ='<div class="clear break"/>';
				$('current_path_main').update(output);
			}
			else{
				output +='<div class="clear break"/>';
				$('current_path_main').update(output.substr(1));
			}
							
		}		
			
		if(transport.headerJSON && transport.headerJSON.error_message)
			alert(transport.headerJSON.error_message);
			
		if($('current_path') && transport.headerJSON.meta)
		{
			var output = '';

			// Update the current path breadcrumb trail
			$H(transport.headerJSON.meta.path_components).each(function(pair){
				if(pair[0] == '/')									
					output += '/<strong><a href="javascript:AS4ResourceManager.getInstance().reload(\'' + pair[0] + '\');">'  + pair[1] + '</a></strong>';
				else
				if(pair[0] != '/')
					output += '/<strong><a href="javascript:AS4ResourceManager.getInstance().reload(' + pair[0] + ');">'  + pair[1] + '</a></strong>';
			}.bind(this));
			
			$('current_path').update(output.substr(1));
		}
	
		if($('files_select_all'))
			$('files_select_all').observe('click', function(){AS4FormMethods.toggleCheckboxes(this, $('files_list_form'))});

		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Observe any loaded resources for events
		$$('.file > .icon').each(function(element) {
			$(element).observe('click', this.onClickResource.bind(this, element))
		}.bind(this));
		
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Reference the search terms that were used
		if(transport.headerJSON.meta.search_terms == this.terms) 
			this.previousTerms = transport.headerJSON.meta.search_terms;
		
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Apply Coverflow browsing
		if(this.outputMode == AS4ResourceManager.OUTPUT_MODE_INLINE && typeof(CoverFlow) != 'undefined' && this.usesCoverFlow )
		{
			if(this.coverFlow)
			{
				this.coverFlow.destroy();
				this.coverFlow = new CoverFlow();
			}
			else
			{
				this.coverFlow = new CoverFlow();
				 // vertical slider control                                                                                                                                                                         
				 new Control.Slider('media_gallery_handle', 'media_gallery_track', {
					 axis: 'vertical',
						 onSlide: function(value) { this.coverFlow.reset(); this.coverFlow.value = value; this.coverFlow.update(); }.bind(this),
						 onChange: function(value) { this.coverFlow.reset();this.coverFlow.value = value; this.coverFlow.update(); }.bind(this)
				 });
			}

			eval('var json = ' + $('files').readAttribute('class'));

			// Build a new CoverFlow browser
			this.coverFlow.create('media_gallery_container', json.data, {
				contain: '.icon'
			});

			// Update the slider control size
//			$('media_gallery_handle').setStyle({
//				height: Math.max($('media_gallery_track').getHeight() / Math.min((this.coverFlow.data.length - 5), 1), 10) + 'px'
//			});
		}


		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Make file icons draggable according to the current render mode. 
		if(this.allowDragging)
		{
			var elements = $A([]);
			if($('file_list'))
				elements = $('file_list').select('.icon');
			else if($('folders_list') && this.outputMode == AS4ResourceManager.OUTPUT_MODE_INLINE)
				elements = $('folders_list').select('.icon');

			elements.each(function(element)
			{
				// Normal Scriptac. draggables can't be dragged outside a scrollable (overflow:scroll/auto) container, as they just cause
				// the container to grow. So, rather than directly dragging the icon, we drag a clone of it that is injected at the document
				// top-node level. Hence, a super-draggable!
				element.observe('mousedown', AS4ResourceManager.getInstance().makeSuperDraggable.bindAsEventListener(this, element));
				element.observe('mouseup', function() {
					if(this.draggableClone){
						$(this.draggableClone).remove();
					}
				});
			});
		}
		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Rendering full mode, so set up any interface requirements (e.g. drag-drop folder reordering)
		if($('folders'))
			Sortable.create('folders',
			{
				scroll: 'files_panel_container',
				handle: 'icon',
				only: 'folder',
				hoverclass: 'drop_zone',
				onUpdate: this.onDropFolder
			}).bind(this);


		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
		// Apply transparencies to any loaded icons
		if(Prototype.Browser.IE)
			AS4Shell.getInstance().renderTransparencies();
	},
	
	/**
	 * Make an element a super-draggable, that is a node that when clicked is cloned to the top-document level
	 * and the clone then made draggable
	 * 
	 * @param {Object} event
	 */
	makeSuperDraggable: function(event, element)
	{
		if(!event.isLeftClick())
			return;
						
		var src = $(element).down('img').src
		this.draggableClone = Builder.node('img', {src: src});

		$w($(element).className).each(function(name){
			$(this.draggableClone).addClassName(name);
		});
		

		$('page_content').insert(this.draggableClone);

		$(this.draggableClone).absolutize();
		$(this.draggableClone).clonePosition(element);

		$(this.draggableClone).id = $(element).id + "_clone";
	
		var draggable = new Draggable(this.draggableClone, {
			revert: false,
			starteffect: null,
			endeffect: null,
			reverteffect: null,
			onEnd: function(event) {
				$(this.draggableClone).remove();
				
			}.bind(this)
			
		});
	
		draggable.initDrag(event);
	},
	
	/**
	 * Callback triggered when a folder has been re-ordered within the resource manager
	 * @param {Element} element The sortable containing element
	 */
	onDropFolder: function(element)
	{
		var url = '/resource_manager/update_order_index';
		
		AS4Shell.getInstance().ajaxUpdate(url, Sortable.serialize('folders'), null, $A());
	},
	
	/**
	 * Event triggered after a search has completed. Forwards content on to the onLoadFolderContents method
	 *  
	 * @param {Object} transport
	 * @param {Object} target
	 */
	onSearchComplete: function(transport, target)
	{
		this.onLoadFolderContents(transport, target);
	},
	
	/**
	 * Event triggered when the loadContextActions returns content
	 */
	onLoadContextActions: function(transport, target)
	{
	},

	// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
	// User interface callbacks
	
	/**
	 * Event handler triggered when a resource element is clicked on. If set, every resource element will observe
	 * for a click event.
	 *
	 * @param {integer} element The element that sent the event
	 */
	onClickResource: function(element) 
	{
	},
	
	//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

	setTerms: function(terms)
	{
		if ($('quick_search_terms')) 
		{
			if (terms != $('quick_search_terms').readAttribute('placeholder')) 
				this.terms = terms;
		}
		else
			this.terms = terms;
	}
});


 
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
// Static Methods & Properties

// Static instance of the AS4ResourceManager object
AS4ResourceManager.instance = null;

/**
 * @type integer Output the library as a full-page render
 */
AS4ResourceManager.OUTPUT_MODE_FULL = 0;

/**
 * @type integer Output the library as an inline browser
 */
AS4ResourceManager.OUTPUT_MODE_INLINE = 1;

/**
 * @type integer Filter items restricting to web pages 
 */
AS4ResourceManager.FILTER_WEB_PAGE = 1;

/**
 * @type integer Filter items restricting to file items 
 */
AS4ResourceManager.FILTER_FILES = 5;

/**
 * @type integer Filter items restricting to media items 
 */
AS4ResourceManager.FILTER_MEDIA = 11;

/**
 * Return a singleton instance of the AS4ResourceManager object
 * @return AS4ResourceManager
 */
AS4ResourceManager.getInstance = function()
{
	if(!AS4ResourceManager.instance)
		AS4ResourceManager.instance = new AS4ResourceManager();
		
	return AS4ResourceManager.instance;
}
 
