//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using CommunityServer;
using CommunityServer.Components;
using CommunityServer.Files.Components;

namespace CommunityServer.Files.Components
{
	/// <summary>
	/// Manager class for the <see cref="Folder"/> objects.  This class cannot be instanciated, it contains all static methods.
	/// </summary>
	public class Folders
	{
		// Do not allow the class to be instanciated.
		private Folders() { }

		#region Folder


		/// <summary>
		/// This method creates a new <see cref="Folder"/>.  It returns the ForumID of object in the database.
		/// </summary>
		/// <param name="folder">The <see cref="Folder"/> object to create</param>
		/// <returns>int</returns>
		public static int Create(Folder folder)
		{ 
			// Make sure the date is set for the gallery
			folder.DateCreated = DateTime.Now;

			// Make sure it is clean
			folder.Name = HtmlScrubber.Clean(folder.Name, false, true);
			folder.Description = HtmlScrubber.Clean(folder.Description, false, true);

			// Censor the stuff, if enabled
			if(CSContext.Current.SiteSettings.EnableCensorship)
			{
				folder.Name = Transforms.CensorPost(folder.Name);
				folder.Description = Transforms.CensorPost(folder.Description);
			}

			// Create the gallery
			folder.SectionID = Sections.AddSection(folder);

			ExpireFoldersCache();

			// Return the ID
			return folder.SectionID;
		}


		/// <summary>
		/// This method updates a <see cref="Folder"/> object.
		/// </summary>
		/// <param name="folder">The <see cref="Folder"/> object to update</param>
		/// <returns>int</returns>
		public static int Update(Folder folder) 
		{
			// Make sure it is clean
			folder.Name = HtmlScrubber.Clean(folder.Name, false, true);
			folder.Description = HtmlScrubber.Clean(folder.Description, false, true);

			// Censor the stuff, if enabled
			if(CSContext.Current.SiteSettings.EnableCensorship)
			{
				folder.Name = Transforms.CensorPost(folder.Name);
				folder.Description = Transforms.CensorPost(folder.Description);
			}

			ExpireFoldersCache(folder.SectionID);

			// Update the gallery
			return Sections.UpdateSection(folder);
		}


		/// <summary>
		/// This method deletes a specified <see cref="Folder"/> and all of the <see cref="Entry"/> items it contains.
		/// </summary>
		/// <param name="folderID"></param>
		public static void Delete(int folderID)
		{
			// We first need the gallery, to do a few things
			Folder folder = GetFolder(folderID, false);

			FileGalleryAttachmentSettings fgas = FileGalleryConfiguration.GetConfig().AttachmentSettings;

			// Delete the picture files
			try
			{
				fgas.DeleteSectionFromDisk(folder.SectionID);
			}
			catch(Exception ex)
			{ 
				new CSException(CSExceptionType.UnknownError, "An error occured while deleting a folder.", ex).Log(); 
			}

			// Delete the gallery in the database
			Sections.DeleteSection(folder);

			ExpireFoldersCache(folderID);
		}

		public static Folder GetRandomFolder()
		{
			ArrayList folders = GetFolders();

			Section section = Sections.GetRandomSection(folders);
			if(section == null)
				return null;

			return section as Folder;
		}

		/// <summary>
		/// This method gets the specified <see cref="Folder"/>
		/// </summary>
		/// <param name="folderID">The ID of the <see cref="Folder"/> to retrieve</param>
		/// <returns><see cref="Folder"/></returns>
		public static Folder GetFolder(int folderID)
		{
			return GetFolder(folderID, true);
		}

		/// <summary>
		/// This method gets the specified <see cref="Folder"/>.  Allows you to specified if the data is cached.
		/// </summary>
		/// <param name="folderID">The ID of the <see cref="Folder"/> to retrieve</param>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns><see cref="Folder"/></returns>
		public static Folder GetFolder(int folderID, bool cacheable)
		{
		    CSContext csContext = CSContext.Current;
			Hashtable folders = GetFolders(csContext, csContext.User.UserID, true, cacheable, !cacheable, true);

			// Return the gallery
			foreach(Folder folder in folders.Values)
				if(folder.SectionID == folderID)
					return folder;

			// If we are still here, then the gallery doesn't exist
			if (csContext.User.IsAnonymous && csContext.Context != null)
			{
				csContext.Context.Response.Redirect(SiteUrls.Instance().Login, true);
				return null;
			}
			else
				throw new CSException(CSExceptionType.ResourceNotFound, "Folder not found: " + folderID);
		}

		/// <summary>
		/// This method gets the spcified <see cref="Folder"/>.
		/// </summary>
		/// <param name="applicationKey">The ApplicationKey of the <see cref="Folder"/> to retrieve</param>
		/// <returns><see cref="Folder"/></returns>
		public static Folder GetFolder(string applicationKey)
		{
			return GetFolder(applicationKey, true);
		}

