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

using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Xml;
using CommunityServer;
using CommunityServer.Components;
using CommunityServer.Configuration;

namespace CommunityServer.Files.Components
{
	/// <summary>
	/// Summary description for FileGalleryDataProvider.
	/// </summary>
	public abstract class FileGalleryDataProvider
	{

		public static readonly string FileGalleryDataProviderName = "FileGalleryDataProvider";

		#region Instance

		private static FileGalleryDataProvider _defaultInstance = null;

		static FileGalleryDataProvider()
		{
			CreateDefaultCommonProvider();
		}

		/// <summary>
		/// Returns an instance of the user-specified data provider class.
		/// </summary>
		/// <returns>An instance of the user-specified data provider class.  This class must inherit the
		/// CommonDataProvider interface.</returns>
		public static FileGalleryDataProvider Instance() 
		{
			return _defaultInstance;
		}

		public static FileGalleryDataProvider Instance (Provider dataProvider) 
		{
			FileGalleryDataProvider fdp = CSCache.Get(dataProvider.Name) as FileGalleryDataProvider;
			if(fdp == null)
			{
				fdp = DataProviders.Invoke(dataProvider) as FileGalleryDataProvider;
				CSCache.Max(dataProvider.Name,fdp);
			}
			return fdp;
		}

		/// <summary>
		/// Creates the Default CommonDataProvider
		/// </summary>
		private static void CreateDefaultCommonProvider()
		{
			// Get the names of the providers
			//
			CSConfiguration config = CSConfiguration.GetConfig();

			// Read the configuration specific information
			// for this provider
			//
			Provider sqlForumsProvider = (Provider) config.Providers[FileGalleryDataProviderName];

			// Read the connection string for this provider
			//
            
			_defaultInstance = DataProviders.CreateInstance(sqlForumsProvider) as FileGalleryDataProvider;
		}
        
		#endregion

		public abstract int GetRandomSectionID();
		public abstract Hashtable GetFolders(bool mergePermissions);
		public abstract void UpdateEntryCategories(int folderID, int postID, string[] categoryList);
		public abstract ArrayList GetEntryCategories(int postID);
		public abstract void CreateEntry(Entry entry);
		public abstract void CreateEntryData(Entry entry, PostAttachment pictureData);
		public abstract void DeleteEntryData(int postID);
		public abstract void UpdateEntry(Entry entry, int editedByUserID);
		public abstract void DeleteEntry(int sectionID, int threadID);
		public abstract void DeletePost(int postID, int userID);
		public abstract ThreadSet GetComments(FileGalleryThreadQuery query);
		public abstract ThreadSet GetEntries(FileGalleryThreadQuery query);
		public abstract Entry GetEntry(int postID, int userID);
		public abstract int GetRandomPostID(int sectionID, int categoryID);
		public abstract UserDownloadSet GetUserDownloads(int postID, DateTime beginDate, DateTime endDate, int pageIndex, int pageSize);
//		public abstract PostAttachment GetEntryData(int postID, int userID, bool logDownload);
		public abstract ArrayList GetComments(int postID, bool allowUnapproved);
		public abstract void CreateComment(EntryComment comment);
		public abstract void UpdateComment(EntryComment comment, int userID, string editNotes);
		public abstract ArrayList GetFileGalleryPermissions(int id);
		public abstract bool ApprovePost(int postID, int userIDApprovedBy);
		public abstract int GetEntrySortOrder(int folderID, int categoryID, int postID, EntriesSortBy sortBy);
		public abstract PostSet SearchReindexPosts(int setsize, int settingsID);
		public abstract ThreadSet SearchIndexPosts (int setsize, FileGalleryThreadQuery query);
//		public abstract SearchResultSet GetSearchResults(SearchQuery query, SearchTerms terms);
		public abstract void LogDownload(int entryID, int userID);

		public abstract ArrayList GetFoldersToModerate(int userID);
		public abstract PostSet GetEntriesToModerate(int sectionID, int pageIndex, int pageSize, int sortBy, int sortOrder, int userID, bool returnRecordCount);

		#region Populate

		public static void PopulateUserDownloadFromIDataReader(IDataReader dr, ref UserDownload ud)
		{
			ud.User = CommonDataProvider.cs_PopulateUserFromIDataReader(dr);
			ud.LatestDownloadDate = (DateTime) dr["LatestDownloadDate"];
			ud.TotalDownloads = (int) dr["TotalDownloads"];
			ud.PostID = (int) dr["PostID"];
		}

