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

using System;
using System.Globalization;
using System.Web;
using System.Web.Caching;
using System.Xml.Serialization;
using CommunityServer.Components;

namespace CommunityServer.Controls
{

	/// <summary>
	/// Renders a Tab + Submenus based on the tab configuration file.
	/// </summary>
	public abstract class TabDrivenTemplatedWebControl : TemplatedWebControl
	{
		public TabDrivenTemplatedWebControl() : base()
		{
		}

		#region Public Properties

		/// <summary>
		/// Returns the currently selected tab
		/// </summary>
		public virtual string Selected
		{
			get 
			{
				return (string) ViewState["Selected"]; 
			}
			set 
			{  
				ViewState["Selected"] = value; 
			}
		}
        
		/// <summary>
		/// returns the location of the current tab configuration file
		/// </summary>
		public virtual string FileLocation
		{
			get
			{
				string path = Context.Server.MapPath(this.ResolveUrl(FileName));
				return path;
			}
		}

		/// <summary>
		/// returns the file name containing the tab configuration
		/// </summary>
		public virtual string FileName
		{
			get 
			{
				Object state = ViewState["FileName"];
				if ( state != null ) 
				{
					return (String)state;
				}
				return "tabs.config";
			}
			set 
			{
				ViewState["FileName"] = value;
			}
		}

		/// <summary>
		/// if true, the url is written into the control label
		/// </summary>
		public virtual bool UseDirectNavigation
		{
			get 
			{
				Object state = ViewState["UseDirectNavigation"];
				if ( state != null ) 
				{
					return (bool)state;
				}
				return false;
			}
			set 
			{
				ViewState["UseDirectNavigation"] = value;
			}
		}
		#endregion

		#region GetTabs()
		/// <summary>
		/// Returns the current instance of the TabCollection
		/// </summary>
		/// <returns></returns>
		protected TabCollection GetTabs()
		{
			string path = FileLocation;

			if(path.StartsWith("/") || path.StartsWith("~"))
				path = Context.Server.MapPath(path);

			TabCollection tc = CSCache.Get(path) as TabCollection;
			if(tc == null)
			{
                
				tc = (TabCollection)Serializer.ConvertFileToObject(path,typeof(TabCollection));
				CSCache.Max(path,tc,new CacheDependency(path));
			}
			return tc;
		}
		#endregion

		#region Tab Helpers

		/// <summary>
		/// Allows tabs to removed/not included on other tabs
		/// </summary>
		protected bool IsNotFiltered(Tab child)
		{
			if(child.Filter == null)
				return true;
	
			string[] filters = child.Filter.Split(',');
			foreach(string filter in filters)
			{
				if(string.Compare(filter,this.Selected,true)==0)
					return false;
			}
	
			return true;

		}
		
		/// <summary>
		/// Checks to see if the current tab has any Roles and if the current user is a member any
		/// of the roles
		/// </summary>
		protected bool IncludeLink(Tab t)
		{
			if(t.HasRoles)
			{
				string[] roles = t.Roles.Split(';');
				foreach(string role in roles)
				{
					if(Context.User.IsInRole(role))
						return true;
				}
				return false;
			}
			return true;
		}

		/// <summary>
		/// Resolves the current url and attempts to append the specified querystring
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		protected string FormatLink(Tab t)
		{
			string url = null;
			
			if(t.UrlName==null)
			{
				if(!t.HasHref)
					return null;

				if(t.HasQueryString)
					url = string.Format(t.Href.Replace('^','&'),Context.Request.QueryString[t.QueryString]);
				else
					url = t.Href;
			}
			else
			{
				if(!t.HasParameters)
					url = FormatUrl(t.UrlName);
				else
					url = FormatUrl(t.UrlName,t.UrlParameters);
			}

			return ResolveUrl(url);
		}

		protected string FormatUrl(string name)
		{
			return Globals.GetSiteUrls().UrlData.FormatUrl(name);
		}

		protected string FormatUrl(string name, params object[] parameters)
		{
			return Globals.GetSiteUrls().UrlData.FormatUrl(name, parameters);
		}

		protected virtual string GetText(Tab t)
		{
			if(t.HasText)
			{
				return t.Text;
			}
			else
			{
				if (Globals.IsNullorEmpty(t.ResourceFile))
					return ResourceManager.GetString(t.ResourceName);
				else
					return ResourceManager.GetString(t.ResourceName, t.ResourceFile);
			}
		}
		#endregion

