using System;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;

using System.Xml;
using System.Collections;

namespace EasyTabParts
{
	[DefaultProperty("ZoneTabXml"),
		ToolboxData("<{0}:ZoneTabs runat=server></{0}:ZoneTabs>"),
		XmlRoot(Namespace="EasyTabParts")]
	public class ZoneTabs : System.Web.UI.WebControls.WebParts.WebPart
    {

        #region Members

        // Child Controls
        private EasyTabParts.TabList _tabList;

        // Editor Part Property Settings
		private string _zoneTabXml = defaultZoneTabXml;
        private EasyTabParts.TabList.TabThemeOption _tabTheme =
            EasyTabParts.TabList.TabThemeOption.blue;
        private System.Web.UI.WebControls.Orientation _zoneLayout =
            System.Web.UI.WebControls.Orientation.Vertical;
        private bool _reverseColors = false;
        private int _fontSize = 12;
        private bool _bold = false;

        #endregion

        #region Web Part Properties

        // ZoneTabXml - Holds the list of tabs and web parts hidden by each
		private const string defaultZoneTabXml = "<tabs />";

        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
		public string ZoneTabXml
		{
            get { return _zoneTabXml; }
            set { _zoneTabXml = value; }
		}

        // TabTheme - Holds the theme of tabs to show
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public EasyTabParts.TabList.TabThemeOption TabTheme
        {
            get { return _tabTheme; }
            set { _tabTheme = value; }
        }

        // ZoneLayout - Allows override of zone horizontal/vertical layout
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public System.Web.UI.WebControls.Orientation ZoneLayout
        {
            get { return _zoneLayout; }
            set {
                    _zoneLayout = value;
                    if (_tabList != null)
                    {
                        if (_zoneLayout == System.Web.UI.WebControls.Orientation.Vertical)
                        {
                            _tabList.TabOrientation = System.Web.UI.WebControls.Orientation.Horizontal;
                        }
                        else
                        {
                            _tabList.TabOrientation = System.Web.UI.WebControls.Orientation.Vertical;
                        }
                    }
                }
        }

        // ReverseColors - Swaps the colors of selected vs. unselected tabs
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public bool ReverseColors
        {
            get { return _reverseColors; }
            set { _reverseColors = value; }
        }
        
        // Font Size - Holds the font size in points
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public int FontSize
        {
            get { return _fontSize; }
            set { _fontSize = value; }
        }

        // Bold - If true, tab text is shown in bold
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public bool Bold
        {
            get { return _bold; }
            set { _bold = value; }
        }

		#endregion

		#region Editor Part Registration and Control Access

        // CreateEditorParts - Override to declare our own editor part
        public override EditorPartCollection CreateEditorParts()
        {
            ArrayList editorPartArray = new ArrayList();

            ZoneTabsEditorPart editorPart = new ZoneTabsEditorPart();
            editorPart.ID = this.ID + "_editorPart";
            editorPartArray.Add (editorPart);

            return new EditorPartCollection(editorPartArray);
        }

		#endregion

        #region Exception Handling

        bool errorSet = false;
        string errorMessage = "";
        private void HandleException(Exception ex)
        {
            errorSet = true;
            errorMessage = ex.Message;
        }

        #endregion

        #region Web Part Rendering

		protected override void CreateChildControls()
		{
			base.CreateChildControls ();

            this.Page.ClientScript.RegisterClientScriptBlock(typeof(string), "EASY_TABS",
                "<link type=\"text/css\" rel=\"stylesheet\" href=\"_layouts/images/EasyTabParts.css\">");

			// Create the tabs table control
            _tabList = new EasyTabParts.TabList();
            _tabList.SelectedIndexChanged += new EventHandler(_tabList_SelectedIndexChanged);
            _tabList.FontSize = _fontSize;
            _tabList.Bold = _bold;
            if (_zoneLayout == System.Web.UI.WebControls.Orientation.Horizontal)
            {
                // A horizontal zone needs vertical tabs
                _tabList.TabOrientation = System.Web.UI.WebControls.Orientation.Vertical;
            }
            else
            {
                // A vertical zone needs horizontal tabs
                _tabList.TabOrientation = System.Web.UI.WebControls.Orientation.Horizontal;
            }
            _tabList.TabColorsReversed = _reverseColors;

			try
			{
                BindTabListToMetadata(_tabList.Items);
			}
			catch (Exception ex)
			{
				HandleException (ex);
			}

			this.Controls.Add (_tabList);
		}

        void _tabList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (sender is EasyTabParts.TabList)
            {
                EasyTabParts.TabList tl = sender as EasyTabParts.TabList;
                SetWebParts(tl.SelectedValue);
            }
        }

        private void BindTabListToMetadata(ListItemCollection items)
        {
            // Get the tab data into an XmlDocument, and make a node list of the tab
            // elements
            XmlDocument tabConfigDoc = new XmlDocument();
            tabConfigDoc.LoadXml(_zoneTabXml);
            XmlNodeList tabNodes =
                tabConfigDoc.GetElementsByTagName(ZoneTabConstants.XmlElementNameTab);

            // Now loop through the nodes adding tabs as we go
            foreach (XmlNode node in tabNodes)
            {
                XmlElement elt = node as XmlElement;
                if (elt != null)
                {
                    string tabName =
                        elt.Attributes[ZoneTabConstants.XmlAttributeNameName].Value;
                    ListItem li = new ListItem(tabName);
                    items.Add(li);
                }
            }
        }

