context: /********
   * This file is part of Ext.NET.
   *     
   * Ext.NET is free software: you can redistribute it and/or modify
   * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as 
   * published by the Free Software Foundation, either version 3 of the 
   * License, or (at your option) any later version.
   * 
   * Ext.NET is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
   * 
   * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
   * along with Ext.NET.  If not, see <http://www.gnu.org/licenses/>.
   *
   *
   * @version   : 2.0.0.beta - Community Edition (AGPLv3 License)
   * @author    : Ext.NET, Inc. http://www.ext.net/
   * @date      : 2012-03-07
   * @copyright : Copyright (c) 2007-2012, Ext.NET, Inc. (http://www.ext.net/). All rights reserved.
   * @license   : GNU AFFERO GENERAL PUBLIC LICENSE (AGPL) 3.0. 
   *              See license.txt and http://www.ext.net/license/.
   *              See AGPL License at http://www.gnu.org/licenses/agpl-3.0.txt
   ********/
  
  using System;
  using System.ComponentModel;
  using System.Globalization;
  using System.Reflection;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  
  using Ext.Net.Utilities;
  
  namespace Ext.Net
  {
      /// <summary>
      /// 
      /// </summary>
      [Meta]
      public abstract partial class TreeStoreBase : AbstractStore, IAjaxPostBackEventHandler
      {
          /// <summary>
          /// 
          /// </summary>
          [ConfigOption("autoLoad")]
          [DefaultValue(false)]
          [Description("")]
          protected override bool AutoLoadProxy
          {
              get
              {
                  return false;
              }
          }
          
          /// <summary>
          /// Remove previously existing child nodes before loading. Default to true.
          /// </summary>
          [Meta]
          [ConfigOption]        
          [DefaultValue(true)]
          [Description("Remove previously existing child nodes before loading. Default to true.")]
          public virtual bool ClearOnLoad
          {
              get
              {
                  return this.State.Get<bool>("ClearOnLoad", true);
              }
              set
              {
                  this.State.Set("ClearOnLoad", value);
              }
          }
  
          /// <summary>
          /// The default root id. Defaults to 'root'
          /// </summary>
          [Meta]
          [ConfigOption]
          [DefaultValue("root")]
          [Description("The default root id. Defaults to 'root'")]
          public virtual string DefaultRootId
          {
              get
              {
                  return this.State.Get<string>("DefaultRootId", "root");
              }
              set
              {
                  this.State.Set("DefaultRootId", value);
              }
          }
  
          /// <summary>
          /// The root property to specify on the reader if one is not explicitly defined.
          /// </summary>
          [Meta]
          [ConfigOption]
          [DefaultValue("")]
          [Description("The root property to specify on the reader if one is not explicitly defined.")]
          public virtual string DefaultRootProperty
          {
              get
              {
                  return this.State.Get<string>("DefaultRootProperty", "");
              }
              set
              {
                  this.State.Set("DefaultRootProperty", value);
              }
          }
  
          /// <summary>
          /// The root property to specify on the reader if one is not explicitly defined.
          /// </summary>
          [Meta]
          [ConfigOption]
          [DefaultValue(null)]
          [Description("The root property to specify on the reader if one is not explicitly defined.")]
          public virtual bool? FolderSort
          {
              get
              {
                  return this.State.Get<bool?>("FolderSort", null);
              }
              set
              {
                  this.State.Set("FolderSort", value);
              }
          }
  
          /// <summary>
          /// The name of the parameter sent to the server which contains the identifier of the node. Defaults to 'node'.
          /// </summary>
          [Meta]
          [ConfigOption]
          [DefaultValue("node")]
          [Description("The name of the parameter sent to the server which contains the identifier of the node. Defaults to 'node'.")]
          public virtual string NodeParam
          {
              get
              {
                  return this.State.Get<string>("NodeParam", "node");
              }
              set
              {
                  this.State.Set("NodeParam", value);
              }
          }
  
          private NodeCollection root;
  
          /// <summary>
          /// The root node for the tree.
          /// </summary>
          [Category("7. TreePanel")]
          [NotifyParentProperty(true)]
          [ConfigOption("root>Primary", JsonMode.Object)]
          [PersistenceMode(PersistenceMode.InnerProperty)]
          [Description("The root node for the tree.")]
          public virtual NodeCollection Root
          {
              get
              {
                  if (this.root == null)
                  {
                      this.root = new NodeCollection(true);
                      this.root.Owner = this;
                  }
  
                  return this.root;
              }
          }
  
          /// <summary>
          /// Returns the root node for this tree.
          /// </summary>
          /// <returns></returns>
          public virtual NodeProxy GetRootNode()
          {
              return NodeProxy.GetRootNode(this);
          }
  
          /// <summary>
          /// Returns the record node by id
          /// </summary>
          /// <param name="id"></param>
          /// <returns></returns>
          public virtual NodeProxy GetNodeById(object id)
          {
              return NodeProxy.GetNodeById(this, id);
          }
  
          /// <summary>
          /// Sets the root node for this store. See also the root config option.
          /// </summary>
          /// <param name="node"></param>
          public virtual void SetRootNode(Node node)
          {
              this.Call("setRootNode", new JRawValue(node.ToScript()));
          }
  
  
          private static readonly object EventReadData = new object();
  
          /// <summary>
          /// 
          /// </summary>
          [Description("")]
          public delegate void ReadDataEventHandler(object sender, NodeLoadEventArgs e);
  
          /// <summary>
          /// 
          /// </summary>
          [Category("Action")]
          [Description("")]
          public event ReadDataEventHandler ReadData
          {
              add
              {
                  this.Events.AddHandler(EventReadData, value);
              }
              remove
              {
                  this.Events.RemoveHandler(EventReadData, value);
              }
          }
  
          internal virtual void OnReadData(NodeLoadEventArgs e)
          {
              ReadDataEventHandler handler = (ReadDataEventHandler)Events[EventReadData];
  
              if (handler != null)
              {
                  handler(this, e);
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="eventArgument"></param>
          /// <param name="extraParams"></param>
          public void RaiseAjaxPostBackEvent(string eventArgument, ParameterCollection extraParams)
          {
              bool success = true;
              string msg = null;
  
              StoreResponseData response = new StoreResponseData(true);
  
              try
              {
                  if (eventArgument.IsEmpty())
                  {
                      throw new ArgumentNullException("eventArgument");
                  }
  
                  //string data = null;
                  //JToken parametersToken = null;
  
                  //if (this.DirectConfig != null)
                  //{
                  //    JToken serviceToken = this.DirectConfig.SelectToken("config.serviceParams", false);
  
                  //    if (serviceToken != null)
                  //    {
                  //        data = JSON.ToString(serviceToken);
                  //    }
                  //}
  
                  switch (eventArgument)
                  {
                      case "read":
                          if (this.IsBoundUsingDataSourceID)
                          {
                              Node bindNode = new Node();
                              this.DataBindNode(bindNode, extraParams["dataPath"]);
                              response.Data = bindNode.Children.ToJson();
                          }
                          else
                          {
                              NodeLoadEventArgs e = new NodeLoadEventArgs(extraParams);
                              this.OnReadData(e);
                              NodeCollection nodes = e.Nodes;
                              success = e.Success;
                              msg = e.ErrorMessage;
                              response.Data = nodes != null ? nodes.ToJson() : null;
                          }
                          break;
                  }
              }
              catch (Exception ex)
              {
                  success = false;
                  msg = this.IsDebugging ? ex.ToString() : ex.Message;
  
                  if (this.ResourceManager.RethrowAjaxExceptions)
                  {
                      throw;
                  }
              }
  
              
  
              //if (success)
              //{
              //    switch (eventArgument)
              //    {
              //        case "read":
  
              //            if (this.RequiresDataBinding)
              //            {
              //                this.DataBind();
              //            }
  
              //            response.Data = this.GetAjaxDataJson();
              //            PageProxy dsp = this.Proxy.Primary as PageProxy;
              //            response.Total = dsp != null ? dsp.Total : -1;
              //            break;
              //    }
              //}
              
              ResourceManager.ServiceResponse = new Response { Data = response.ToString(), Success = success, Message = msg };
          }
  
          #region DataBound
  
          private static readonly object EventDataBound = new object();
  
          private object dataSource;
          private bool requiresDataBinding;
          private bool preRendered;
          private bool requiresBindToNull;        
  
          /// <summary> 
          /// 
          /// </summary>
          [Bindable(true)]
          [DefaultValue(null)]
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
          public virtual object DataSource
          {
              get
              {
                  return this.dataSource;
              }
              set
              {
                  if (value != null)
                  {
                      this.ValidateDataSource(value);
                  }
                  this.IsDataBound = false;
                  this.dataSource = value;
                  this.OnDataPropertyChanged();
              }
          }
  
  
          /// <summary> 
          /// 
          /// </summary>
          [DefaultValue("")]
          [IDReferenceProperty(typeof(HierarchicalDataSourceControl))]
          public virtual string DataSourceID
          {
              get
              {                
                  return this.State.Get<string>("DataSourceID", string.Empty);
              }
              set
              {
                  if (String.IsNullOrEmpty(value) && !String.IsNullOrEmpty(this.DataSourceID))
                  {
                      this.requiresBindToNull = true;
                  }
  
                  this.IsDataBound = false;
                  this.State.Set("DataSourceID", value);
                  this.OnDataPropertyChanged();
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected bool IsBoundUsingDataSourceID
          {
              get
              {
                  return (this.DataSourceID.Length > 0);
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected bool RequiresDataBinding
          {
              get
              {
                  return this.requiresDataBinding;
              }
              set
              {
                  if (value && this.preRendered && this.DataSourceID.Length > 0 && this.Page != null && !this.Page.IsCallback && !RequestManager.IsAjaxRequest)
                  {
                      this.requiresDataBinding = true;
                      EnsureDataBound();
                  }
                  else
                  {
                      this.requiresDataBinding = value;
                  }
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          public event EventHandler DataBound
          {
              add
              {
                  this.Events.AddHandler(EventDataBound, value);
              }
              remove
              {
                  this.Events.RemoveHandler(EventDataBound, value);
              }
          }
  
          private bool ajaxDataBindingRequired = true;
  
          /// <summary>
          /// 
          /// </summary>
          protected virtual void AjaxDataBind()
          {
              if (RequestManager.IsAjaxRequest && this.IsAjaxRequestInitiator)
              {
                  return;
              }
  
              if (!this.ajaxDataBindingRequired || this.IsParentDeferredRender)
              {
                  return;
              }
  
              this.RequiresDataBinding = false;
              this.PerformSelect();
  
              //this.GenerateAjaxResponseScript();
          }
  
          private bool isDataBound;
  
          private bool IsDataBound
          {
              get
              {
                  return this.isDataBound;
              }
              set
              {
                  this.isDataBound = value;
              }
          }
  
          /// <summary>
          /// 
          /// </summary> 
          public override void DataBind()
          {
              base.DataBind();
  
              if (this.IsDataBound)
              {
                  return;
              }
  
              if (RequestManager.IsAjaxRequest && !this.IsAjaxRequestInitiator && !this.IsDynamic)
              {
                  this.AjaxDataBind();
              }
  
              if (((!RequestManager.IsAjaxRequest || this.IsDynamic) && this.Proxy.Count == 0) || (RequestManager.IsAjaxRequest && this.IsAjaxRequestInitiator))
              {
                  this.RequiresDataBinding = false;
                  this.PerformSelect();
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected virtual void EnsureDataBound()
          {
              if (this.RequiresDataBinding && (this.DataSourceID.Length > 0 || this.requiresBindToNull))
              {
                  this.DataBind();
                  this.requiresBindToNull = false;
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="e"></param>
          protected virtual void OnDataBound(EventArgs e)
          {
              EventHandler handler = this.Events[EventDataBound] as EventHandler;
              if (handler != null)
              {
                  handler(this, e);
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected virtual void OnDataPropertyChanged()
          {
              this.RequiresDataBinding = true;
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="e"></param>
          protected override void OnInit(EventArgs e)
          {
              base.OnInit(e);
  
              if (this.Page != null)
              {
                  if (!RequestManager.IsAjaxRequest && this.Page.IsPostBack)
                  {
                      this.RequiresDataBinding = true;
                  }
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="e"></param>
          protected override void OnPreRender(EventArgs e)
          {
              this.preRendered = true;
              if (!RequestManager.IsAjaxRequest)
              {
                  this.EnsureDataBound();
              }
              base.OnPreRender(e);
          }
  
          #endregion
  
          #region HierarchicalDataBound
  
          //private IHierarchicalDataSource currentHierarchicalDataSource;
          private string currentSiteMapNodeDataPath;
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="dataSource"></param>
          protected virtual void ValidateDataSource(object dataSource)
          {
              if ((dataSource == null) ||
                  (dataSource is IHierarchicalEnumerable) ||
                  (dataSource is NodeCollection) ||
                  (dataSource is IHierarchicalDataSource))
              {
                  return;
              }
              throw new InvalidOperationException(ServiceMessages.INVALID_DATASOURCE);
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected virtual void PerformSelect()
          {
              this.OnDataBinding(EventArgs.Empty);
              this.PerformDataBinding();
              this.RequiresDataBinding = false;            
              this.OnDataBound(EventArgs.Empty);
              this.IsDataBound = true;
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          protected virtual void OnDataSourceChanged(object sender, EventArgs e)
          {
              this.RequiresDataBinding = true;
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <returns></returns>
          protected virtual IHierarchicalDataSource GetDataSource()
          {
              if (this.DataSource != null && this.IsBoundUsingDataSourceID)
              {
                  throw new HttpException("Control bound using both DataSourceID and DataSource properties.");
              }
  
              if (this.DataSource is IHierarchicalDataSource)
              {
                  return (IHierarchicalDataSource)this.DataSource;
              }
  
              IHierarchicalDataSource ds = null;
              string dataSourceID = this.DataSourceID;
  
              if (dataSourceID.Length != 0)
              {
                  Control control = Utilities.ControlUtils.FindControl(this, this.DataSourceID);
                  if (control == null)
                  {
                      throw new HttpException("A IDatasource Control with the ID '{0}' could not be found.".FormatWith(this.DataSourceID));
                  }
                  ds = control as IHierarchicalDataSource;
                  if (ds == null)
                  {
                      throw new HttpException("The control with ID '{0}' is not a control of type IHierarchicalDataSource.".FormatWith(this.DataSourceID));
                  }
              }
              return ds;
          }
  
          private NodeBindingCollection dataBindings;
  
          /// <summary>
          /// 
          /// </summary>
          [NotifyParentProperty(true)]
          [PersistenceMode(PersistenceMode.InnerProperty)]
          public virtual NodeBindingCollection DataBindings
          {
              get
              {
                  if (this.dataBindings == null)
                  {
                      this.dataBindings = new NodeBindingCollection();
                  }
  
                  return this.dataBindings;
              }
          }
  
          /// <summary>
          /// 
          /// </summary>
          /// <param name="viewPath"></param>
          /// <returns></returns>
          protected virtual HierarchicalDataSourceView GetData(string viewPath)
          {
              string currentViewPath = viewPath;
              IHierarchicalDataSource ds = this.GetDataSource();
  
              if (ds == null)
              {
                  return null;
              }
              
              HierarchicalDataSourceView view = ds.GetHierarchicalView(currentViewPath);
              if (view == null)
              {
                  throw new InvalidOperationException("View is not found");
              }
              return view;
          }
  
          /// <summary>
          /// 
          /// </summary>
          protected virtual void PerformDataBinding()
          {
              if (String.IsNullOrEmpty(this.DataSourceID) && this.DataSource == null)
              {
                  this.Root.Clear();
                  
                  return;
              }
  
              if (this.DataSource is NodeCollection)
              {
                  var nodes = (NodeCollection)this.DataSource;
                  if (this.Root.Count == 0 && nodes.Count == 1)
                  {
                      this.Root.AddRange(nodes);
                  }
  
gt:                 else if (this.Root.Count > 0)