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

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI;
using CommunityServer.Components;

namespace CommunityServer.Controls
{
	/// <summary>
	/// The head control replaces the standard head element in a CS document. 
	/// 
	/// This controls is a "late rendered" control. It's data/content is stored in the HttpContext and 
	/// can be written to from any page/control prior to the Render method being executed.
	/// 
	/// It currently provides a standard way to add a Title, MetaTags, CSS Style Sheets, and Syndication
	/// Autodiscovery
	/// 
	/// Prior to rendering it's closing bracket, it will also render any child controls.
	/// </summary>
    [PersistChildren(true), ParseChildren(false)]
    public class Head : Control
    {
        public Head()
        {
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.WriteLine("");
            writer.WriteLine("<head>");

            SiteSettings settings = CSContext.Current.SiteSettings;

            RenderTitle(settings, writer);

            RenderMetaTags(settings, writer);
			RenderLinkTags(settings, writer);

            RenderStyleSheets(writer);
			RenderFavicon(writer);

            RenderAutoDiscoverySyndication(writer);

            base.Render(writer);

            RenderAdditionHealder(settings,writer);
			RenderRawContent(writer);

            writer.WriteLine("</head>");

        }

		protected virtual void RenderFavicon(HtmlTextWriter writer)
		{
			writer.WriteLine("<link rel=\"shortcut icon\" type=\"image/ico\" href=\"{0}\" />", Globals.GetSiteUrls().Favicon);
		}

        #region Render Methods

        protected virtual void RenderAdditionHealder(SiteSettings settings,  HtmlTextWriter writer)
        {
            if(!Globals.IsNullorEmpty(settings.RawAdditionalHeader))
            {
                writer.WriteLine(settings.RawAdditionalHeader);
            }
        }
     

	    protected virtual void RenderAutoDiscoverySyndication(HtmlTextWriter writer)
	    {
	        ArrayList autoDiscovery = Context.Items[autoDiscoveryKey] as ArrayList;
	        if(autoDiscovery != null && autoDiscovery.Count > 0)
	        {
	            foreach(string item in autoDiscovery)
	            {
	                writer.WriteLine(item);
	            }
	        }
	    }

		protected virtual void RenderStyleSheets(HtmlTextWriter writer)
		{
			RenderStyleSheets(writer, StyleRelativePosition.First);
			RenderStyleSheets(writer, StyleRelativePosition.Unspecified);
			RenderStyleSheets(writer,  StyleRelativePosition.Last);
		}
	    protected virtual void RenderStyleSheets(HtmlTextWriter writer, StyleRelativePosition position)
	    {
	        Queue queue = Context.Items[styleKey] as Queue;
	        if(queue != null && queue.Count > 0)
	        {
	            IEnumerator ie = queue.GetEnumerator();
	            while(ie.MoveNext())
	            {
					StyleQueueItem si = (StyleQueueItem)ie.Current;
					if(si.Position == position)
						writer.WriteLine(si.StyleTag);
	            }
               
	        }
	    }

	    protected virtual void RenderMetaTags(SiteSettings settings, HtmlTextWriter writer)
	    {
	        NameValueCollection metaTags = Context.Items[metaKey] as NameValueCollection;
	        if(metaTags == null)
	            metaTags = new NameValueCollection();
    
	        if(Globals.IsNullorEmpty(metaTags["description"]) && !Globals.IsNullorEmpty(settings.SearchMetaDescription))
	        {
	            metaTags["description"] = settings.SearchMetaDescription;
	        }
    
	        if(Globals.IsNullorEmpty(metaTags["keywords"]) && !Globals.IsNullorEmpty(settings.SearchMetaKeywords))
	        {
	            metaTags["keywords"] = settings.SearchMetaKeywords;
	        }
    
	        metaTags["GENERATOR"] = SiteStatistics.CommunityServerVersionVersionInfo;
    
	        foreach(string key in metaTags.Keys)
	        {
	            writer.WriteLine(metaFormat,key, metaTags[key]); 
	        }
	    }

		protected virtual void RenderLinkTags(SiteSettings settings, HtmlTextWriter writer)
		{
			NameValueCollection linkTags = Context.Items[linkKey] as NameValueCollection;
			if(linkTags == null)
				linkTags = new NameValueCollection();

			foreach(string key in linkTags.Keys)
			{
				writer.WriteLine(linkFormat,key, linkTags[key]); 
			}
		}

	    protected virtual void RenderTitle(SiteSettings settings, HtmlTextWriter writer)
	    {
	        string title = Context.Items[titleKey] as string;
	        if(Globals.IsNullorEmpty(title))
	            title = settings.SiteName;
    
	        writer.WriteLine("<title>{0}</title>",title);
	    }

		protected virtual void RenderRawContent(HtmlTextWriter writer)
		{
			ArrayList rawContent = Context.Items[rawContentKey] as ArrayList;
			if(rawContent == null)
				rawContent = new ArrayList();

			foreach(string item in rawContent)
			{
				writer.WriteLine(item); 
			}
		}
		
		#endregion