		// OnPreRender - Set the tab state as needed - this has to happen after
		// viewstate has had a chance to load
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender (e);

            _tabList.FontSize = _fontSize;
            _tabList.Bold = _bold;

            if (!this.BrowserDisplayMode())
			{
				// We are in design mode: update tabs and force show all web parts

                _tabList.Items.Clear();
                BindTabListToMetadata(_tabList.Items);
				ShowAllWebParts();
			}
			else
			{
                // We are rendering: if no tab is selected, auto-select the first one
                // Then adjust the web parts
                if (_tabList.SelectedIndex < 0)
                {
                    _tabList.Items[0].Selected = true;
                }
                SetWebParts(_tabList.SelectedValue);
            }
		}

        /// <summary>
        /// Render this Web Part to the output parameter specified.
        /// </summary>
        /// <param name="output"> The HTML writer to write out to </param>
        protected override void Render(HtmlTextWriter output)
        {
            if (!errorSet)
            {
                _tabList.TabTheme = _tabTheme;

                base.Render(output);
            }
            else
            {
                output.Write(SPEncode.HtmlEncode(errorMessage));
            }
        }

        private bool BrowserDisplayMode()
        {
            return (!this.WebPartManager.DisplayMode.AllowPageDesign);
        }

        #endregion

        #region Web Part Management

        // SetWebParts (tabName) - Set web part state for the specified tab
		private void SetWebParts (string tabName)
		{
            this.Zone.LayoutOrientation = this.ZoneLayout;

			// Now to turn the web parts on and off based on the selected tab.
            // To start, build an XPath query to find the <tab> element for the
			// selected tab in _zoneTabXml, which holds all the zone/tab settings
			string xpathQuery = "//" +
				ZoneTabConstants.XmlElementNameTab +
				"[@" +
				ZoneTabConstants.XmlAttributeNameName +
				"=\"" + tabName + "\"]";

			try
			{
				// Now get the Xml and  locate the element
				XmlDocument tabConfigDoc = new XmlDocument ();
                tabConfigDoc.LoadXml(_zoneTabXml);
				XmlElement tabConfigElement = 
					tabConfigDoc.SelectSingleNode (xpathQuery) as XmlElement;

				if (tabConfigElement != null)
				{
					// If here, we successfully found the <tab> element we're
					// looking for.
					// Now scan the current web part zone and examine each web
					// part

                    System.Web.UI.WebControls.WebParts.WebPartZoneBase
                        myZone = this.Zone;

					if (myZone != null)
					{
                        for (int i = 0; i < myZone.WebParts.Count; i++)

						{
							// Get the web part
                            System.Web.UI.WebControls.WebParts.WebPart wp =
                                myZone.WebParts[i] as System.Web.UI.WebControls.WebParts.WebPart;
                            if (wp != null)
							{
								// Build an XPath query to get the attribute for
								// this web part
								xpathQuery = "./" +
									ZoneTabConstants.XmlElementNameWebPart +
									"[@" +
									ZoneTabConstants.XmlAttributeTitleName +
									"=\"" + wp.Title + "\"]";
								XmlElement wpElement = 
									tabConfigElement.SelectSingleNode (xpathQuery) as XmlElement;
								if (wpElement != null)
								{
									// If here, we found an XML element for this web part.
									// If it's supposed to be hidden, then hide it!
									XmlAttribute visibleAttribute = wpElement.Attributes["visible"];
									if (visibleAttribute != null &&
										this.BrowserDisplayMode() &&
										visibleAttribute.Value == 
											ZoneTabConstants.XmlAttributeVisibleValueFalse)
									{
										// Hide the web part
                                        wp.Hidden = true;
									}
									else
									{
										//Show the web part
                                        wp.Hidden = false;
									}
								}
								else
								{
									// If here, there was no XML element for this web part.
									// Show it!
                                    wp.Hidden = false;
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				HandleException (ex);
			}
		}

		// ShowAllWebParts () - Turns all the web parts on, for use in design mode
		private void ShowAllWebParts ()
		{
			try
			{
				// Get the web part zone
				Microsoft.SharePoint.WebPartPages.WebPartZone myZone;
				myZone = this.Page.FindControl (this.Zone.ID)
                    as Microsoft.SharePoint.WebPartPages.WebPartZone;

				if (myZone != null)
				{
					// Loop through the contained web parts and turn them all to
					// visible
					for (int i=0; i < myZone.Controls.Count; i++)
					{
						Microsoft.SharePoint.WebPartPages.WebPart wp =
                            myZone.Controls[i] as Microsoft.SharePoint.WebPartPages.WebPart;
						if (wp != null)
						{
                            wp.Hidden = false;
						}
					}
				}
			}
			catch (Exception ex)
			{
				HandleException (ex);
			}
		}


        // This utility function is available to the ToolPart so it can enumerate the web
        // parts in the current zone
        public Microsoft.SharePoint.WebPartPages.WebPartZone GetZone()
        {
            try
            {
                Microsoft.SharePoint.WebPartPages.WebPartZone myZone;
                myZone = this.Page.FindControl(this.Zone.ID)
                    as Microsoft.SharePoint.WebPartPages.WebPartZone;
                return (myZone);
            }
            catch
            {
                return (null);
            }
        }

		#endregion

	}
}