		public static void PopulateFolderFromIDataReader(IDataReader dr, ref Folder folder)
		{
			folder.SectionID =					(int) dr["SectionID"];
			folder.ParentID =					(int) dr["ParentID"];
			folder.GroupID =					(int) dr["GroupID"];
			folder.DateCreated =				(DateTime) dr["DateCreated"];
			folder.Description =				(string) dr["Description"];
			folder.Name =						(string) dr["Name"];
			folder.NewsgroupName =				(string) dr["NewsgroupName"];
			folder.IsModerated =				Convert.ToBoolean(dr["IsModerated"]);
			folder.DefaultThreadDateFilter =	(ThreadDateFilterMode) dr["DaysToView"];
			folder.IsActive =					Convert.ToBoolean(dr["IsActive"]);
			folder.IsSearchable =				Convert.ToBoolean(dr["IsSearchable"]);
			folder.SortOrder =					(int) dr["SortOrder"];
			folder.DisplayMask =				(byte[]) dr["DisplayMask"];
			folder.TotalPosts =				(int) dr["TotalPosts"];
			folder.TotalThreads =				(int) dr["TotalThreads"];
			folder.MostRecentPostAuthor =		(string) dr["MostRecentPostAuthor"];
			folder.MostRecentPostSubject =		(string) dr["MostRecentPostSubject"];
			folder.MostRecentPostAuthorID =	(int) dr["MostRecentPostAuthorID"];
			folder.MostRecentPostID =			(int) dr["MostRecentPostId"];
			folder.MostRecentThreadID =		(int) dr["MostRecentThreadId"];
			folder.MostRecentThreadReplies =	(int) dr["MostRecentThreadReplies"];
			folder.MostRecentPostDate =		(DateTime) dr["MostRecentPostDate"];
			folder.EnableAutoDelete =			Convert.ToBoolean(dr["EnableAutoDelete"]);
			folder.EnablePostStatistics =		Convert.ToBoolean(dr["EnablePostStatistics"]);
			folder.AutoDeleteThreshold =		(int) dr["AutoDeleteThreshold"];
			folder.EnableAnonymousPosting =	Convert.ToBoolean(dr["EnableAnonymousPosting"]);
			folder.ForumType =					(ForumType) dr["ForumType"];
			folder.NavigateUrl =				(string) dr["Url"];
			folder.DefaultLanguage = dr["DefaultLanguage"] as string;

			folder.ApplicationKey = dr["ApplicationKey"] as string;

			SerializerData data = CommonDataProvider.PopulateSerializerDataIDataRecord(dr, SerializationType.Section);
			folder.SetSerializerData(data);

			folder.ApplicationType = (ApplicationType) (Int16)dr["ApplicationType"];

			try 
			{
				folder.PostsToModerate = (int) dr["PostsToModerate"];
			} 
			catch {}
		}

		public static Entry PopulateEntryFromIDataRow(DataRow dr, DataRelation relationShip ,bool populateThreadSet, bool populatePost, bool populateAttachmentMetaData, bool populateDownloads) 
		{

			Entry entry = new Entry();

			// Populate picture
			//
			entry.SectionID =				 (int) dr["SectionID"];
			entry.PostID =				 (int) dr["PostID"];
			entry.Subject =                (string) dr["Subject"];
			entry.FormattedBody =			 (string) dr["FormattedBody"];
			entry.Body =                   (string) dr["Body"];
			entry.PostDate =               (DateTime) dr["PostDate"];
			entry.ThreadDate =             (DateTime) dr["ThreadDate"];
			entry.ThreadID				= Convert.ToInt32(dr["ThreadID"]);
			entry.Username =					dr["PostAuthor"].ToString().Trim().Length > 0 ? (string) dr["PostAuthor"] : (string) dr["ThreadPostAuthor"];
			entry.IsApproved				= Convert.ToBoolean(dr["IsApproved"]);
			entry.IsLocked =               (bool) dr["IsLocked"];
			entry.Views =                  (int) dr["TotalViews"];
			entry.AuthorID =               (int) dr["UserID"];
 		    //populate the post UserID as well as the IThread AuthorID
            entry.UserID =                  (int)dr["UserID"];
            entry.RatingSum =               (int)dr["RatingSum"];
			entry.TotalRatings =           (int) dr["TotalRatings"];
			entry.StickyDate =             (DateTime) dr["StickyDate"];
			entry.IsSticky =               (bool) dr["IsSticky"];
			entry.SortOrder =				(int) dr["SortOrder"];
			entry.SettingsID =			(int) dr["SettingsID"];
			entry.Points =					(int)dr["PostPoints"];

			if (populateDownloads && dr["Downloads"] != DBNull.Value)
				entry.Downloads =			(int) dr["Downloads"];

			SerializerData data = CommonDataProvider.PopulateSerializerDataFromDataRow(dr, SerializationType.Post);
			entry.SetSerializerData(data);

			// Fields for ThreadSet
			if (populateThreadSet)
			{
				entry.Replies =                (int) dr["TotalReplies"];
				entry.MostRecentPostID =       (int) dr["MostRecentPostID"];
				entry.MostRecentPostAuthor =   (string) dr["MostRecentPostAuthor"];
				entry.MostRecentPostAuthorID = (int) dr["MostRecentPostAuthorID"];
				entry.Status =                 (ThreadStatus) dr["ThreadStatus"];
				entry.EmoticonID				= (int) dr["ThreadEmoticonID"];
			}

			// Fields for just a Post
			if (populatePost)
			{
				entry.Replies =                (int) dr["Replies"];
				//				entry.AttachmentFilename	= (string) dr["AttachmentFilename"];
				entry.PostLevel			= Convert.ToInt32(dr["PostLevel"]);
				entry.SortOrder			= Convert.ToInt32(dr["SortOrder"]);
				entry.UserHostAddress		= (string) dr["IPAddress"];
				entry.PostType			= (PostContentType) dr["PostType"];
				entry.EmoticonID			= (int) dr["EmoticonID"];
			}

			entry.AttachmentFilename = dr["AttachmentFileName"] as string;
			if(entry.AttachmentFilename != null && populateAttachmentMetaData)
				entry.Attachment = CommonDataProvider.PopulatePostAttachmentMetaDataFromIDataRow(dr);

			DataRow[] categories = dr.GetChildRows(relationShip);
			if(categories != null && categories.Length > 0)
			{
				entry.Categories = new string[categories.Length];
				for(int i = 0; i<categories.Length; i++)
				{
					entry.Categories[i] = categories[i]["Name"] as string;
				}
			}

			return entry;
		}

