using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;

using System.Xml;

namespace EasyTabParts
{
	/// <summary>
	/// Description of the toolpart. Override the GetToolParts method in your Web Part
	/// class to invoke this toolpart. To establish a reference to the Web Part 
	/// the user has selected, use the ParentToolPane.SelectedWebPart property.
	/// </summary>
	public class ZoneTabsToolPart: Microsoft.SharePoint.WebPartPages.ToolPart
	{
		
		/// <summary>
		/// Constructor for the class. A great place to set Set default values for
		/// additional base class properties here.
		/// <summary>

		public ZoneTabsToolPart()
		{
			   this.Title = "Zone Tab Settings";
		}

		#region ApplyChanges - Logic to push ToolPart changes back to the web part

		///	<summary>
		///	Called by the tool pane to apply property changes to the selected Web Part. 
		///	</summary>
		public override void ApplyChanges()
		{
			// First, get our associated tool part as a ZoneTabs class so we can
			// access its properties
			ZoneTabs ztWebPart = this.ParentToolPane.SelectedWebPart as ZoneTabs;

			if (ztWebPart != null)
			{
				// The tab settings are in an XML structure.
				// Build an empty XML structure: <tabs />
				XmlDocument settingsXmlDoc = new XmlDocument();
				XmlElement settingsXmlRoot =
					settingsXmlDoc.CreateElement (ZoneTabConstants.XmlElementNameTabs);
				settingsXmlDoc.AppendChild (settingsXmlRoot);

				// Now create tab elements for each tab
				XmlElement [] tabElements = new XmlElement[ZoneTabConstants.MaxTabs];

				for (int i=0; i<ZoneTabConstants.MaxTabs; i++)
				{
					string tabName = tabNameTB[i].Text;
					if (tabName != "")
					{
						tabElements[i] = AddTab (settingsXmlDoc, settingsXmlRoot, tabName);
					}
				}

				// OK, now we have a <tab> element for each tab in use (non-blank name)
				// Next, we want to create a child element for each disabled web part the
				// tab will trigger. NOTE that although the user perceives ZoneTabs as
				// showing web parts, it actually hides the unwanted web parts, so we
				// only need to note the web parts that need hiding
				for (int i=0; i<webPartTable.Rows.Count; i+=2)
				{
					string webPartTitle = webPartTable.Rows[i].Cells[0].Text;
					TableCell webPartCbCell = webPartTable.Rows[i+1].Cells[0];

					for (int j=0; j<webPartCbCell.Controls.Count; j++)
					{
						CheckBox cb = webPartCbCell.Controls[j] as CheckBox;
						if (cb != null)
						{
							if (!cb.Checked && cb.Enabled)
							{
								AddDisabledPartToTab (settingsXmlDoc, tabElements[j], webPartTitle);
							}
						}
					}
				}

				// Now our XML is ready, push it and the rest of the properties
				// up to the ZoneTabs web part
				ztWebPart.ZoneTabXml = settingsXmlDoc.OuterXml;
				ztWebPart.TopBarPixels = topBarDropDownList.Pixels;
				ztWebPart.BottomBarPixels = bottomBarDropDownList.Pixels;
			}
		}

		// Adds a <tab name="tabName"> element to the <tabs /> (root) element of our
		// XML structure
		private XmlElement AddTab (XmlDocument xmlDoc, XmlElement root, string tabName)
		{
			XmlElement tabElement = xmlDoc.CreateElement (ZoneTabConstants.XmlElementNameTab);
			XmlAttribute nameAttribute = xmlDoc.CreateAttribute (ZoneTabConstants.XmlAttributeNameName);
			nameAttribute.Value = tabName;
			tabElement.Attributes.Append (nameAttribute);
			root.AppendChild (tabElement);

			return (tabElement);
		}

