using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Xml.Serialization;
using Orciid.Core;

namespace Orciid.WebServices
{
	public class RemoteCollectionService : OrciidWebService
	{
		private const string SESSION_USER = "CurrentUser";
		private const string SESSION_COLLECTION_ID = "RemoteCollectionID";
		private const string SESSION_SHARE_ENTRY = "ShareEntry";

		public RemoteCollectionService()
		{
			//CODEGEN: This call is required by the ASP.NET Web Services Designer
			InitializeComponent();
		}

		#region Component Designer generated code
		
		//Required by the Web Services Designer 
		private IContainer components = null;
				
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if(disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);		
		}
		
		#endregion

		[WebMethod(EnableSession=true)]
		public bool Login(string login, string pwd, int cid)
		{
			CheckSSLRequirement(true);
			try
			{
				Orciid.Core.User user = Orciid.Core.User.GetByLogin(login, pwd);
				user.Activate(Context.Request.UserHostAddress);
				Collection coll = Collection.GetByID(cid);
				CollectionShareEntry entry = coll.FindValidShareEntry();
				if (entry == null)
					return false;
				Session[SESSION_SHARE_ENTRY] = entry;
				Session[SESSION_USER] = user;
				Session[SESSION_COLLECTION_ID] = cid;
				return true;
			}
			catch
			{
				return false;
			}
		}

		public struct CollectionInfo
		{
			public string title;
			public string description;
			public string usageagreement;
			[XmlElement("field", Type = typeof(FieldInfo))]
			public ArrayList fields;
		}

		public struct FieldInfo
		{
			public string label;
			public string name;
			public int type;
			public string dcelement;
			public string dcrefinement;
			public bool searchable;
			public bool keywordsearchable;
			public bool sortable;
			public bool browsable;
			public int shortview;
			public int mediumview;
			public int longview;
		}