		#region GetState
		/// <summary>
		/// Walks the tab and it's children to see if any of them are currently selected
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		protected SelectedState GetState(Tab t)
		{
			//Check the parent
			if(string.Compare(t.Name,Selected,true,CultureInfo.InvariantCulture) == 0)
				return SelectedState.Selected;

			//Walk each of the child tabs
			if(t.HasChildren)
			{
				foreach(Tab child in t.Children)
				{
					if(string.Compare(child.Name,this.Selected,true,CultureInfo.InvariantCulture) == 0)
						return SelectedState.ChildSelected;

					else if(child.HasChildren)
					{
						foreach(Tab cc in child.Children)
							if(string.Compare(cc.Name,this.Selected,true,CultureInfo.InvariantCulture) == 0)
								return SelectedState.ChildSelected;
					}
				}
			}

			//Nothing here is selected
			return SelectedState.Not;
		}

		#endregion

		#region SelectedState
		/// <summary>
		/// Internal enum used to track if a tab is selected
		/// </summary>
		protected enum SelectedState
		{
			Not,
			Selected,
			ChildSelected
		};
		#endregion

	}

	#region TabCollection
	/// <summary>
	/// TabCollection is a container for all of the tabs.
	/// </summary>
	[Serializable]
	public class TabCollection
	{
		private Tab[] _tabs;
		/// <summary>
		/// Property Tabs (Tab[])
		/// </summary>
		[XmlArray("Tabs")]
		public Tab[] Tabs
		{
			get {  return this._tabs; }
			set {  this._tabs = value; }
		}
	}
	#endregion

	#region Tab
	/// <summary>
	/// Tab is a container object which represents a singe tab
	/// </summary>
	[Serializable]
	public class Tab
	{
		#region Private Members
		private string _text;
		private string _href;
		private string _name;
		private string _queryString;
		private string _roles;
		private string _resourcename = null;
		private string _resourcefile = null;
		private string _urlname = null;
		private string[] _urlparameters = null;
		private bool _enable = true;
		private Tab[] _children;
		private bool _isRoot = false;
		private string _filter = null;
		private IMenuItem _itab = null;
		private string _iTabType;
		private bool _isModal = false;
		private string _modalWidth;
		private string _modalHeight;
		private string _modalCallback;
		private bool _isJavaScript = false;
		private string _javaScript;
		#endregion

		#region Public Properties
		/// <summary>
		/// Property Text (string)
		/// </summary>
		[XmlAttribute("text")]
		public string Text
		{
			get {  return this._text; }
			set {  this._text = value; }
		}

		[XmlAttribute("modalwidth")]
		public string ModalWidth
		{
			get {  return this._modalWidth; }
			set {  this._modalWidth = value; }
		}

		[XmlAttribute("modalheight")]
		public string ModalHeight
		{
			get {  return this._modalHeight; }
			set {  this._modalHeight = value; }
		}

		[XmlAttribute("modalcallback")]
		public string ModalCallback
		{
			get {  return this._modalCallback; }
			set {  this._modalCallback = value; }
		}

		[XmlAttribute("filter")]
		public string Filter
		{
			get
			{
				return _filter;
			}
			set
			{
				_filter= value;
			}
		}

        
		/// <summary>
		/// Property Href (string)
		/// </summary>
		[XmlAttribute("href")]
		public string Href
		{
			get {  return this._href; }
			set {  this._href = value; }
		}

		[XmlAttribute("javascript")]
		public string JavaScript
		{
			get {  return this._javaScript; }
			set {  this._javaScript = value; }
		}

		/// <summary>
		/// Property urlname (string)
		/// </summary>
		[XmlAttribute("urlname")]
		public string UrlName
		{
			get {  return this._urlname; }
			set {  this._urlname = value; }
		}

		/// <summary>
		/// Property parameters (string)
		/// </summary>
		[XmlAttribute("urlparameters")]
		public string UrlParameters
		{
			get {  return this._urlparameters.ToString(); }
			set {  this._urlparameters = value.Split(','); }
		}

		/// <summary>
		/// Property parameters (string[])
		/// </summary>
		[XmlAttribute("parameters")]
		public string[] Parameters
		{
			get {  return this._urlparameters; }
			set {  this._urlparameters = value; }
		}