		// Adds a <webPart title="Title" visible="false"> element to a <tab> element
		private void AddDisabledPartToTab (XmlDocument xmlDoc, XmlElement tabElement,
			string webPartTitle)
		{
			if (tabElement != null)
			{
				XmlElement webPartElement = 
					xmlDoc.CreateElement (ZoneTabConstants.XmlElementNameWebPart);
				XmlAttribute titleAttribute =
					xmlDoc.CreateAttribute (ZoneTabConstants.XmlAttributeTitleName);
				XmlAttribute visibleAttribute = 
					xmlDoc.CreateAttribute (ZoneTabConstants.XmlAttributeVisibleName);

				titleAttribute.Value = webPartTitle;
				webPartElement.Attributes.Append (titleAttribute);

				visibleAttribute.Value = ZoneTabConstants.XmlAttributeVisibleValueFalse;
				webPartElement.Attributes.Append (visibleAttribute);

				tabElement.AppendChild (webPartElement);
			}
		}

		#endregion

		#region SyncChanges - Logic to sync the ToolPart controls with the web part values

		/// <summary>
		///	If the ApplyChanges method succeeds, this method is called by the tool pane 
		///	to refresh the specified property values in the toolpart user interface.
		/// </summary>
		public override void SyncChanges()
		{
			// First, get the web part as a ZonePart so we can access its properties
			ZoneTabs ztWebPart = this.ParentToolPane.SelectedWebPart as ZoneTabs;

			if (ztWebPart != null)
			{
				// Get the XML that represents the tab settings
				XmlDocument settingsXmlDoc = new XmlDocument();
				settingsXmlDoc.LoadXml (ztWebPart.ZoneTabXml);
				XmlNodeList tabNodes = 
					settingsXmlDoc.GetElementsByTagName (ZoneTabConstants.XmlElementNameTab);

				// Each web part in the zone will have a pair of rows in webPartTable.
				// For each one of these, set the check boxes per the XML.
				for (int i=0; i<webPartTable.Rows.Count; i+=2)
				{
					string webPartTitle = webPartTable.Rows[i].Cells[0].Text;
					TableCell webPartCbCell = webPartTable.Rows[i+1].Cells[0];

					FixCheckBoxes (webPartTitle, webPartCbCell, tabNodes);
				}
			}

			// Now sync the other properties
			topBarDropDownList.Pixels = ztWebPart.TopBarPixels;
			bottomBarDropDownList.Pixels = ztWebPart.BottomBarPixels;
		}

		// Updates the check boxes for a given web part based on the <tab /> XML elements
		// (all zones are shown unless they are disabled by a child <webPart> element)
		private void FixCheckBoxes (string webPartTitle, TableCell webPartCbCell, 
				XmlNodeList tabNodes)
		{
			// Iterate through the tabs, each of which will have a <tab /> element
			// As we do this we are going horizontally across the table cell of check
			// boxes which correspond to the specified web part
			for (int i=0; i<tabNodes.Count; i++)
			{
				// Get the checkbox for this tab
				CheckBox cb = webPartCbCell.Controls[i] as CheckBox;
				XmlElement tabElement = tabNodes[i] as XmlElement;
				if (cb != null && tabElement != null)
				{
					// If here, both the checkbox and the tab exist, so enable
					// the checkbox and set it if the web part is enabled
					cb.Enabled = true;
					cb.Checked = WebPartEnabledOn (tabElement, webPartTitle);
				}
			}

			// Now handle the case where one or more tabs were removed (by setting
			// the name to blank). We need to disable the corresponding check boxes.
			if (tabNodes.Count < ZoneTabConstants.MaxTabs)
			{
				// If here, there are fewer <tab> elements than there are controls
				// (we always have MAX_TABS checkboxes per web part)
				// Iterate through the blank ones and disable them
				for (int i=tabNodes.Count; i<ZoneTabConstants.MaxTabs; i++)
				{
					CheckBox cb = webPartCbCell.Controls[i] as CheckBox;
					if (cb != null)
					{
						cb.Checked = true;
						cb.Enabled = false;
					}
				}
			}
		}