		[WebMethod(EnableSession=true)]
		public CollectionInfo GetCollectionInfo()
		{
			CheckSSLRequirement(false);
			try
			{
				Orciid.Core.User user = (Orciid.Core.User)Session[SESSION_USER];
				int cid = (int)Session[SESSION_COLLECTION_ID];
				user.Activate(Context.Request.UserHostAddress);
				Collection coll = Collection.GetByID(cid);
				CollectionInfo result = new CollectionInfo();
				result.title = coll.Title;
				result.description = coll.Description;
				result.usageagreement = coll.UsageAgreement;
				result.fields = new ArrayList();
				foreach (Field f in coll.GetFields())
				{
					FieldInfo info = new FieldInfo();
					info.label = f.Label;
					info.name = f.Name;
					info.type = (int)f.Type;
					info.dcelement = f.DCElement;
					info.dcrefinement = f.DCRefinement;
					info.searchable = f.Searchable;
					info.keywordsearchable = f.KeywordSearchable;
					info.sortable = f.Sortable;
					info.browsable = f.Browsable;
					info.shortview = (int)f.ShortView;
					info.mediumview = (int)f.MediumView;
					info.longview = (int)f.LongView;
					result.fields.Add(info);
				}
				return result;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		[WebMethod(EnableSession=true)]
		public int GetImageCount()
		{
			CheckSSLRequirement(false);
			try
			{
				Orciid.Core.User user = (Orciid.Core.User)Session[SESSION_USER];
				int cid = (int)Session[SESSION_COLLECTION_ID];
				user.Activate(Context.Request.UserHostAddress);
				Collection coll = Collection.GetByID(cid);
				return coll.ImageCount;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		[WebMethod(EnableSession=true)]
		public string[] Search(string searchconditions)
		{
			CheckSSLRequirement(false);
			try
			{
				Orciid.Core.User user = (Orciid.Core.User)Session[SESSION_USER];
				int cid = (int)Session[SESSION_COLLECTION_ID];
				CollectionShareEntry entry = (CollectionShareEntry)Session[SESSION_SHARE_ENTRY];
				user.Activate(Context.Request.UserHostAddress);
				Collection coll = Collection.GetByID(cid);
				Orciid.Core.Search.SearchParameters sp = 
					new Orciid.Core.Search.SearchParameters(searchconditions);
				sp.collections.Clear();
				sp.collections.Add(coll);
				ImageIdentifier[] ids = Orciid.Core.Search.Execute(sp, entry.SearchResults, true);
				if (ids == null)
					return null;
				string[] result = new string[ids.Length];
				for (int i = 0; i < ids.Length; i++)
					result[i] = ids[i].ToString();
				return result;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		public struct ImageInfo
		{
			[XmlAttribute]
			public string id;
			[XmlAttribute]
			public DateTime created;
			[XmlAttribute]
			public DateTime modified;
			[XmlAttribute]
			public DateTime cacheuntil;
			[XmlAttribute]
			public DateTime expire;
			[XmlAttribute]
			public DateTime filedate;
			[XmlElement("fielddata", Type = typeof(FieldDataInfo))]
			public ArrayList fielddata;
		}

		public struct FieldDataInfo
		{
			[XmlAttribute]
			public string field;
			[XmlText]
			public string val;
		}

		private DateTime NewestDate(params DateTime[] dates)
		{
			DateTime newest = DateTime.MinValue;
			foreach (DateTime d in dates)
				if (d > newest)
					newest = d;
			return newest;
		}

		// Among characters less than 0x20, XML only allows 0x09, 0x0A, 0x0D
		// the XML serializer used by .NET 1.1 web services does not handle this 
		// and produces XML that the deserializer will not handle
		// This method removes all the invalid characters
		// See FogBugz case 260
		private string RemoveInvalidChars(string input)
		{
			if (input == null)
				return null;
			StringBuilder b = new StringBuilder(input.Length);
			foreach (char c in input)
				if (c >= '\u0020' || c == '\u0009' || c == '\u000A' || c == '\u000D')
					b.Append(c);
			return b.ToString();
		}

		[WebMethod(EnableSession=true)]
		public ImageInfo[] GetImageInfo(string[] ids)
		{
			CheckSSLRequirement(false);
			try
			{
				Orciid.Core.User user = (Orciid.Core.User)Session[SESSION_USER];
				int cid = (int)Session[SESSION_COLLECTION_ID];
				CollectionShareEntry entry = (CollectionShareEntry)Session[SESSION_SHARE_ENTRY];
				user.Activate(Context.Request.UserHostAddress);
				Collection coll = Collection.GetByID(cid);
				ArrayList imageids = new ArrayList();
				foreach (string id in ids)
					imageids.Add(ImageIdentifier.Parse(id));
				ArrayList images = coll.GetImagesByID(true, imageids);
				ArrayList result = new ArrayList();
				Field[] fields = coll.GetFields();
				foreach (Orciid.Core.Image image in images)
					if (image != null)
					{
						ImageInfo info = new ImageInfo();
						info.id = image.ID.ToString();
						info.created = image.CreatedDate;
						info.modified = image.ModifiedDate;
						info.cacheuntil = DateTime.Now + TimeSpan.FromDays(entry.CacheTimeSpan);
						info.expire = DateTime.Now + TimeSpan.FromDays(entry.ExpirationTimeSpan);
						info.filedate = NewestDate(
							image.GetResourceModificationDate(ImageSize.Full),
							image.GetResourceModificationDate(ImageSize.Medium),
							image.GetResourceModificationDate(ImageSize.Thumbnail));
						info.fielddata = new ArrayList();
						foreach (Field f in fields)
							foreach (string s in image[f].GetAll())
							{
								FieldDataInfo fdi = new FieldDataInfo();
								fdi.field = f.Name;
								fdi.val = RemoveInvalidChars(s);
								info.fielddata.Add(fdi);
							}
						result.Add(info);
					}
				return (ImageInfo[])result.ToArray(typeof(ImageInfo));
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}
	}
}
