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

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.Galleries.Components
{
	/// <summary>
	/// Summary description for GalleryService.
	/// </summary>
	[ WebService(Name="GalleryService",
	Description="Community Server :: Photo Posting Web Service",Namespace="http://communityserver.org/gallery/services/posts/")]
	public class GalleryService : CSWebServiceBase
	{
		public GalleryService()
		{
		}

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

		public struct Album
		{
			public int ID;
			public string Name;
			public int PhotoCount;
			public Album[] Albums;
		}

		#region Gallery Post
		#endregion

		#region Service Methods
		[WebMethod(MessageName="Create",Description="Creates a new gallery post",EnableSession=false)]
		[SoapHeader("Credentials")]
		public bool Create(GalleryPost post)
		{
			LoginSetSection();

			Components.GalleryPost gp = new Components.GalleryPost();
			gp.Username = CurrentUser.Username;
			gp.SectionID = this.currentGallery.SectionID;
			gp.ParentID = 0;
			gp.GalleryPostType = GalleryPostType.Image;
			post.PostID = -1;

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


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

			// Create the picture in the database
			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;

			GalleryPosts.CreatePicture(currentGallery.SectionID, gp, new PostAttachment( fileName, contentType, new MemoryStream(post.PictureData)));

			return true;
		}

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

			Components.GalleryPost gp = new Components.GalleryPost();
			gp.Username = CurrentUser.Username;
			gp.SectionID = this.currentGallery.SectionID;
			gp.ParentID = 0;
			gp.GalleryPostType = GalleryPostType.Image;
			post.PostID = -1;

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


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

			// Create the picture in the database
			GalleryPosts.UpdatePicture(gp);
		}

		
		[WebMethod(MessageName="Delete",Description="Deletes a post by the PostID",EnableSession=false)]
		[SoapHeader("Credentials")]
		public void Delete(int postID)
		{
			LoginSetSection();
			Components.GalleryPost gp = Components.GalleryPosts.GetPicture(postID,false);
			if(gp == null)
				throw new ArgumentOutOfRangeException("Post does not exist");

			if(gp.SectionID == this.currentGallery.SectionID)
			{
				Components.GalleryPosts.DeletePicture(gp);
				return;
			}
			throw new SecurityException("PostID does not match current Gallery");
		}

		
		[WebMethod(MessageName="GetCategories",Description="Returns a list of category names for the current Gallery",EnableSession=false)]
		[SoapHeader("Credentials")]
		public string[] GetCategories()
		{
			LoginSetSection();

			ArrayList al = GalleryPostCategories.GetCategories(currentGallery.SectionID,true,true,-1,false);
			string[] sa = new string[al.Count];
			for(int i = 0; i<al.Count; i++)
			{
                
				sa[i] = ((PostCategory)al[i]).Name;
			}

			return sa;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="category"></param>
		/// <returns></returns>
		private Album CreateAlbumFromPostCategory(PostCategory category )
		{
			Album album = new Album();
			album.ID = category.CategoryID;
			album.Name = category.Name;
			album.PhotoCount = category.TotalThreads;

			return album;
		}
		

		[WebMethod(MessageName="GetAlbumHeirarchy", Description="Returns a heirarchical list of Albums in the current gallery", EnableSession=false)]
		[SoapHeader("Credentials")]
		public Album[] GetAlbumHeirarchy()
		{
			LoginSetSection();

			ArrayList rawCategories = PostCategories.GetCategories(currentGallery.SectionID, false, false, -1);

			PostCategory.SortBy = currentGallery.CategorySortBy;
			rawCategories.Sort() ;

			//Search for disabled (orphanded) parent nodes, removing them and moving their children to the root
			ArrayList categories = new ArrayList();
			ArrayList validParents = new ArrayList();
				validParents.Add(0);	
			foreach(PostCategory c in rawCategories)
				validParents.Add(c.CategoryID);

			foreach(PostCategory c in rawCategories)
			{
				if(!validParents.Contains(c.ParentID))
					c.ParentID = 0;
					
				categories.Add(c);
			}
			
			PostCategory root = new PostCategory();
			root.Name = currentGallery.Name;
			root.TotalThreads = currentGallery.PostCount;
			root.IsEnabled = true;

			categories.Add(root);

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

			foreach(DataRow dbRow in dt.Rows)
			{
				if(dbRow["CategoryID"].ToString() == "0")
				{
					dbRow["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"]);

			Album rootAlbum = new Album();
			rootAlbum.Albums = new Album[] {};
			//Loop through categories to find the root
			foreach(DataRow dbRow in ds.Tables[0].Rows)
			{
				if(dbRow.IsNull("ParentID"))
				{   
					rootAlbum.ID = Int32.Parse(dbRow["CategoryID"].ToString());
					rootAlbum.Name = dbRow["Name"].ToString();
					rootAlbum.PhotoCount = Int32.Parse(dbRow["TotalThreads"].ToString());

					//Pass the root to the tree builder
					PopulateAlbum(dbRow, ref rootAlbum);
				}
			}

			return rootAlbum.Albums;
		}

		
		/// <summary>
		/// An internal method that is used to recursively build the Album tree structure
		/// </summary>
		/// <param name="dbRow"></param>
		/// <param name="album"></param>
		private void PopulateAlbum( DataRow dbRow, ref Album album )
		{
			ArrayList albums = new ArrayList();
			foreach (DataRow childRow in dbRow.GetChildRows("NodeRelation"))
			{ 
				Album childAlbum = new Album();
				childAlbum.ID = Int32.Parse(childRow["CategoryID"].ToString());
				childAlbum.Name = childRow["Name"].ToString();
				childAlbum.PhotoCount = Int32.Parse(childRow["TotalThreads"].ToString());

				PopulateAlbum(childRow, ref childAlbum);
				albums.Add(childAlbum);
			}

			album.Albums = (Album[])albums.ToArray(typeof(Album));
		}

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

			ArrayList galleries = CommunityServer.Galleries.Galleries.GetGalleries(true,false);
			galleries = Sections.FilterByAccessControl(galleries,Permission.Post,CurrentUser);
			string[] galleryList = new string[galleries.Count];
			for(int i = 0; i<galleries.Count; i++)
				galleryList[i] = ((Gallery)galleries[i]).ApplicationKey;

			return galleryList;

		}


		[WebMethod]
		[SoapHeader("Credentials")]
		public GalleryPost[] GetPictures()
		{
			LoginSetSection();

			GalleryThreadQuery query = new GalleryThreadQuery();
			query.SectionID = currentGallery.SectionID;
			query.ApplicationPostType = GalleryPostType.Image;
			query.PageSize = 100;

			ArrayList pictures = GalleryPosts.GetPictures(query).Threads;
			GalleryPost[] posts = new GalleryPost[pictures.Count];

			for(int i = 0 ; i < pictures.Count ; i++)
				posts[i] = PictureToGalleryPost((Components.GalleryPost)pictures[i]);

			return posts;
		}

	
		[WebMethod]
		[SoapHeader("Credentials")]
		public GalleryPost GetPicture(int pictureID )
		{
			Components.GalleryPost galleryPost = GalleryPosts.GetPicture(pictureID);
			return PictureToGalleryPost(galleryPost);
		}
		
		
		[WebMethod(MessageName="GetAlbumPictures", Description="Returns a list of Photos in the specified album in the current gallery", EnableSession=false)]
		[SoapHeader("Credentials")]
		public GalleryPost[] GetAlbumPictures( int albumID )
		{
			LoginSetSection();

			GalleryThreadQuery query = new GalleryThreadQuery();
			query.SectionID = currentGallery.SectionID;
			query.CategoryID = albumID;
			query.ApplicationPostType = GalleryPostType.Image;
			query.IncludeCategories = true;
			query.PageSize = 100;

			ArrayList pictures = GalleryPosts.GetPictures(query).Threads;
			GalleryPost[] posts = new GalleryPost[pictures.Count];

			for(int i = 0 ; i < pictures.Count ; i++)
				posts[i] = PictureToGalleryPost((Components.GalleryPost)pictures[i]);

			return posts;
		}

		[WebMethod(MessageName="GetSupportedExtensions", Description="Returns a list of file extensions that are allowed to be uploaded", EnableSession=false)]
		public string[] GetSupportedFileExtensions()
		{
			ArrayList extensions = new ArrayList();
//			CSContext context = CSContext.Current;
//			CommunityServer.Galleries.Components.GalleryImageSettings
//
//			HashTable settings = CommunityServer.Components.SiteSettingsManager.GetSiteSettings(
//			if( settings != null )
//			{
//				settings
//			}

			return (string[])extensions.ToArray(typeof(String));
		}
		#endregion

		#region Protected Methods
		protected override void AllocateSection() {


			if(Globals.IsNullorEmpty(Credentials.SectionName))
				throw new SecurityException("Invalid (or unsupplied) Blogname");


			ArrayList galleries = CommunityServer.Galleries.Galleries.GetGalleries();
			

			foreach( Gallery gallery in galleries ) {
				if( gallery.ApplicationKey == Credentials.SectionName.ToLower() ) {
					currentGallery = gallery;
					break;
				}
			}

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

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

		#endregion

		#region Private Methods

		private GalleryPost PictureToGalleryPost(Components.GalleryPost galleryPost)
		{
			PostAttachment pictureData = GalleryPosts.GetPictureData(galleryPost);
			GalleryPost post = new GalleryPost();

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

			return post;
		}
		
		#endregion

		#region Private Data
		protected Gallery currentGallery = null;
		#endregion
	}
}