		// Returns true if the specified web part is enabled for the <tab> element
		// passed.
		private bool WebPartEnabledOn (XmlElement tabElement, string webPartTitle)
		{
			// Construct an XPath query to find the desired web part
			string xpathQuery = "./" +
				ZoneTabConstants.XmlElementNameWebPart +
				"[@" +
				ZoneTabConstants.XmlAttributeTitleName +
				"=\"" + webPartTitle + "\"]";
			XmlElement wpElement = tabElement.SelectSingleNode (xpathQuery) as XmlElement;

			// If in doubt, show the web part
			bool result = true;

			if (wpElement != null)
			{
				// If here, we found the web part - check its state
				XmlAttribute visibleAttribute = 
					wpElement.Attributes [ZoneTabConstants.XmlAttributeVisibleName];
				if (visibleAttribute != null)
				{
					if (visibleAttribute.Value == 
						ZoneTabConstants.XmlAttributeVisibleValueFalse)
					{
						result = false;
					}
				}
			}
			return (result);
		}

		#endregion

		#region CancelChanges - Logic to cancel changes made since last Apply

		/// <summary>
		///	Called by the tool pane if the user discards changes to the selected Web Part. 
		/// </summary>
		public override void CancelChanges()
		{
		}

		#endregion

		#region Tool Part Rendering

		// Tool Part Controls
		private Label tabsLabel;
		private Table tabNameTable;
		private TextBox [] tabNameTB;
		private Table webPartTable;
		private Table PixelsTable;
		private Label topBarLabel;
		private PixelDropDownList topBarDropDownList;
		private Label bottomBarLabel;
		private PixelDropDownList bottomBarDropDownList;

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

			// Get a reference to the ZoneTabs web part we are editing
			ZoneTabs ztWebPart = this.ParentToolPane.SelectedWebPart as ZoneTabs;

			if (ztWebPart != null)
			{
				
				// Fill in tabs label
				tabsLabel = new Label ();
				tabsLabel.Text = "Tab Names:";
				this.Controls.Add (tabsLabel);

				// Get current settings info, stored in an XML document
				XmlDocument settingsXmlDoc = new XmlDocument();
				settingsXmlDoc.LoadXml (ztWebPart.ZoneTabXml);

				// Get a node for each <tab> element
				XmlNodeList nodes = 
					settingsXmlDoc.GetElementsByTagName (ZoneTabConstants.XmlElementNameTab);

				// Now build tab name textbox controls
				tabNameTable = new Table ();
				tabNameTB = new TextBox [ZoneTabConstants.MaxTabs];

				// We always have MaxTabs text boxes so user can fill in new ones
				for (int i=0; i<ZoneTabConstants.MaxTabs; i++)
				{
					// Create a table row, cell and text box
					TableRow tr = new TableRow();
					TableCell tc = new TableCell();
					tabNameTB [i] = new TextBox();

					// Get the tab name if it's defined in the XML, otherwise leave it empty
					XmlElement tabElement = nodes[i] as XmlElement;
					if (tabElement != null)
					{
						string tabName = 
							tabElement.Attributes[ZoneTabConstants.XmlAttributeNameName].Value;
						tabNameTB [i].Text = tabName;
					}
					else
					{
						tabNameTB[i].Text = "";
					}
					// Now add the controls to the table
					tc.Controls.Add (tabNameTB [i]);
					tr.Cells.Add (tc);
					tabNameTable.Rows.Add (tr);
				}
				this.Controls.Add	(tabNameTable);

				// Next build web parts names controls
				webPartTable = new Table();

				// Create a row for each web part in the zone
//				WebPartZone wpZone = ztWebPart.GetZone();
//                for (int i=0; i<wpZone.Controls.Count; i++)
                System.Web.UI.WebControls.WebParts.WebPartZoneBase wpZone
                    = ztWebPart.Zone;
                for (int i = 0; i < wpZone.WebParts.Count; i++)
                {
                    System.Web.UI.WebControls.WebParts.WebPart wp2 =
                        wpZone.WebParts[i] as System.Web.UI.WebControls.WebParts.WebPart;
                    if (wp2 != null)
                    {
                        AddWpTableRow(webPartTable, nodes, ztWebPart, wp2);
                    }
				}
				this.Controls.Add (webPartTable);

				// OK, now we need a table for selecting top bar pixels
				PixelsTable = new Table();
				TableRow trow = new TableRow();
				TableCell tcell = new TableCell();

				topBarLabel = new Label ();
				topBarLabel.Text = "Top Bar Thickness:";
				tcell.Controls.Add (topBarLabel);
				trow.Cells.Add (tcell);
				tcell = new TableCell();
				topBarDropDownList = new PixelDropDownList (ztWebPart.TopBarPixels);
				tcell.Controls.Add (topBarDropDownList);
				trow.Cells.Add (tcell);
				PixelsTable.Rows.Add (trow);

				// And another table for selecting bottom bar pixels
				trow = new TableRow();
				tcell = new TableCell();
				bottomBarLabel = new Label();
				bottomBarLabel.Text = "Bottom Bar Thickness: ";
				tcell.Controls.Add (bottomBarLabel);
				trow.Cells.Add (tcell);
				tcell = new TableCell();
				bottomBarDropDownList = new PixelDropDownList (ztWebPart.BottomBarPixels);
				tcell.Controls.Add (bottomBarDropDownList);
				trow.Cells.Add (tcell);
				PixelsTable.Rows.Add (trow);
				
				this.Controls.Add (PixelsTable);
			}
		}