		public static Entry PopulateEntryFromIDataReader(IDataReader dr, bool populateThreadSet, bool populatePost, bool populateAttachmentMetaData, bool populateDownloads) 
		{
			Entry entry = new Entry();

			// Populate picture
			//
			entry.SectionID =				 (int) dr["SectionID"];
			entry.PostID =				 (int) dr["PostID"];
			entry.Subject =                (string) dr["Subject"];
			entry.FormattedBody =			 (string) dr["FormattedBody"];
			entry.Body =                   (string) dr["Body"];
			entry.PostDate =               (DateTime) dr["PostDate"];
			entry.ThreadDate =             (DateTime) dr["ThreadDate"];
			entry.ThreadID				= Convert.ToInt32(dr["ThreadID"]);
			entry.Username =					dr["PostAuthor"].ToString().Trim().Length > 0 ? (string) dr["PostAuthor"] : (string) dr["ThreadPostAuthor"];
			entry.IsApproved				= Convert.ToBoolean(dr["IsApproved"]);
			entry.IsLocked =               (bool) dr["IsLocked"];
			entry.Views =                  (int) dr["TotalViews"];
			entry.AuthorID =               (int) dr["UserID"];
		    //populate the post UserID as well as the IThread AuthorID
            entry.UserID =                  (int)dr["UserID"];
            entry.RatingSum =               (int)dr["RatingSum"];
			entry.TotalRatings =           (int) dr["TotalRatings"];
			entry.StickyDate =             (DateTime) dr["StickyDate"];
			entry.IsSticky =               (bool) dr["IsSticky"];
			entry.SortOrder =				(int) dr["SortOrder"];
			entry.SettingsID =			(int) dr["SettingsID"];
			entry.Points =					(int)dr["PostPoints"];

			if (populateDownloads && dr["Downloads"] != DBNull.Value)
				entry.Downloads =			(int) dr["Downloads"];

			SerializerData data = CommonDataProvider.PopulateSerializerDataIDataRecord(dr, SerializationType.Post);
			entry.SetSerializerData(data);

			// Fields for ThreadSet
			if (populateThreadSet)
			{
				entry.Replies =                (int) dr["TotalReplies"];
				entry.MostRecentPostID =       (int) dr["MostRecentPostID"];
				entry.MostRecentPostAuthor =   (string) dr["MostRecentPostAuthor"];
				entry.MostRecentPostAuthorID = (int) dr["MostRecentPostAuthorID"];
				entry.Status =                 (ThreadStatus) dr["ThreadStatus"];
				entry.EmoticonID				= (int) dr["ThreadEmoticonID"];
			}

			// Fields for just a Post
			if (populatePost)
			{
				entry.Replies =                (int) dr["Replies"];
//				entry.AttachmentFilename	= (string) dr["AttachmentFilename"];
				entry.PostLevel			= Convert.ToInt32(dr["PostLevel"]);
				entry.SortOrder			= Convert.ToInt32(dr["SortOrder"]);
				entry.UserHostAddress		= (string) dr["IPAddress"];
				entry.PostType			= (PostContentType) dr["PostType"];
				entry.EmoticonID			= (int) dr["EmoticonID"];
			}

			entry.AttachmentFilename = dr["AttachmentFileName"] as string;
			if(entry.AttachmentFilename != null && populateAttachmentMetaData)
				entry.Attachment = CommonDataProvider.PopulatePostAttachmentMetaDataFromIDataRecord(dr);

			return entry;
		}

		#endregion

		#region Helpers

		public static object ConvertCategoriesToXML(string[] Categories)
		{
			if(Categories == null || Categories.Length == 0)
				return DBNull.Value;

			StringWriter sw = new StringWriter();
			XmlTextWriter writer = new XmlTextWriter(sw);
			writer.WriteStartElement("Categories");
			foreach (string category in Categories)
			{
				writer.WriteElementString("Category", category);
			}
			writer.Close();
			return sw.ToString();
		}

		#endregion

	}
}
