/*******************************************************}
{                                                       }
{               Borland DB Web                          }
{           Data aware Web controls                     }
{  Copyright (c) 2003 Borland Software Corporation      }
{                                                       }
{*******************************************************/

using System;
using System.Data;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;

namespace Borland.Data.Web
{


	/// <summary>
	/// Data aware DataGrid class, for use with DBWebDataSource
	/// </summary>
	[Designer("Borland.Data.Web.DBWebGridDesigner"),
   ToolboxBitmap(typeof(Borland.Data.Web.DBWebGrid),
   "Borland.Data.Web.DBWebGrid.bmp"),
	ToolboxData("<{0}:DBWebGrid runat=server></{0}:DBWebGrid>")]
	public class DBWebGrid : DataGrid, IDBWebDataLink, IPostBackDataHandler
	{

      private DataGrid FDataGrid;
      private DataTable dt;
      private DBWebDataLink FDataLink;
      private IDBWebDataLink IDataLink;
      private int NewPageIndex;
      private bool FReadOnly;
      private bool FHandlePagingEvents;
      private bool FHandleColumnEvents;
      private bool FInternalSet;

		public DBWebGrid() : base()
		{
      	FDataGrid = new DataGrid();
         FDataGrid.Width = Unit.Parse("300px");
         dt = new DataTable();
         string columnName1 = BdwResources.GetString("defaultColumnName1");
         string columnName2 = BdwResources.GetString("defaultColumnName2");
         dt.Columns.Add(columnName1, Type.GetType("System.String"));
         dt.Columns.Add(columnName2, Type.GetType("System.String"));
         FDataGrid.DataSource = dt;
         NewPageIndex = -1;
         FDataLink = new DBWebDataLink(this);
         IDataLink = (FDataLink as IDBWebDataLink);
         FInternalSet = false;
         FHandleColumnEvents = true;
         FHandlePagingEvents = true;
         AllowPaging = true;
      }

		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
			if( Page != null )
				Page.RegisterRequiresPostBack(this);
      }

		protected override void OnPreRender(EventArgs args)
		{
			base.OnPreRender(args);
			string s = Page.Request.QueryString[DBWebConst.sBorlandImageID];
         if( s != null )
         	return;
         Page.RegisterHiddenField(DBWebConst.sDBWebDataGrid + DBWebConst.Splitter + IDataLink.TableName,
         								 this.ID);
      	if( this.AutoGenerateColumns )
         	Page.Session[this.ID + DBWebConst.sAutoGenerateColumns] = true;
         else
         	Page.Session[this.ID + DBWebConst.sAutoGenerateColumns] = false;
         int ColIndex = 0;
         for( int i = 0; i < Columns.Count; i++ )
         {
         	if( Columns[i] is BoundColumn )
            {
            	if( (Columns[i] as BoundColumn).ReadOnly == false )
               {
	            	Page.Session[this.ID + Convert.ToString(ColIndex)] = (Columns[i] as BoundColumn).DataField;
   	            ColIndex++;
               }
            }
         }
         // Updates will not work correctly if Bound Columns are added with
         //  AutoGenerate set to true.
      	if( this.AutoGenerateColumns && ColIndex > 0 )
         	Page.Session[this.ID + DBWebConst.sInvalidBoundColumns] = true;
         DataBind();
		}

