using System;
using System.Collections;
using System.IO;
using System.Security;
using System.Web.Services;
using System.Web.Services.Protocols;
using CommunityServer.Components;
using System.Data;

namespace CommunityServer.Files.Components
{
	/// <summary>
	/// Summary description for FileGalleryService.
	/// </summary>
	
	[WebService(Name="FileGalleryService",
	Description="Community Server :: File Gallery Posting Web Service", Namespace="http://communityserver.org/filegallery/services/posts/")]
	public class FileGalleryService : CSWebServiceBase
	{
		public FileGalleryService() { }

		public struct FileGalleryPost
		{
			public int PostID;
			public string Subject;
			public string Description;
			public string Filename;
			public string ContentType;
			public long FileSize;
			public byte[] FileData;
			public string[] Categories;
		}

		public struct CurrentFolder
		{
			public int ID;
			public string Name;
			public int EntryCount;
			public CurrentFolder[] CurrentFolders;

		}

		[WebMethod(MessageName="Create",Description="Creates a new file gallery post",EnableSession=false)]
		[SoapHeader("Credentials")]
		public bool Create(FileGalleryPost post)
		{
			this.LoginSetSection();

			Components.Entry entry = new Components.Entry();
			entry.Username = CurrentUser.Username;
			entry.SectionID = currentFolder.SectionID;
			entry.ParentID = 0;
			// entry.FileGalleryPostType
			entry.PostID = -1;

			entry.Subject = post.Subject;
			entry.Body = post.Description;
			entry.Excerpt = "";
			entry.PostType = PostContentType.HTML;
			entry.FormattedBody = null;

			entry.PostDate = DateTime.Now;
			entry.UserTime = UserTime.ConvertToUserTime(entry.PostDate);
			entry.Name = "";

			// TESTING
			string fileNameAndPath = post.Filename;
			string fileName = String.Empty;

			if( fileNameAndPath.LastIndexOf(@"\") > 0 )
				fileName = fileNameAndPath.Substring(fileNameAndPath.LastIndexOf(@"\")+1);
			else
				fileName = fileNameAndPath;

			string contentType = "image/";
			if( post.ContentType == null || post.ContentType.Length == 0 )
			{
				if( fileName.LastIndexOf(@".") > 0 )
					contentType += fileName.Substring(fileName.LastIndexOf(@"."));
				else
					contentType += "x";
			}
			else
				contentType = post.ContentType;

			Entries.Create(currentFolder.SectionID, entry, new Guid());

			return true;

		}

		[WebMethod(MessageName="Update",Description="Update an existing post",EnableSession=false)]
		[SoapHeader("Credentials")]
		public void Update(FileGalleryPost post )
		{
			this.LoginSetSection();

			Components.Entry entry = new Components.Entry();
			entry.Username = CurrentUser.Username;
			entry.SectionID = currentFolder.SectionID;
			entry.ParentID = 0;
			entry.PostID = -1;

			entry.Subject = post.Subject;
			entry.Body = post.Description;
			entry.Excerpt = "";
			entry.PostType = PostContentType.HTML;
			entry.FormattedBody = null;

			entry.PostDate = DateTime.Now;
			entry.UserTime = UserTime.ConvertToUserTime(entry.PostDate);
			entry.Name = "";

			Entries.Update(entry, new Guid());
		}

		[WebMethod(MessageName="Delete",Description="Deletes a post by the PostID",EnableSession=false)]
		[SoapHeader("Credentials")]
		public void Delete(int postID)
		{
			LoginSetSection();

			Components.Entry entry = Components.Entries.GetEntry(postID, false);
			if(entry == null)
				throw new ArgumentOutOfRangeException("Post does not exist");

			if(entry.SectionID == this.currentFolder.SectionID)
			{
				Components.Entries.Delete(entry);
				return;
			}
			throw new SecurityException("PostID does not match current file gallery");
		}

		[WebMethod(MessageName="GetFolders",Description="Returns a list of folder names for the current file gallery",EnableSession=false)]
		[SoapHeader("Credentials")]
		public string[] GetFolders()
		{
			LoginSetSection();

			Entry entry = Entries.GetEntry(currentFolder.SectionID, false);
			ArrayList al = Entries.GetEntryCategories(entry);
			string[] sa = new string[al.Count];
			for(int i = 0; i<al.Count; i++)
			{
                
				sa[i] = ((PostCategory)al[i]).Name;
			}

			return sa;
		}

		private CurrentFolder CreateFolderFromPostCategory(PostCategory category )
		{
			CurrentFolder folder = new CurrentFolder();
			folder.ID = category.CategoryID;
			folder.Name = category.Name;
			folder.EntryCount = category.TotalThreads;

			return folder;
		}

		[WebMethod(MessageName="GetFolderHeirarchy", Description="Returns a heirarchical list of Folders in the current file gallery", EnableSession=false)]
		[SoapHeader("Credentials")]
		public CurrentFolder[] GetFolderHeirarchy()
		{
			this.LoginSetSection();

			ArrayList rawFolders = Entries.GetEntryCategories(Entries.GetEntry(currentFolder.SectionID), false);
		
			PostCategory.SortBy = currentFolder.CategorySortBy;
			rawFolders.Sort();

			ArrayList folders = new ArrayList();
			ArrayList validParents = new ArrayList();
				validParents.Add(0);
			foreach(PostCategory c in rawFolders)
				validParents.Add(c.CategoryID);

			foreach(PostCategory c in rawFolders)
			{
				if(!validParents.Contains(c.ParentID))
					c.ParentID = 0;
				folders.Add(c);
			}

			PostCategory root = new PostCategory();
			root.Name = currentFolder.Name;
			root.TotalThreads = currentFolder.TotalThreads;
			root.IsEnabled = true;

			folders.Add(root);

			DataTable dt = CADataConverter.ToDataTable(folders, (typeof(PostCategory)));

			foreach (DataRow dr in dt.Rows)
			{
				if(dr["CategoryID"].ToString() == "0")
				{
					dr["ParentID"] = DBNull.Value;
				}
			}

			DataSet ds = new DataSet();
			ds.Tables.Add(dt);
			ds.Relations.Add("NodeRelation", ds.Tables[0].Columns["CategoryID"], ds.Tables[0].Columns["ParentID"]);

			CurrentFolder rootFolder = new CurrentFolder();
			rootFolder.CurrentFolders = new CurrentFolder[] { };

			foreach(DataRow dr in ds.Tables[0].Rows)
			{
				if(dr.IsNull("ParentID"))
				{   
					rootFolder.ID = Int32.Parse(dr["CategoryID"].ToString());
					rootFolder.Name = dr["Name"].ToString();
					rootFolder.EntryCount = Int32.Parse(dr["TotalThreads"].ToString());

					//Pass the root to the tree builder
					PopulateFolder(dr, ref rootFolder);
				}
			}

			return rootFolder.CurrentFolders;
		}

		private void PopulateFolder( DataRow dbRow, ref CurrentFolder folder )
		{
			ArrayList folders = new ArrayList();
			foreach (DataRow childRow in dbRow.GetChildRows("NodeRelation"))
			{ 
				CurrentFolder childFolder = new CurrentFolder();
				childFolder.ID = Int32.Parse(childRow["CategoryID"].ToString());
				childFolder.Name = childRow["Name"].ToString();
				childFolder.EntryCount = Int32.Parse(childRow["TotalThreads"].ToString());

				PopulateFolder(childRow, ref childFolder);
				folders.Add(childFolder);
			}

			folder.CurrentFolders = (CurrentFolder[])folders.ToArray(typeof(CurrentFolder));
		}

		[WebMethod(MessageName="Folders",Description="Returns a list of file galleries the current user has post access to",EnableSession=false)]
		[SoapHeader("Credentials")]
		public string[] Folders()
		{
			Login();

			ArrayList folders = CommunityServer.Files.Components.Folders.GetFolders();
			folders = Sections.FilterByAccessControl(folders,Permission.Post,CurrentUser);
			string[] folderList = new string[folders.Count];
			for(int i = 0; i<folders.Count; i++)
				folderList[i] = ((Folder)folders[i]).ApplicationKey;

			return folderList;

		}

		[WebMethod]
		[SoapHeader("Credentials")]
		public FileGalleryPost[] GetFiles()
		{
			this.LoginSetSection();

			FileGalleryThreadQuery query = new FileGalleryThreadQuery();
			query.SectionID = currentFolder.SectionID;
			query.ApplicationPostType = FileGalleryPostType.File;
			query.PageSize = 100;

			ArrayList entries = Entries.GetEntries(query).Threads;
			FileGalleryPost[] posts = new FileGalleryPost[entries.Count];

			for(int i = 0 ; i < entries.Count ; i++)
				posts[i] = EntryToFolderPost((Entry)entries[i]);

			return posts;
		}

		[WebMethod]
		[SoapHeader("Credentials")]
		public FileGalleryPost GetEntry(int entryID )
		{
			Entry entry = Entries.GetEntry(entryID);
			return EntryToFolderPost(entry);
		}

		[WebMethod(MessageName="GetFolderEntries", Description="Returns a list of files in the specified folder in the current folder group", EnableSession=false)]
		[SoapHeader("Credentials")]
		public FileGalleryPost[] GetFolderEntries( int folderID )
		{
			this.LoginSetSection();

			FileGalleryThreadQuery query = new FileGalleryThreadQuery();
			query.SectionID = currentFolder.SectionID;
			query.CategoryID = folderID;
			query.ApplicationPostType = FileGalleryPostType.File;
			query.IncludeCategories = true;
			query.PageSize = 100;

			ArrayList entries = Entries.GetEntries(query).Threads;
			FileGalleryPost[] posts = new FileGalleryPost[entries.Count];
			
			for(int i = 0 ; i < entries.Count ; i++)
				posts[i] = EntryToFolderPost((Entry)entries[i]);

			return posts;
		}

		private FileGalleryPost EntryToFolderPost(Entry entry)
		{
			PostAttachment fileData = Entries.GetEntryData(entry.PostID);
			FileGalleryPost post = new FileGalleryPost();

			post.PostID = entry.PostID;
			post.Subject = entry.Subject;
			post.Description = entry.FormattedBody;
			post.Filename = fileData.FileName;
			post.FileData = new byte[fileData.Content.Length];
			fileData.Content.Read(post.FileData, 0, (int)fileData.Content.Length);
			post.FileSize = fileData.Content.Length;
			if( entry.Categories != null && entry.Categories.Length > 0 )
				post.Categories = entry.Categories;

			return post;
		}

		protected override void AllocateSection()
		{
			if(Globals.IsNullorEmpty(Credentials.SectionName))
				throw new SecurityException("Invalid (or unsupplied) Blogname");

			ArrayList folders = CommunityServer.Files.Components.Folders.GetFolders();

			foreach (CommunityServer.Files.Components.Folder folder in folders)
			{
				if (folder.ApplicationKey == Credentials.SectionName.ToLower())
				{
					currentFolder = folder;
				}
			}

			if(currentFolder == null)
				throw new Exception("The requested file gallery does not exist");

			Permissions.AccessCheck(currentFolder,Permission.Post,CurrentUser);
			
			return;
		}

		protected Folder currentFolder = null;
	}
}