        // Adds a pair of rows to the table of web parts for the provided web part
        private void AddWpTableRow(Table webPartTable, XmlNodeList tabNodes,
            WebPart zoneTabsWebPart, 
            System.Web.UI.WebControls.WebParts.WebPart webPartToAdd)
        {
            // First off - we never add ourselves, so if the web part to add is
            // our own web part, then skip the whole thing
            if (webPartToAdd != zoneTabsWebPart)
            {
                // OK, we have a valid web part. Grab its title.
                string webPartTitle = webPartToAdd.Title;

                // Now create a table row and cell for the web part name
                TableRow tr = new TableRow();
                TableCell tc = new TableCell();
                tc.Text = webPartTitle;
                tr.Cells.Add(tc);
                webPartTable.Rows.Add(tr);

                // Next, we need another row for the checkboxes.
                // We use one check box per tab, to control which tabs the web part
                // will appear on
                tr = new TableRow();
                tc = new TableCell();

                // First, create checkboxes for the tabs we have
                for (int i = 0; i < tabNodes.Count; i++)
                {
                    XmlElement tabElement = tabNodes[i] as XmlElement;
                    if (tabElement != null)
                    {
                        CheckBox cb = new CheckBox();
                        if (WebPartEnabledOn(tabElement, webPartTitle))
                        {
                            cb.Checked = true;
                        }
                        else
                        {
                            cb.Checked = false;
                        }
                        tc.Controls.Add(cb);
                    }
                }

                // Now create the remaining checkboxes, which will be disabled
                if (tabNodes.Count < ZoneTabConstants.MaxTabs)
                {
                    for (int i = tabNodes.Count; i < ZoneTabConstants.MaxTabs; i++)
                    {
                        CheckBox cb = new CheckBox();
                        cb.Enabled = false;
                        cb.Checked = true;
                        tc.Controls.Add(cb);
                    }
                }
                tr.Cells.Add(tc);
                webPartTable.Rows.Add(tr);
            }
        }


        // The base class RenderToolPart will do exactly what we want
//		protected override void RenderToolPart(HtmlTextWriter output)
//		{
//		}

		#endregion

	}											
}
								
