using System;
using System.Collections;
using System.Data;

namespace Orciid.Core
{
	/// <summary>
	/// Access control entry for shared collection
	/// </summary>
	/// <remarks>
	/// When sharing a collection, several restrictions (user account, IP address range etc.) can
	/// be specified.  Objects of this class hold the information for one set of restrictions.
	/// </remarks>
	public class CollectionShareEntry
	{
		private int userid;
		private string subnet;
		private string mask;
		private int cachetimespan;
		private int expirationtimespan;
		private int searchresults;
		private int collectionid;
		private int id;

		internal CollectionShareEntry(int collid)
		{
			collectionid = collid;
			cachetimespan = 7;
			expirationtimespan = 14;
			searchresults = 1000;
		}

		internal static ArrayList GetForCollection(int collid)
		{
			ArrayList entries = new ArrayList();
			using (DBConnection conn = DBConnector.GetConnection())
			{
				Query query = new Query(conn,
					@"SELECT ID,UserID,Subnet,Mask,CacheTimeSpan,ExpirationTimeSpan,SearchResults 
					FROM RemoteCollectionAccess WHERE CollectionID={collectionid}");
				query.AddParam("collectionid", collid);
				DataTable table = conn.SelectQuery(query);
				foreach (DataRow row in table.Rows)
				{
					CollectionShareEntry entry = new CollectionShareEntry(collid);
					entry.id = conn.DataToInt(row["ID"], 0);
					entry.userid = conn.DataToInt(row["UserID"], 0);
					entry.subnet = conn.DataToString(row["Subnet"]);
					entry.mask = conn.DataToString(row["Mask"]);
					entry.cachetimespan = conn.DataToInt(row["CacheTimeSpan"], 0);
					entry.expirationtimespan = conn.DataToInt(row["ExpirationTimeSpan"], 0);
					entry.searchresults = conn.DataToInt(row["SearchResults"], 0);
					entries.Add(entry);
				}
			}
			return entries;
		}

		/// <summary>
		/// Store entry in database
		/// </summary>
		/// <remarks>
		/// After creating or changing a collection share entry, this method stores the
		/// new settings in the database.
		/// </remarks>
		public void Update()
		{
			Collection coll = Collection.GetByID(collectionid);
			if (coll == null)
				throw new CoreException("Collection not found");
			Orciid.Core.User.RequirePrivilege(Privilege.ModifyACL, coll);
			if (collectionid <= 0)
				throw new CoreException("CollectionShareEntry not associated with a collection");
			if (userid <= 0)
				throw new CoreException("CollectionShareEntry not associated with a user");
			if (subnet == null || mask == null)
				throw new CoreException("Subnet and/or Mask not set for CollectionShareEntry");
			using (DBConnection conn = DBConnector.GetConnection())
			{
				Query query;
				if (id == 0)
				{
					query = new Query(conn,
						@"INSERT INTO RemoteCollectionAccess 
						(CollectionID,UserID,Subnet,Mask,CacheTimeSpan,
						ExpirationTimeSpan,SearchResults) 
						VALUES ({collectionid},{userid},{subnet},{mask},{cachetimespan},
						{expirationtimespan},{searchresults})");
					query.AddParam("collectionid", collectionid);
					query.AddParam("userid", userid);
					query.AddParam("subnet", subnet);
					query.AddParam("mask", mask);
					query.AddParam("cachetimespan", cachetimespan);
					query.AddParam("expirationtimespan", expirationtimespan);
					query.AddParam("searchresults", searchresults);
					conn.ExecQuery(query);
					id = conn.LastIdentity("RemoteCollectionAccess");
				}
				else
				{
					query = new Query(conn,
						@"UPDATE RemoteCollectionAccess 
						SET UserID={userid},Subnet={subnet},Mask={mask},CacheTimeSpan={cachetimespan},
						ExpirationTimeSpan={expirationtimespan},SearchResults={searchresults} 
						WHERE ID={id}");
					query.AddParam("userid", userid);
					query.AddParam("subnet", subnet);
					query.AddParam("mask", mask);
					query.AddParam("cachetimespan", cachetimespan);
					query.AddParam("expirationtimespan", expirationtimespan);
					query.AddParam("searchresults", searchresults);
					query.AddParam("id", id);
					conn.ExecQuery(query);
				}
			}
		}

		/// <summary>
		/// Delete entry
		/// </summary>
		/// <remarks>
		/// This method removes a collection share entry from the database.
		/// </remarks>
		public void Delete()
		{
			Collection coll = Collection.GetByID(collectionid);
			if (coll == null)
				throw new CoreException("Collection not found");
			Orciid.Core.User.RequirePrivilege(Privilege.ModifyACL, coll);
			if (id > 0)
			{
				using (DBConnection conn = DBConnector.GetConnection())
				{
					Query query = new Query(conn,
						@"DELETE FROM RemoteCollectionAccess WHERE ID={id}");
					query.AddParam("id", id);
					conn.ExecQuery(query);
				}
			}
		}

		internal static void DeleteAll(int collid)
		{
			using (DBConnection conn = DBConnector.GetConnection())
			{
				Query query = new Query(conn,
					@"DELETE FROM RemoteCollectionAccess WHERE CollectionID={collid}");
				query.AddParam("collid", collid);
				conn.ExecQuery(query);
			}
		}

		/// <summary>
		/// Collection Identifier
		/// </summary>
		/// <remarks>
		/// Identifies the collection this collection share entry applies to.
		/// </remarks>
		/// <value>
		/// Identifies the collection this collection share entry applies to.
		/// </value>
		public int CollectionID
		{
			get
			{
				return collectionid;
			}
		}

		/// <summary>
		/// Internal Identifier
		/// </summary>
		/// <remarks>
		/// The internal identifier of this collection share entry
		/// </remarks>
		/// <value>
		/// The internal identifier of this collection share entry
		/// </value>
		public int ID
		{
			get
			{
				return id;
			}
		}

		/// <summary>
		/// User Identifier
		/// </summary>
		/// <remarks>
		/// Identifies the user account this collection share entry applies to.
		/// </remarks>
		/// <value>
		/// Identifies the user account this collection share entry applies to.
		/// </value>
		public int UserID
		{
			get
			{
				return userid;
			}
			set
			{
				userid = value;
			}
		}

		/// <summary>
		/// User Login Name
		/// </summary>
		/// <remarks>
		/// Identifies the login name of the user account this collection share entry applies to.
		/// </remarks>
		/// <value>
		/// Identifies the login name of the user account this collection share entry applies to.
		/// </value>
		public string User
		{
			get
			{
				Orciid.Core.User user = Orciid.Core.User.GetByID(userid);
				if (user != null)
					return user.Login;
				else
					return null;
			}
			set
			{
				Orciid.Core.User user = Orciid.Core.User.GetByLogin(value);
				if (user != null)
					userid = user.ID;
				else
					throw new CoreException("No user exists with specified login");
			}
		}

		/// <summary>
		/// Subnet information
		/// </summary>
		/// <remarks>
		/// Identifies the subnet a request for this shared collection must come from.
		/// </remarks>
		/// <value>
		/// Identifies the subnet a request for this shared collection must come from.
		/// </value>
		public string Subnet
		{
			get
			{
				return subnet;
			}
			set
			{
				if (IPAddress.IsValid(value))
					subnet = value;
				else
					throw new CoreException("Invalid subnet specification");
			}
		}

		/// <summary>
		/// Subnet mask information
		/// </summary>
		/// <remarks>
		/// Identifies the subnet a request for this shared collection must come from.
		/// </remarks>
		/// <value>
		/// Identifies the subnet a request for this shared collection must come from.
		/// </value>
		public string Mask
		{
			get
			{
				return mask;
			}
			set
			{
				if (IPAddress.IsValid(value))
					mask = value;
				else
					throw new CoreException("Invalid subnet mask specification");
			}
		}

		/// <summary>
		/// Cache duration
		/// </summary>
		/// <remarks>
		/// Specifies how long images can be cached on the client accessing this shared collection
		/// before the image should be refreshed.
		/// </remarks>
		/// <value>
		/// Specifies how long images can be cached on the client accessing this shared collection
		/// before the image should be refreshed.
		/// </value>
		public int CacheTimeSpan
		{
			get
			{
				return cachetimespan;
			}
			set
			{
				cachetimespan = value;
			}
		}

		/// <summary>
		/// Expiration duration
		/// </summary>
		/// <remarks>
		/// Specifies how long images can be cached on the client accessing this shared collection
		/// before the image must be deleted.
		/// </remarks>
		/// <value>
		/// Specifies how long images can be cached on the client accessing this shared collection
		/// before the image must be deleted.
		/// </value>
		public int ExpirationTimeSpan
		{
			get
			{
				return expirationtimespan;
			}
			set
			{
				expirationtimespan = value;
			}
		}

		/// <summary>
		/// Maximum number of search results
		/// </summary>
		/// <remarks>
		/// Specifies how many search results will be returned to the client searching this
		/// shared collection at the most.
		/// </remarks>
		/// <value>
		/// Specifies how many search results will be returned to the client searching this
		/// shared collection at the most.
		/// </value>
		public int SearchResults
		{
			get
			{
				return searchresults;
			}
			set
			{
				searchresults = value;
			}
		}
	}
}