		/// <summary>
		/// This method gets the specified <see cref="Folder"/>.  Allows you to specify if the data is cached.
		/// </summary>
		/// <param name="applicationKey">The ApplicationKey of the <see cref="Folder"/> to retrieve</param>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns><see cref="Folder"/></returns>
		public static Folder GetFolder(string applicationKey, bool cacheable)
		{
			applicationKey = applicationKey.ToLower();
		    CSContext csContext = CSContext.Current;
			Hashtable folders = GetFolders(csContext, csContext.User.UserID, true, cacheable, !cacheable, true);

			// Return the gallery
			Folder folder = folders[applicationKey] as Folder;

			if(folder != null)
				return folder;
			
			// If we are still here, then the gallery doesn't exist
			if (csContext.User.IsAnonymous && csContext.Context != null)
			{
				csContext.Context.Response.Redirect(SiteUrls.Instance().Login, true);
				return null;
			}
			else
				throw new CSException(CSExceptionType.ResourceNotFound, "Folder not found: " + applicationKey);
		}

		/// <summary>
		/// This method gets all of the <see cref="Folder"/> objects at the current site.
		/// </summary>
		/// <returns><see cref="ArrayList"/></returns>
		public static ArrayList GetFolders()
		{
			return GetFolders(CSContext.Current.User.UserID, false, true, false);
		}

		/// <summary>
		/// This method gets all of the <see cref="Folder"/> objects at the curren site.  Allows you to specify if the data is cached.
		/// </summary>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns>ArrayList</returns>
		public static ArrayList GetFolders(bool cacheable, bool flush)
		{
			return GetFolders(CSContext.Current.User.UserID, false, cacheable, flush);
		}

		/// <summary>
		/// This method gets all of the <see cref="Folder"/> objects at the current site.  Allows you to specify the user to retrieve
		/// <see cref="Folder"/> objects from, whether to ignore permissions, and whether to cache the data.
		/// </summary>
		/// <param name="userID">The UserID of the <see cref="User"/> to filter based on permissions</param>
		/// <param name="ignorePermissions">Specified whether not to ignore permissions.</param>
		/// <param name="cacheable">Specified whether or not to cache the data</param>
		/// <returns>ArrayList</returns>
		public static ArrayList GetFolders(int userID, bool ignorePermissions, bool cacheable, bool flush)
		{
		    CSContext csContext = CSContext.Current;
			ArrayList folders = new ArrayList();
			Hashtable foldersTable;

			// Get the Albums as a hashtable
			foldersTable = GetFolders(csContext, userID, ignorePermissions, cacheable, flush, false);

			foreach(Folder folder in foldersTable.Values)
				folders.Add( folder );

			folders.Sort(new SectionSorter());

			return folders;
		}

		public static ArrayList GetFoldersByGroupID(int groupID, bool ignorePermissions, bool cacheable, bool flush)
		{
			return GetFoldersByGroupID(groupID, Users.GetUser(true).UserID, ignorePermissions, cacheable, flush);
		}

		public static ArrayList GetFoldersByGroupID(int groupID, int userID, bool ignorePermissions, bool cacheable, bool flush) 
		{
		    CSContext csContext = CSContext.Current;
			ArrayList folders = new ArrayList();
			Hashtable forumsTable;

			// Get the ForumGroups as a hashtable
			forumsTable = GetFolders(csContext, userID, ignorePermissions, cacheable, flush, false);

			// Convert the hashtable to an arraylist
			foreach(Folder folder in forumsTable.Values)
				if (folder.GroupID == groupID)
					folders.Add( folder );

			// Sort the galleries
			folders.Sort(new SectionSorter());

			return folders;
		}

		public static void ExpireFoldersCache(int sectionID)
		{
			ExpireFoldersCache();
		}

		public static void ExpireFoldersCache()
		{
			CSCache.Remove(string.Format("Folders-Site:{0}", CSContext.Current.SiteSettings.SettingsID));
		}

