//------------------------------------------------------------------------------
// <copyright file=”*.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{

  [DesignerCategory("Code")]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  [DesignTimeVisible(false)]
  [ToolboxItem(false)]
  public class DataVertGridRow : PropertyAxisBar, IGridLineHost
 {
    #region private consts
    #endregion

    #region privates
    private int height = 64;

    //private string dataPropertyName = string.Empty;

    //private Color backColor = Color.Empty;
    private readonly GridLine vertLine;

    internal bool WidthStored;
    internal bool SelectedInternal;
    internal float FillWeightInternal = 100;
    internal bool OmitFromWidthCalculation;
    //internal int DisplayIndexQuery = -1;
    //internal int DisplayIndexQueryIndex = -1;
    #endregion

    public DataVertGridRow()
    {
      this.vertLine = new GridLine(this);
    }

    #region design-time properties

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataVertGridRowTitle Title
    {
      get { return (DataVertGridRowTitle)base.Title; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine VertLine
    {
      get
      {
        return vertLine;
      }
    }
    #endregion

    #region runtime properties
    [Browsable(false)]
    public bool IsColumnVisible
    {
      get
      {
        if (Grid == null)
          return Visible;
        else
          return Visible && Grid.RowCanBeVisible(this);
      }
    }

    [Browsable(false)]
    public new DataVertGridEh Grid
    {
      get
      {
        return (DataVertGridEh)base.Grid;
      }

      protected internal set
      {
        base.Grid = value;
      }
    }

    [Browsable(false)]
    public bool IsDataBound
    {
      get { return (PropDescr != null); }
    }

    [DefaultValue(false)]
    [Browsable(false)]
    public bool Selected
    {
      get
      {
        return false;
      }
    }

    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //[Browsable(false)]
    //public int Height
    //{
    //  get { return CalcDefaultRowHeight(); }
    //}

    ////TODO Postpone. 
    //[Browsable(false)]
    //public DataVertGridColumnRowCells RowCells
    //{
    //  get
    //  {
    //    return rowCells;
    //  }
    //}

    /// <summary>
    /// The cell for a new virtual row.
    /// New virtual row - is a row that does not have an appropriate entry in the DatGrid.Rows collection.
    /// </summary>
    [Browsable(false)]
    public virtual DataAxisGridDataCellMan NewVirtualRowCell
    {
      get
      {
        return Grid.EmptyDataCell;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public virtual int Height
    {
      get { return height; }
      internal set { height = value; }
    }
    #endregion

    #region internal fields and properties
    #endregion

    #region Methods
    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    protected virtual void GridLineChanged(GridLine gl)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      return Grid.RowOptions.HorzLine.Visible;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      return Grid.RowOptions.HorzLine.Color;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return Grid.RowOptions.HorzLine.Style;
    }

    //Other
    protected override DataAxisGridBarTitle CreateDataAxisGridBarTitle()
    {
      return new DataVertGridRowTitle(this);
    }

    protected override void GridChanged()
    {
      base.GridChanged();
      UpdateDefaultPadding();
    }

    public override BaseGridCellManager GetDataCellMan(object listItemBar)
    {
      return GetColumnCellMan(listItemBar);
    }

    public DataAxisGridDataCellMan GetColumnCellMan(object listItem)
    {
      return InternalGetColumnCell(listItem);
    }

    protected internal DataAxisGridDataCellMan InternalGetColumnCell(object listItem)
    {
      DataVertGridDataCellObjectNeededEventArgs e = new DataVertGridDataCellObjectNeededEventArgs(this, listItem);
      OnGetColumnCell(e);
      if (e.CellObject == null)
        e.CellObject = Grid.EmptyDataCell;
      return e.CellObject;
    }

    protected virtual void OnGetColumnCell(DataVertGridDataCellObjectNeededEventArgs e)
    {
      //TODO Postpone. 
      //DataGridDataCellObjectNeededEventHandler eh = this.Events[EventKeyDataGridDataCellObjectNeededEventHandler] as DataGridDataCellObjectNeededEventHandler;
      //if (eh != null)
      //{
      //  eh(this, e);
      //}
    }

    //private void DataPropertyNameChanged()
    //{
    //  if (Grid != null)
    //    Grid.UpdateRowsList();
    //}

    protected internal virtual int CalcHeight()
    {
      int height = 0;
      int maxHeight = CalcDefaultRowHeight(); 

      if (Grid.VisibleColumns.Count > 0)
      {
        foreach (object listItem in Grid.VisibleColumns)
        {
          height = CalcRowHeightForListItem(listItem);
          if (height > maxHeight)
            maxHeight = height;
        }
      }

      height = Title.CalcHeight();
      if (height > maxHeight)
        maxHeight = height;

      return maxHeight;
    }

    protected internal virtual int CalcDefaultRowHeight()
    {
      return 0;
    }

    protected internal virtual int CalcRowHeightForListItem(object listItem)
    {
      DataAxisGridDataCellMan listItemDataCell = GetColumnCellMan(listItem) as DataAxisGridDataCellMan;

      if (listItemDataCell != null)
        return listItemDataCell.ProcessCalcCellHeight(this, listItem, Grid.DataColumnWidth);
      else
        return CalcDefaultRowHeight();
    }

    protected internal override void OnPullValue(DataAxisGridDataCellPullValueEventArgs e)
    {
      e.Value = GetColumnValue(e.ListItemBar);
      e.Handled = true;
    }

    protected internal override void OnPushValue(DataAxisGridDataCellPushValueEventArgs e)
    {
      object listItem = e.ListItemBar;

      if (PropDescr == null)
        throw new InvalidOperationException("PropDescr == null");

      if (Grid.CurrencyManager.Current == listItem)
        Grid.DataLink.SetCurrentRowValue(PropDescr, e.Value);
      else
        PropDescr.SetValue(listItem, e.Value);
    }

    public virtual object GetColumnValue(object listItem)
    {
      if (DataValueSource == DataValueSource.ListItem)
      {
        return listItem;
      }
      else if (PropDescr == null || listItem == null)
      {
        return null;
      }
      else
      {
        object srcRow = listItem;
        return PropDescr.GetValue(srcRow);
      }
    }

    public virtual string GetColumnDisplayText(object listItem)
    {
      //object srcRow = row.srcRow;
      if (listItem == null) return null;

      object value = GetColumnValue(listItem);
      return GetValueDisplayText(value);
    }

    public virtual string GetValueDisplayText(object value)
    {
      TypeConverter srcConverter = null;
      TypeConverter targetConverter = TypeDescriptor.GetConverter(typeof(string));
      if (DataType != null)
        srcConverter = TypeDescriptor.GetConverter(DataType);
      object result = EhLibManager.DefaultEhLibManager.ValueConverter.FormatValue(
        value, typeof(string), srcConverter, targetConverter, "", null, "", null);
      return result.ToString();
    }

    //public virtual object ParseValue(object listItem, object formattedValue)
    //{
    //  if (string.IsNullOrEmpty(formattedValue as string))
    //    return GetEmptyValue(listItem);
    //  else if (PropDescr.PropertyType == formattedValue.GetType())
    //    return formattedValue;
    //  else
    //  {
    //    object parsedValue;
    //    TypeConverter tc = PropDescr.Converter;
    //    TypeConverter sc = TypeDescriptor.GetConverter(formattedValue);

    //    Debug.Assert(tc != null, @"tc != null");
    //    //Debug.Assert(sc != null, @"sc != null");

    //    if (tc.CanConvertFrom(formattedValue.GetType()))
    //    {
    //      parsedValue = tc.ConvertFrom(formattedValue);
    //    }
    //    else if (sc.CanConvertTo(PropDescr.PropertyType))
    //    {
    //      parsedValue = sc.ConvertTo(formattedValue, PropDescr.PropertyType);
    //    }
    //    else
    //    {
    //      parsedValue = formattedValue;
    //    }

    //    return parsedValue;
    //  }
    //}

    //public virtual object GetEmptyValue(object listItem)
    //{
    //  //object result;
    //  if (listItem != null)
    //  {
    //    object v = listItem;
    //    if (v is DataRowView)
    //      return DBNull.Value;
    //    else
    //      return null;
    //  }
    //  else
    //    return null;
    //}

    public override void Invalidate()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }

    public virtual string GetDisplayText(object listItem)
    {
      DataAxisGridDataCellMan cell = InternalGetColumnCell(listItem);
      //DataVertGridRowDataCell dataCell = (cell as DataVertGridRowDataCell);
      if (cell != null)
        return cell.GetDisplayText(this, listItem);
      else
        //TODO VisibleIndex?
        return null;// cell.GetDisplayText(VisibleIndex, row.VisibleIndex);
    }

    public virtual ContextMenuStrip GetContextMenuStripAtRow(DataGridRow row)
    {
      return null;
    }

    public virtual bool CanModifyValueAtRow(DataGridRow row)
    {
      return false;
    }

    //TODO Postpone.
    //protected override void OnCellContentClick(DataGridDataCellEventArgs e)
    //{
    //  //DataGridDataCellEventHandler eh = this.Events[EventKeyDataGridDataCellContentClick] as DataGridDataCellEventHandler;
    //  //if (eh != null)
    //  //{
    //  //  eh(this, e);
    //  //}
    //}

    protected internal override void UpdatedInList()
    {
      base.UpdatedInList();
    }

    protected internal override void CellFontChanged()
    {
      Grid.UpdateRowHeights();
    }

    public override Font DefaultFont()
    {
      if (Grid != null)
        return Grid.RowOptions.Font;
      else
        return null;
    }

    public override Color DefaultForeColor()
    {
      if (Grid != null)
        return Grid.RowOptions.ForeColor;
      else
        return Color.Empty;
    }

    protected internal override void RowHeightAutoExpandChanged()
    {
      if (Grid != null)
        Grid.RowHeightAutoExpandChanged();
    }

    public override bool HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.AutoExpand;
      else
        return false;
    }

    public override int HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.ContentHeight;
      else
        return 1;
    }

    public override int HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.MaxContentHeight;
      else
        return 0;
    }

    public override GridRowHeightUnit HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.Unit;
      else
        return GridRowHeightUnit.TextLine;
    }


    protected internal override void GridCellPosToDataCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex - Grid.FixedColCount;
      areaRowIndex = gridRowIndex - Grid.FixedRowCount;
    }

    protected internal override void DataCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex + Grid.FixedColCount;
      gridRowIndex = areaRowIndex + Grid.FixedRowCount;
    }

    protected internal override void AxisObjectsByDataColRowIndex(int dataColIndex, int dataRowIndex, out PropertyAxisBar propAxisBar, out object listItemBar)
    {
      if (dataRowIndex < Grid.VisibleRows.Count)
        propAxisBar = Grid.VisibleRows[dataRowIndex];
      else
        propAxisBar = null;

      if (dataColIndex < Grid.VisibleColumns.Count)
        listItemBar = Grid.VisibleColumns[dataColIndex];
      else
        listItemBar = null;
    }

    //protected internal override object GetValue(PropertyAxisBar propAxisBar, object listItemBar)
    //{
    //  return ((DataVertGridRow)propAxisBar).GetColumnValue(listItemBar);
    //}

    protected internal override void OnGetDataCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      if (e.BorderType == GridCellBorderType.Right || e.BorderType == GridCellBorderType.Left)
      {
        GridLine gl = Grid.RowOptions.HorzLine;
        e.Visible = gl.Visible;
        e.Color = gl.Color;
        e.Style = gl.Style;
        e.IsExtent = true;
      }
      else
      {
        e.Visible = Grid.LineOptions.VertLines;
        e.Color = Grid.LineOptions.BrightColor;
        e.Style = DashStyle.Solid;
        e.IsExtent = true;
      }
    }

    #endregion

    #region events
    #endregion

  }

  public class DataVertGridMonoCellRow : DataVertGridRow
  {

    #region privates
    private DataAxisGridDataCellMan dataCell;
    #endregion

    public DataVertGridMonoCellRow()
    {
    }

    #region internal properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    protected EditButton EditButton
    {
      get
      {
        return DataCell.EditButton;
      }

      set
      {
        DataCell.EditButton = value;
      }
    }
    #endregion

    #region runtime properties
    [Browsable(false)]
    public DataAxisGridDataCellMan DataCell
    {
      get
      {
        if (dataCell == null)
        {
          dataCell = CreateTemplateCell();
          dataCell.PropAxisBar = this;
        }
        return dataCell;
      }
    }

    [Browsable(false)]
    public override DataAxisGridDataCellMan NewVirtualRowCell
    {
      get
      {
        return DataCell;
      }
    }

    public Padding Padding
    {
      get { return DataCell.Padding; }
      set { DataCell.Padding = value; }
    }

    public HorizontalAlignment HorzAlign
    {
      get { return DataCell.HorzAlign; }
      set { DataCell.HorzAlign = value; }
    }

    public VerticalAlignment VertAlign
    {
      get { return DataCell.VertAlign; }
      set { DataCell.VertAlign = value; }
    }

    [DefaultValue(null)]
    public virtual ContextMenuStrip ContextMenuStrip
    {
      get { return DataCell.ContextMenuStrip; }
      set { DataCell.ContextMenuStrip = value; }
    }

    public Color ForeColor
    {
      get { return DataCell.ForeColor; }
      set { DataCell.ForeColor = value; }
    }

    public Font Font
    {
      get { return DataCell.Font; }
      set { DataCell.Font = value; }
    }

    [DefaultValue(false)]
    public virtual bool ReadOnly
    {
      get { return DataCell.ReadOnly; }
      set { DataCell.ReadOnly = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridRowHeightOptions HeightOptions
    {
      get
      {
        return DataCell.HeightOptions;
      }
    }

    //public bool HeightAutoExpand
    //{
    //  get { return DataCell.HeightAutoExpand; }
    //  set { DataCell.HeightAutoExpand = value; }
    //}
    #endregion

    #region methods

    //Padding
    protected virtual void PaddingChanged()
    {
      if (Grid != null)
        Grid.UpdateBaseFixedBands();
    }

    protected virtual Padding DefaultPadding()
    {
      return DataCell.DefaultPadding();
    }

    protected virtual bool ShouldSerializePadding()
    {
      return DataCell.ShouldSerializePadding();
    }

    public virtual void ResetPadding()
    {
      DataCell.ResetPadding();
    }

    //HorzAlign
    protected virtual HorizontalAlignment DefaultHorzAlign()
    {
      return DataCell.DefaultHorzAlign();
    }

    protected virtual void HorzAlignChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    protected virtual bool ShouldSerializeHorzAlign()
    {
      return DataCell.ShouldSerializeHorzAlign();
    }

    public virtual void ResetHorzAlign()
    {
      DataCell.ResetHorzAlign();
    }

    //VertAlign
    protected internal virtual void VertAlignChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public virtual VerticalAlignment DefaultVertAlign()
    {
      return DataCell.DefaultVertAlign();
    }

    public virtual bool ShouldSerializeVertAlign()
    {
      return DataCell.ShouldSerializeVertAlign();
    }

    public virtual void ResetVertAlign()
    {
      DataCell.ResetVertAlign();
    }

    //ForeColor
    protected virtual void ForeColorChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public override Color DefaultForeColor()
    {
      if (Grid != null)
        return Grid.RowOptions.ForeColor;
      else
        return SystemColors.WindowText;
    }

    protected virtual bool ShouldSerializeForeColor()
    {
      return DataCell.ShouldSerializeForeColor();
    }

    public virtual void ResetForeColor()
    {
      DataCell.ResetForeColor();
    }

    //Font
    protected virtual void FontChanged()
    {
      if (Grid != null)
        Grid.UpdateRowHeights();
    }

    public override Font DefaultFont()
    {
      if (Grid != null)
        return Grid.RowOptions.Font;
      else
        return null;
    }

    protected virtual bool ShouldSerializeFont()
    {
      return DataCell.ShouldSerializeFont();
    }

    public virtual void ResetFont()
    {
      DataCell.ResetFont();
    }

    //Other
    protected override void GridChanged()
    {
      base.GridChanged();
      DataCell.Grid = Grid;
    }

    protected virtual DataAxisGridDataCellMan CreateTemplateCell()
    {
      return null;
    }

    protected override void OnGetColumnCell(DataVertGridDataCellObjectNeededEventArgs e)
    {
      base.OnGetColumnCell(e);
      if (e.CellObject == null)
        e.CellObject = DataCell;
    }

    //public override void UpdateDefaultPadding()
    //{
    //  DataCell.UpdateDefaultPadding();
    //}

    protected internal override int CalcDefaultRowHeight()
    {
      int th;

      if (HeightOptions.Unit == GridRowHeightUnit.TextLine)
        th = EhLibUtils.GetFontHeight(Font) * HeightOptions.ContentHeight;
      else
        th = HeightOptions.ContentHeight;
      th = th + Padding.Top + Padding.Bottom;
      return th;
    }

    public override ContextMenuStrip GetContextMenuStripAtRow(DataGridRow row)
    {
      return DataCell.ContextMenuStrip;
    }

    public override bool CanModifyValueAtRow(DataGridRow row)
    {
      return !DataCell.ReadOnly;
    }

    #endregion
  }

}