        #region Static Keys
	    private static readonly string metaFormat = "<meta name=\"{0}\" content=\"{1}\" />";
        private static readonly string titleKey = "CommunityServer.Controls.Title.Value";
        private static readonly string metaKey = "CommunityServer.Controls.MetaTags";
        private static readonly string autoDiscoveryKey = "CommunityServer.Controls.AutoDiscovery";
        private static readonly string styleKey = "CommunityServer.Controls.StyleTags";
        private static readonly string styleFormat = "<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\" media=\"{1}\" />";
        private static readonly string autoDiscoveryLink = "<link rel=\"alternate\" type=\"application/{0}+xml\" title=\"{1}\" href=\"{2}\"  />";
		private static readonly string linkFormat = "<link rel=\"{0}\" href=\"{1}\" />";
		private static readonly string linkKey = "CommunityServer.Controls.LinkTags";
		private static readonly string rawContentKey = "CommunityServer.Controls.RawHeaderContent";
		#endregion

        #region MetaTags
        /// <summary>
        /// Adds the description meta tag.
        /// </summary>
        public static void AddMetaDescription(string value, HttpContext context)
        {
            AddMetaTag("description",value, context);
        }

        /// <summary>
        /// Adds the keywork meta tag
        /// </summary>
        public static void AddMetaKeywords(string value, HttpContext context)
        {
            AddMetaTag("keywords",value, context);
        }

        /// <summary>
        /// Adds a new meta tag key and value
        /// </summary>
        public static void AddMetaTag(string key, string value, HttpContext context)
        {
            if(!Globals.IsNullorEmpty(key) && !Globals.IsNullorEmpty(value))
            {
                NameValueCollection mc = context.Items[metaKey] as NameValueCollection;
                if(mc == null)
                {
                    mc = new NameValueCollection();
                    context.Items.Add(metaKey, mc);
                }
                mc[key] = value;
            }
        }
        #endregion

        #region Title
        public static void AddTitle(string title, HttpContext context)
        {
            context.Items[titleKey] = title;
        }

        public static void AddSiteNameTitle(string title, HttpContext context)
        {
            AddTitle(string.Format(ResourceManager.GetString("title_format"),CSContext.Current.SiteSettings.SiteName,title),context );
        }
        #endregion

        #region Style
        /// <summary>
        /// Adds a style to a Queue collection. Style items are always rendered first in first out
        /// Although some some control can be offered using StyleRelativePosition
        /// </summary>
        /// <param name="url">Fully qualified url to style sheet</param>
        /// <param name="media"></param>
        /// <param name="context"></param>
        public static void AddStyle(string url, string media, HttpContext context)
        {
			AddStyle(url, media, context, StyleRelativePosition.Unspecified);
		}
		public static void AddStyle(string url, string media, HttpContext context, StyleRelativePosition position)
		{
			Queue styleQueue = context.Items[styleKey] as Queue;
			if(styleQueue == null)
			{
				styleQueue = new Queue();
				context.Items[styleKey] = styleQueue;
			}

			styleQueue.Enqueue(new StyleQueueItem(string.Format(styleFormat,url,media), position));
		}
		#endregion

        #region Syndication AutoDiscovery

        /// <summary>
        /// Adds a RSS 2.0 autodiscoverable link to the header
        /// </summary>
        public static void AddRssAutoDiscovery(string title, string url, HttpContext context)
        {
            SetAutoDiscoverty(title + " (RSS 2.0)", url, context, "rss");
        }

        /// <summary>
        /// Adds an Atom 1.0 autodiscoverale link to the header
        /// </summary>
        public static void AddAtomDiscovery(string title, string url, HttpContext context)
        {
            SetAutoDiscoverty(title + " (Atom 1.0)", url, context, "atom");
        }

        private static void SetAutoDiscoverty(string title, string url, HttpContext context, string autoType)
        {
            ArrayList mc = context.Items[autoDiscoveryKey] as ArrayList;
            if(mc == null)
            {
                mc = new ArrayList();
                context.Items.Add(autoDiscoveryKey, mc);
            }
			
			if(!mc.Contains(string.Format(autoDiscoveryLink,autoType,title,url)))
				mc.Add(string.Format(autoDiscoveryLink,autoType,title,url));
        }

        #endregion

		#region Link Tags
		/// <summary>
		/// Adds a new link tag rel and href
		/// </summary>
		public static void AddLinkTag(string rel, string href, HttpContext context)
		{
			if(!Globals.IsNullorEmpty(rel) && !Globals.IsNullorEmpty(href))
			{
				NameValueCollection lc = context.Items[linkKey] as NameValueCollection;
				if(lc == null)
				{
					lc = new NameValueCollection();
					context.Items.Add(linkKey, lc);
				}
				lc[rel] = href;
			}
		}
		#endregion

		#region Raw Content

		/// <summary>
		/// Adds raw content to the HTML Header, such as script blocks or custom tags
		/// </summary>
		public static void AddRawContent(string content, HttpContext context)
		{
			if (!Globals.IsNullorEmpty(content))
			{
				ArrayList mc = context.Items[rawContentKey] as ArrayList;
				if(mc == null)
				{
					mc = new ArrayList();
					context.Items.Add(rawContentKey, mc);
				}
				mc.Add(content);
			}
		}

		#endregion

    }
}
