context: using System;
  using System.Linq;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Diagnostics;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using N2.Definitions;
  using N2.Edit;
  using N2.Engine;
  using N2.Persistence;
  using N2.Web.Parts;
  using N2.Collections;
  using System.Web.UI.HtmlControls;
  using N2.Edit.Versioning;
  
  namespace N2.Web.UI.WebControls
  {
      public class ItemEditorList : Panel
      {
          #region Fields
  
          private readonly Engine.Logger<ItemEditorList> logger;
          private readonly Panel addPanel = new Panel { CssClass = "addArea form-actions" };
          private IDefinitionManager definitions;
          private int itemEditorIndex;
          private HtmlGenericControl itemEditorsContainer = new HtmlGenericControl("div");
          private Type minimumType = typeof (ContentItem);
          private ContentItem parentItem;
          private PartsAdapter partsAdapter;
  
          #endregion
  
          #region Constructor
  
          public ItemEditorList()
          {
              CssClass = "itemListEditor";
  			AllowedTemplateKeys = new string[0];
  			ItemEditors = new List<ItemEditor>();
  			AddedDefinitions = new List<string>();
  			DeletedIndexes = new List<int>();
  		}
  
          #endregion
  
          #region Properties
  
          public string Label { get; set; }
  
          public List<ItemEditor> ItemEditors { get; set; }
  
  		/// <summary>Gets the parent item where to look for items.</summary>
  		public int ParentItemID
          {
              get { return (int) (ViewState["CurrentItemID"] ?? 0); }
              set { ViewState["CurrentItemID"] = value; }
          }
  
          /// <summary>Gets the parent item where to look for items.</summary>
          public string ParentItemType
          {
              get { return (string) (ViewState["CurrentItemType"] ?? string.Empty); }
              set { ViewState["CurrentItemType"] = value; }
          }
  
          /// <summary>Gets or sets the zone name to list.</summary>
          public string ZoneName
          {
              get { return (string)ViewState["ZoneName"]; }
              set { ViewState["ZoneName"] = value; }
          }
  
          /// <summary>The minimum type to filter children by.</summary>
          public Type MinimumType
          {
              get { return Type.GetType((string)ViewState["MinimumType"] ?? typeof(object).FullName); }
              set { ViewState["MinimumType"] = (value ?? typeof(object)).AssemblyQualifiedName; }
          }
  
          public IList<string> AddedDefinitions { get; set; }
  
  		public IList<int> DeletedIndexes { get; set; }
  
          protected virtual IEngine Engine
          {
              get { return N2.Context.Current; }
          }
  
          public IDefinitionManager Definitions
          {
              get { return definitions ?? (definitions = Engine.Definitions); }
          }
  
          public PartsAdapter Parts
          {
              get
              {
                  return partsAdapter ??
                         (partsAdapter =
                          Engine.Resolve<IContentAdapterProvider>().ResolveAdapter<PartsAdapter>(ParentItem));
              }
              set { partsAdapter = value; }
          }
  
          public ItemDefinition CurrentItemDefinition
          {
              get { return Definitions.GetDefinition(Type.GetType(ParentItemType)); }
          }
  
          public IEnumerable<LinkButton> AddButtons
          {
              get { return ItemUtility.FindInChildren<LinkButton>(addPanel).Where(lb => lb.CssClass == "addButton").ToList(); }
          }
  
          #endregion
  
          public ContentItem ParentItem
          {
              get
              {
                  return parentItem
                         ?? (parentItem = Engine.Persister.Get(ParentItemID));
              }
              set
              {
                  if (value == null)
                      throw new ArgumentNullException("value");
  
                  parentItem = value;
                  ParentItemID = value.ID;
                  ParentItemType = value.GetContentType().AssemblyQualifiedName;
              }
          }
  
  		public string[] AllowedTemplateKeys { get; set; }
  
  		protected override void OnInit(EventArgs e)
          {
              base.OnInit(e);
  
              Controls.Add(itemEditorsContainer);
  
              Controls.Add(addPanel);
          }
  
          protected override void LoadViewState(object savedState)
          {
              var p = (Triplet) savedState;
              base.LoadViewState(p.First);
              AddedDefinitions = (List<string>) p.Second;
              DeletedIndexes = (List<int>) p.Third;
              EnsureChildControls();
              logger.Debug("addedTypes: " + AddedDefinitions.Count + ", deletedIndexes: " + DeletedIndexes.Count);
          }
  
          private HtmlGenericControl CreateControl(Control parent, string tagName, string className)
          {
              var hgc = new HtmlGenericControl(tagName);
              parent.Controls.Add(hgc);
              hgc.Attributes["class"] = className;
              return hgc;
          }
  
          protected override void CreateChildControls()
          {
              if (!string.IsNullOrEmpty(Label))
              {
                  Controls.AddAt(0, new Label { Text = Label, CssClass = "editorLabel" });
              }
  
              foreach (ContentItem item in GetItems())
              {
                  CreateItemEditor(item);
              }
  			itemEditorsContainer.Attributes["class"] = "item-editor-list-items items-count-" + itemEditorsContainer.Controls.Count;
  
  			var allowedDefinitions = Parts.GetAllowedDefinitions(ParentItem, ZoneName, Page.User);
  			allowedDefinitions = allowedDefinitions.Where(d => MinimumType.IsAssignableFrom(d.ItemType));
  			allowedDefinitions = allowedDefinitions.WhereAuthorized(Engine.SecurityManager, Engine.RequestContext.User, ParentItem);
              var allowedChildren = allowedDefinitions.SelectMany(d => Parts.GetTemplates(ParentItem, d))
  				.WhereAllowed(ParentItem, ZoneName, Engine.RequestContext.User, Engine.Definitions, Engine.SecurityManager)
                  .ToList();
  			if (AllowedTemplateKeys != null)
  				allowedChildren = allowedChildren.Where(td => AllowedTemplateKeys.Contains(td.Name)).ToList();
              if (allowedChildren.Count == 0)
              {
                  var alert = CreateControl(addPanel, "div", "alert");
                  alert.InnerHtml = "Cannot add any parts due to zone/user/type restrictions";
              }
              else if (allowedChildren.Count == 1)
              {
                  var btn = CreateButton(addPanel, allowedChildren[0]);
                  btn.CssClass = "btn";
              }
              else
              {
                  var btnGroup = CreateControl(addPanel, "div", "btn-group");
                  var toggle = CreateControl(btnGroup, "a", "btn dropdown-toggle");
                  toggle.Attributes["data-toggle"] = "dropdown";
                  toggle.Attributes["href"] = "#";
                  toggle.InnerHtml = "<b class='fa fa-plus-circle'></b> " + (Utility.GetLocalResourceString("Add") ?? "Add") + " <b class='caret'></b>";
  
                  var dropdownMenu = CreateControl(btnGroup, "ul", "dropdown-menu");
  
  				foreach (var template in allowedChildren)
                  {
  					var li = CreateControl(dropdownMenu, "li", "");
  					CreateButton(li, template);
                  }
              }
  
              base.CreateChildControls();
          }
  
          private LinkButton CreateButton(Control container, TemplateDefinition template)
          {
              var button = new LinkButton
              {
  				ID = "iel" + ID + "_" + template.Definition.GetDiscriminatorWithTemplateKey().Replace('/', '_'),
  				Text = string.IsNullOrEmpty(template.Definition.IconUrl)
                      ? string.Format("<b class='{0}'></b> {1}", template.Definition.IconClass, template.Definition.Title)
                      : string.Format("<img src='{0}' alt='ico'/>{1}", template.Definition.IconUrl, template.Definition.Title),
                  ToolTip = template.Definition.ToolTip,
                  CausesValidation = false,
                  CssClass = "addButton"
              };
              button.Command += (s, a) =>
              {
  				var parentEditor = ItemUtility.FindInParents<ItemEditor>(Parent);
  				var parentVersion = parentEditor.GetAutosaveVersion()
  					?? ParentItem;
  
  				var path = EnsureDraft(parentVersion);
  
  				UpdateItemFromTopEditor(path);
  
  				ContentItem item = CreateItem(template.Definition);
  				item.AddTo(path.CurrentItem, ZoneName);
  				Utility.UpdateSortOrder(path.CurrentItem.Children).ToList();
  
  				if (path.CurrentPage.ID != 0 || path.CurrentPage.VersionOf.HasValue)
  				{
  					var cvr = Engine.Resolve<ContentVersionRepository>();
  					cvr.Save(path.CurrentPage);
  
  					RedirectToVersionOfSelf(path.CurrentPage);
  				}
  				else
  				{
  					Engine.Persister.SaveRecursive(path.CurrentPage);
  					RedirectToVersionOfSelf(path.CurrentPage);
  				}
  			};
              container.Controls.Add(button);
              return button;
          }
  
          protected override object SaveViewState()
          {
              return new Triplet(base.SaveViewState(), AddedDefinitions, DeletedIndexes);
          }
  
          public virtual IList<ContentItem> GetItems()
          {
              if (ParentItem != null)
              {
  
gt:                 var filter = new Collections.AllFilter(GetFilters());