		public static Hashtable GetFolders(CSContext csContext, int userID, bool ignorePermissions, bool cacheable, bool flush, bool ignoreLanguageFilter)
		{
			Hashtable unfilteredFolders;
			CSContext cntx = CSContext.Current;
			User user = cntx.User;

			string cacheKey = string.Format("Folders-Site:{0}", cntx.SiteSettings.SettingsID);
			string localKey = string.Format("FoldersForUser:{0}:{1}",ignorePermissions,ignoreLanguageFilter);

#if DEBUG_NOCACHE
            cacheable = false;
#endif

			if(flush)
			{
				CSCache.Remove(cacheKey);
				csContext.Items[localKey] = null;
			}

			// See if this has already been requested
			unfilteredFolders = csContext.Items[localKey] as Hashtable;
			if(unfilteredFolders != null)
				return unfilteredFolders;

			// Ensure it's not in the cache
			if(!cacheable)
				CSCache.Remove(cacheKey);

			// Have we already fetched for this request?
			unfilteredFolders = CSCache.Get(cacheKey) as Hashtable;

			// Get the albums if it is not in the cache
			if(unfilteredFolders == null)
			{
				unfilteredFolders = FileGalleryDataProvider.Instance().GetFolders(true);

				// Cache if we can
				if(cacheable)
					CSCache.Insert(cacheKey, unfilteredFolders, 15 * CSCache.MinuteFactor);
			} 

			if (!ignoreLanguageFilter && !ignorePermissions)
				unfilteredFolders = Sections.FilterByLanguage(unfilteredFolders, csContext);

			// Are we ignoring permissions?
			if(ignorePermissions)
			{
				csContext.Items[localKey] = unfilteredFolders;
				return unfilteredFolders;
			}

			// We need to create a new hashtable
			Hashtable folders = new Hashtable();

			// Filter the list of blogs to only show blogs this user 
			// is allowed to see
			foreach(Folder folder in unfilteredFolders.Values)
			{
				// The forum is added if the user can View, Read
				if( Permissions.ValidatePermissions( folder, Permission.View, user ))
				{
					if(folder.IsActive || user.IsFileAdministrator)
						folders.Add(folder.ApplicationKey, folder);
				}
			}

			// Insert into request cache
		    csContext.Items[localKey] = folders;

			return folders;
		}

		public static int GetFolderID(string applicationKey)
		{
			if(applicationKey == string.Empty)
				return -1;
			else
				return GetFolder(applicationKey).SectionID;
		}


		#endregion

		#region Folder Groups

		public static Group GetFolderGroup(int groupID, bool cacheable, bool ignorePermissions)
		{
			ArrayList folderGroups = GetFolderGroups(cacheable, ignorePermissions, false);
			foreach(Group fg in folderGroups)
				if(fg.GroupID == groupID)
					return fg;
			return null;
		}

		public static ArrayList GetFolderGroups(bool cacheable, bool ignorePermissions, bool flush)
		{
			return GetFolderGroups(Users.GetUser(true).UserID, cacheable, ignorePermissions, flush);
		}

		public static ArrayList GetFolderGroups(int userID, bool cacheable, bool ignorePermissions, bool flush)
		{
			ArrayList folderGroups = new ArrayList();
			Hashtable folderGroupsTable;

			// Get the ForumGroups as a hashtable
			//
			folderGroupsTable = GetFolderGroups(cacheable, ignorePermissions, userID, flush);

			// Hide forum groups based on the user's cookie
			//
			if(CSContext.Current.IsWebRequest)
				folderGroupsTable = Groups.HideGroups(folderGroupsTable);

			// Convert the hashtable to an arraylist
			//
			foreach(Group fg in folderGroupsTable.Values)
				folderGroups.Add( fg );

			// Sort the forum groups
			//
			folderGroups.Sort();

			return folderGroups;
		}

		private static Hashtable GetFolderGroups(bool cacheable, bool ignorePermissions, int userID, bool flush) 
		{
			CSContext cntx = CSContext.Current;
			int settingsID = cntx.SiteSettings.SettingsID;
			string cacheKey = string.Format("AllFolderGroups-{0}",settingsID);
			Hashtable unfilteredFolderGroups;
			Hashtable folderGroups;

			if(flush)
			{
				cntx[cacheKey] = null;
				CSCache.Remove(cacheKey);
			}

			// Evict item from cache if not cacheable
			//
			if (!cacheable)
				CSCache.Remove(cacheKey);

			// Get the raw forum groups
			//
			unfilteredFolderGroups = CSCache.Get(cacheKey) as Hashtable;
			if(unfilteredFolderGroups == null) 
			{
				unfilteredFolderGroups = CommonDataProvider.Instance().GetGroups(ApplicationType.FileGallery, false);

				if (cacheable)
					CSCache.Insert(cacheKey,unfilteredFolderGroups,CSCache.MinuteFactor * 15);
			} 

			// Are we ignoring permissions?
			//
			if(ignorePermissions)
				return unfilteredFolderGroups;

			// We need to create a new hashtable
			//
			folderGroups = new Hashtable();

			// Filter the list of forum groups to only show forums groups
			// this user is allowed to see, i.e. if all the forums in this
			// group are private and the user is not allowed to see them
			//
			foreach (Group f in unfilteredFolderGroups.Values) 
			{
				// Get the associated forums
				//
				if (!cacheable) 
					folderGroups.Add(f.GroupID, f);
				else if (GetFoldersByGroupID(f.GroupID, userID, ignorePermissions, cacheable, false).Count > 0)
					folderGroups.Add(f.GroupID, f);
			}

			return folderGroups;
		}

		#endregion

	}
}