      #region IDBWebDataLink
      string IDBWebDataLink.TableName
      {
      	get
         {
         	return IDataLink.TableName;
         }
         set
         {
         	IDataLink.TableName = value;
         }
      }
      IDBDataSource IDBWebDataLink.DBDataSource
      {
      	get
         {
         	return IDataLink.DBDataSource;
         }
         set
         {
         	IDataLink.DBDataSource = value;
         }
      }
      [Editor(typeof(Borland.Data.Web.TableNamePropEditor), typeof(UITypeEditor)),
		LocalizableCategoryAttribute("DBWebControl"),
		DefaultValue(null)]
      public string TableName
      {
      	get
         {
	      	return IDataLink.TableName;
         }
      	set
         {
	      	IDataLink.TableName = value;
         }
      }
		[LocalizableCategoryAttribute("DBWebControl"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		DefaultValue(null)]
      public IDBDataSource DBDataSource
      {
      	get
         {
         	return IDataLink.DBDataSource;
         }
         set
         {
         		IDataLink.DBDataSource = value;
         }
      }


      [Editor(typeof(Borland.Data.Web.NoDataSourceEditor), typeof(UITypeEditor)),
      DesignOnly(true),
      DefaultValue(null),
      Browsable(false)]
      public override object DataSource
      {
       	get
         {
         	return base.DataSource;
         }
         set
         {
            if( ClassUtils.IsDesignTime(Page) || FInternalSet )
          		base.DataSource = value;
         }
      }

      #endregion

      #region IPostBackDataHandler
      // RaisePostDataChangedEvent is called prior to DataBind()
      // DataSet and related properties are NOT available here
      // Child controls are not available
		bool IPostBackDataHandler.LoadPostData(string postDataKey,
			NameValueCollection postCollection)
      {
         if( this.Visible == false )
         	return false;
			if( ClassUtils.PostCollectionHasValue(postCollection, TableName, DBWebConst.sFirstText) )
            CurrentPageIndex = 0;
         else if( ClassUtils.PostCollectionHasValue(postCollection, TableName, DBWebConst.sLastRow) )
         	CurrentPageIndex = PageCount -1;
      	FDataLink.LoadPostData(postDataKey, postCollection);
         return false;
      }

	   void IPostBackDataHandler.RaisePostDataChangedEvent()
   	{
	   }
      #endregion

      [LocalizableCategoryAttribute("Behavior"),
      DefaultValue(false)]
      public bool ReadOnly
      {
      	get
         {
         	return FReadOnly;
         }
         set
         {
         	FReadOnly = value;
         }
      }

      [LocalizableCategoryAttribute("DBWebControl"),
      DefaultValue(true)]
      public bool HandlePagingEvents
      {
      	get
         {
         	return FHandlePagingEvents;
         }
         set
         {
         	FHandlePagingEvents = value;
         }
      }

      [LocalizableCategoryAttribute("Paging"),
      DefaultValue(true)]
      public override bool AllowPaging
      {
      	get
         {
         	return base.AllowPaging;
         }
         set
         {
         	base.AllowPaging = value;
         }
      }

      [LocalizableCategoryAttribute("DBWebControl"),
      DefaultValue(true)]
      public bool HandleColumnEvents
      {
      	get
         {
         	return FHandleColumnEvents;
         }
         set
         {
         	FHandleColumnEvents = value;
         }
      }

		protected override void OnPageIndexChanged(DataGridPageChangedEventArgs e )
      {
      	if( FHandlePagingEvents )
         {
	      	UpdatePageIndex( e );
         }
         base.OnPageIndexChanged(e);
      }

      protected override void OnEditCommand(DataGridCommandEventArgs e )
      {
      	if( FHandleColumnEvents )
         {
	         int FCurrentIndex = e.Item.ItemIndex;
   	      if( AllowPaging && CurrentPageIndex > 0 )
      	   	FCurrentIndex += this.PageSize * CurrentPageIndex;
            FDataLink.AddToSession(TableName, TableName + DBWebConst.Splitter + DBWebConst.sSetRow,
            	Convert.ToString(FCurrentIndex) );
         }
         base.OnEditCommand(e);
      }
      protected override void OnCancelCommand(DataGridCommandEventArgs e )
      {
      	if( FHandleColumnEvents )
         {
         	FDataLink.AddToSession(TableName, TableName + DBWebConst.Splitter + DBWebConst.sCancelChange, "true" );
         }
         base.OnCancelCommand(e);
      }

      protected override void OnDeleteCommand(DataGridCommandEventArgs e )
      {
      	int FCurrentIndex = -1;
      	if( FHandleColumnEvents )
         {
	         FCurrentIndex = e.Item.ItemIndex;
   	      if( AllowPaging && CurrentPageIndex > 0 )
      	   	FCurrentIndex += this.PageSize * CurrentPageIndex;
            FDataLink.AddToSession(TableName, TableName + DBWebConst.Splitter + DBWebConst.sDeleteRow,
            							Convert.ToString(FCurrentIndex));
         }
         base.OnDeleteCommand(e);
      }

		public void UpdatePageIndex(System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
		{
      	int NewPageIndex = e. NewPageIndex;
         int iRow = 0;
         int iRowCount = PageSize;
         Object o = Page.Session[TableName + DBWebConst.sCurrentRowIndex];
         if( o != null )
         	iRow = Convert.ToInt32(o);
         o = Page.Session[TableName + DBWebConst.sRowCount];
         if( o != null )
         	iRowCount = Convert.ToInt32(o);

         while( CurrentPageIndex != NewPageIndex )
         {
         	if( NewPageIndex > CurrentPageIndex )
            {
            	iRow = Math.Min(iRow + PageSize, iRowCount -1);
               CurrentPageIndex++;
            }
            else if( NewPageIndex < CurrentPageIndex )
            {
               iRow = Math.Max(0, iRow - PageSize);
               CurrentPageIndex--;
            }
         }
         FDataLink.AddToSession(TableName, TableName + DBWebConst.Splitter + DBWebConst.sSetRow,
            	Convert.ToString(iRow) );
      }

      private void SetGridProps()
      {
      	FDataGrid.AllowCustomPaging = this.AllowCustomPaging;
      	FDataGrid.AllowPaging = this.AllowPaging;
      	FDataGrid.PageSize = this.PageSize;
         FDataGrid.PagerStyle.Visible = this.Visible;
         FDataGrid.PageSize = this.PageSize;
      	FDataGrid.CellPadding = this.CellPadding;
      	FDataGrid.CellSpacing = this.CellSpacing;
         ClassUtils.SetAppearanceProperties(FDataGrid, this);
         ClassUtils.SetBehaviorProperties(FDataGrid, this);
         ClassUtils.SetControlProps(FDataGrid, this);
      }

      private int CalcEditItemIndex(int FCurrentTableRow, int FRowCount)
      {
         if( !AllowPaging )
         	return FCurrentTableRow;
         // Page changed by Navigator buttons
         CurrentPageIndex = 0;
         while( FCurrentTableRow >= PageSize )
         {
         	FCurrentTableRow -= PageSize;
            CurrentPageIndex++;
         }
         return FCurrentTableRow;
      }

      public override void DataBind()
		{
         try
         {
	         // base.DataBind() triggers setting of DBDataSource property from aspx file
   	   	base.DataBind();
				if( FDataLink.IsDataBound )
         	{
         		Object ds = IDataLink.DBDataSource.GetDataSource(Page);
	            if( ds!= null )
   	         {
      	         Object table = IDataLink.DBDataSource.GetTableOrView(Page, IDataLink.TableName);
         	      // might be a DataView or a DataTable;
            	   FInternalSet = true;
               	try
      	         {
	               	DataSource = table;
   	            }
	               finally
   	            {
      	         	FInternalSet = false;
         	      }
            	   int itemIndex = CalcEditItemIndex(IDataLink.DBDataSource.GetDisplayRow(Page, IDataLink.TableName),
               															  IDataLink.DBDataSource.GetRowCount(Page, IDataLink.TableName));
	               SelectedIndex = itemIndex;
   	            if( Enabled && !ReadOnly )
      	         	EditItemIndex = itemIndex;
         	      else
            	   	EditItemIndex = -1;
         			base.DataBind();
               }
            }
         }
         catch(Exception ex)
         {
         	if( !ClassUtils.IsDesignTime(Page) )
            {
	            Page.Response.Write(ClassUtils.GetInternalError(Page, IDataLink, ex, this.ID));
            }
            else
            	throw new Exception(ex.Message);
         }
      }

		protected override void Render(HtmlTextWriter output)
		{
      	if( ClassUtils.IsDesignTime(Page) && !FDataLink.IsDataBound )
         {
         	FDataGrid.EditItemIndex = 0;
            FDataGrid.DataSource = dt;
            FDataGrid.DataBind();
            FDataGrid.RenderControl(output);
			}
         else
         {
	      	bool error = ClassUtils.OutputErrors(Page, output, IDataLink);
   	      if( !error || (IDataLink.DBDataSource as DBWebDataSource).ErrorOption != ErrorHtmlOption.logOnErrorPage )
      	   	base.Render(output);
         	else  // if going to a separate error hmtl page, output "OK" button.
	         {
   	      	ClassUtils.OutputOKButton(output);
         	   Page.Response.End();
	         }
         }
		}
  	}
}