		/// <summary>
		/// Property Name (string)
		/// </summary>
		[XmlAttribute("name")]
		public string Name
		{
			get {  return this._name; }
			set {  this._name = value; }
		}

		/// <summary>
		/// Property QueryString (string)
		/// </summary>
		[XmlAttribute("querystring")]
		public string QueryString
		{
			get {  return this._queryString; }
			set {  this._queryString = value; }
		}

		/// <summary>
		/// Property Roles (string)
		/// </summary>
		[XmlAttribute("roles")]
		public string Roles
		{
			get {  return this._roles; }
			set {  this._roles = value; }
		}

		/// <summary>
		/// Property ResourceName (string)
		/// </summary>
		[XmlAttribute("resourcename")]
		public string ResourceName
		{
			get {  return this._resourcename; }
			set {  this._resourcename = value; }
		}

		/// <summary>
		/// Property ResourceFile (string)
		/// </summary>
		[XmlAttribute("resourcefile")]
		public string ResourceFile
		{
			get {  return this._resourcefile; }
			set {  this._resourcefile = value; }
		}


		/// <summary>
		/// Property Enable (bool)
		/// </summary>
		[XmlAttribute("enabled")]
		public bool Enabled
		{
			get {  return this._enable; }
			set {  this._enable = value; }
		}

		/// <summary>
		/// Property Enable (bool)
		/// </summary>
		[XmlAttribute("isRoot")]
		public bool IsRoot
		{
			get {  return this._isRoot; }
			set {  this._isRoot = value; }
		}

		/// <summary>
		/// Property IsModal (bool)
		/// </summary>
		[XmlAttribute("ismodal")]
		public bool IsModal
		{
			get {  return this._isModal; }
			set {  this._isModal = value; }
		}

		[XmlAttribute("isjavascript")]
		public bool IsJavaScript
		{
			get {  return this._isJavaScript; }
			set {  this._isJavaScript = value; }
		}

		[XmlAttribute("iTabType")]
		public string ITabType
		{
			get {  return this._iTabType; }
			set {  this._iTabType = value; }
		}


		/// <summary>
		/// Property Children (Tab[])
		/// </summary>
		[XmlArray("SubTabs")]
		public Tab[] Children
		{
			get {  return this._children; }
			set {  this._children = value; }
		}

		/// <summary>
		/// If an implementation of ITab is found, the result of IsValid will be returned.
		/// If no implementation is found, true will be returned
		/// </summary>
		protected bool IsITabValid(HttpContext context)
		{
			if(Globals.IsNullorEmpty(ITabType))
				return true;
			
			if(this._itab == null)
			{
				Type t = Type.GetType(this.ITabType);
				if(t == null)
					throw new ArgumentException("The Type: " + this.ITabType + " is not a valid type");

				_itab = Activator.CreateInstance(t) as IMenuItem;
				if(_itab == null)
					throw new ArgumentException("The Type: " + this.ITabType + " is not a valid ITab type");

			}

			return _itab.IsValid(context);
			
		}

		public bool IsValid(HttpContext context)
		{
			if(this.Enabled && IsITabValid(context))
			{
				if(this.HasRoles)
				{
					string[] roles = this.Roles.Split(';');
					foreach(string role in roles)
					{
						if(context.User.IsInRole(role))
							return true;
					}

					//ITab valid, but invalid role set
					return false;
				}

				//ITab valid, but no roles
				return true;
			}

			//ITab is not valid, so move on
			return false;
		}
		#endregion

		#region Has Helpers
		public bool HasChildren
		{
			get{return this.Children != null && this.Children.Length > 0;}
		}

		public bool HasQueryString
		{
			get{return !Globals.IsNullorEmpty(this.QueryString);}
		}

		public bool HasRoles
		{
			get{return !Globals.IsNullorEmpty(this.Roles);}
		}

		public bool HasText
		{
			get{return !Globals.IsNullorEmpty(this.Text);}
		}

		public bool HasHref
		{
			get{return !Globals.IsNullorEmpty(this.Href);}
		}

		public bool HasParameters
		{
			get{return (this.Parameters != null);}
		}

		#endregion

	}
	#endregion

	/// <summary>
	/// Enables adding custom logic to determine if a particular tab should be rendered
	/// </summary>
	public interface IMenuItem
	{
		bool IsValid(HttpContext context);
	}
}

