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

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace EhLib
{

  public enum DataGridExportArea
  {
    WholeGrid, SelectedArea
  }

  public class DataGridExporter : object
  {
    #region Privates
    private readonly List<DataGridColumn> columnsList;
    protected ReadOnlyCollection<DataGridColumn> ColumnsList;
    //protected List<DataGridRow>  rowsList;
    #endregion Privates

    public DataGridExporter()
    {
      columnsList = new List<DataGridColumn>();
      ColumnsList = new ReadOnlyCollection<DataGridColumn>(columnsList);
      //rowsList = new List<DataGridRow>();
    }

    #region Properties
    public DataGridEh Grid { get; set; }

    public DataGridExportArea ImportArea { get; set; }

    public bool IsExportTitle { get; set; }
    #endregion Properties


    #region Methods
    //public Object CreateImportObject()
    public object BuildExportObject()
    {
      Debug.Assert(Grid != null, "DataGridExporter.BuildImportObject() Grid must be assigned");

      columnsList.Clear();
      //rowsList.Clear();

      if (ImportArea == DataGridExportArea.WholeGrid ||
          Grid.Selection.SelectionType == GridSelectionType.All)
      {
        foreach(DataGridColumn col in Grid.VisibleColumns)
          columnsList.Add(col);
        //rowsList.AddRange(Grid.Rows);
      }
      else
      {
        switch (Grid.Selection.SelectionType)
        {
          case GridSelectionType.None:
            columnsList.Add(Grid.VisibleColumns[Grid.CurrentColumnIndex]);
            break;
          case GridSelectionType.Rows:
            foreach (DataGridColumn col in Grid.VisibleColumns)
              columnsList.Add(col);
            break;
          case GridSelectionType.Columns:
            foreach (DataGridColumn col in Grid.VisibleColumns)
              if (col.Selected)
                columnsList.Add(col);
            break;
          case GridSelectionType.CellsBox:
            GridRect selBox = Grid.Selection.SelectedBox;
            for (int i = selBox.Left; i <= selBox.Right; i++)
              columnsList.Add(Grid.VisibleColumns[i]);
            break;
        }
      }

      BeforeExport();
      ExportPrefixData();
      ExportTitle();
      ExportDataRows();
      ExportFooters();
      ExportSuffixData();
      AfterExport();

      return GetExportObject();

      //GetDisplayText(int dataRowIndex);
      //GetEditText(int dataRowIndex);
      //GetValue(int dataRowIndex);
      //SetValue(int dataRowIndex, object value);
    }

    protected virtual object GetExportObject()
    {
      return null;
    }

    protected virtual void ExportDataRows()
    {
      if (ImportArea == DataGridExportArea.WholeGrid ||
          Grid.Selection.SelectionType == GridSelectionType.All ||
          Grid.Selection.SelectionType == GridSelectionType.Columns
          )
      {
        foreach (DataGridRow row in Grid.VisibleRows)
          ExportDataRow(row);
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.CellsBox)
      {
        GridRect selBox = Grid.Selection.SelectedBox;
        for (int i = selBox.Top; i <= selBox.Bottom; i++)
          ExportDataRow(Grid.VisibleRows[i]);
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.Rows)
      {
        foreach (DataGridRow row in Grid.VisibleRows)
          if (row.Selected)
            ExportDataRow(row);
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.None)
      {
        ExportDataRow(Grid.VisibleRows[Grid.CurrentRowIndex]);
      }
    }

    protected virtual void ExportDataRow(DataGridRow row)
    {
      for (int i = 0; i < columnsList.Count; i++)
      {
        ExportDataCell(i, columnsList[i], row);
      }
    }

    protected virtual void ExportDataCell(int colIndex, DataGridColumn col, DataGridRow row)
    {
    }

    protected virtual void ExportFooters()
    {
      //for (int i = 0; i < Grid.Footer.Rows.Count; i++)
      //{
      //  foreach (DataGridColumn col in Grid.VisibleColumns)
      //  {
      //    //ExportFootersCell(col);
      //  }
      //}
    }

    protected virtual void ExportTitle()
    {
      if (!IsExportTitle) return;
      for (int i = 0; i < columnsList.Count; i++)
      {
        //ExportTitleCell(i, columnsList[i], columnsList[i].Title.TitleCell);
        ExportTitleCell(i, columnsList[i], Grid.titleCellMan);
      }
    }

    protected virtual void ExportTitleCell(int colIndex, DataGridColumn column, DataGridTitleCellMan titleCell)
    {
    }

    protected virtual void ExportPrefixData()
    {
    }

    protected virtual void ExportSuffixData()
    {
    }

    protected virtual void AfterExport()
    {
    }

    protected virtual void BeforeExport()
    {
    }

    protected virtual int GetColCount()
    {
      return columnsList.Count;
    }

    protected virtual int GetRowCount()
    {
      if (ImportArea == DataGridExportArea.WholeGrid ||
          Grid.Selection.SelectionType == GridSelectionType.All ||
          Grid.Selection.SelectionType == GridSelectionType.Columns
          )
      {
        return Grid.VisibleRows.Count;
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.CellsBox)
      {
        GridRect selBox = Grid.Selection.SelectedBox;
        return selBox.Bottom - selBox.Top;
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.Rows)
      {
        int result = 0;
        foreach (DataGridRow row in Grid.VisibleRows)
          if (row.Selected)
            result++;
        return result;
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.None)
      {
        return 1;
      }
      else
      {
        return 0;
      }
    }

    #endregion Methods

  }

  public class DataGridTextExporter : DataGridExporter
  {
    #region Privates
    private string cellDelimiter;
    private string lineBreak;
    private string quoteChar;

    readonly StringBuilder resStr = new StringBuilder(64);
    private bool modifyTextToFitFormat;
    #endregion Privates

    public DataGridTextExporter()
    {
      cellDelimiter = ((char)Keys.Tab).ToString();
      lineBreak = "" + (char)Keys.Return + (char)Keys.LineFeed;
      quoteChar = "";
    }

    #region Properties
    public string CellDelimiter
    {
      get { return cellDelimiter; }
      set { cellDelimiter = value; }
    }
    public string LineBreak
    {
      get { return lineBreak; }
      set { lineBreak = value; }
    }
    public string QuoteChar
    {
      get { return quoteChar; }
      set { quoteChar = value; }
    }
    public bool ModifyTextToFitFormat
    {
      get { return modifyTextToFitFormat; }
      set { modifyTextToFitFormat = value; }
    }
    #endregion Properties

    #region Methods
    public string BuildExportString()
    {
      return (string)(BuildExportObject());
    }

    protected override void BeforeExport()
    {
      resStr.Clear();
    }

    protected override void AfterExport()
    {
    }

    protected override object GetExportObject()
    {
      return resStr.ToString();
    }

    protected override void ExportTitleCell(int colIndex, DataGridColumn column, DataGridTitleCellMan titleCell)
    {
      string s = titleCell.GetDisplayText(column.Index, 0);

      if (ModifyTextToFitFormat)
      {
        s = s.Replace(CellDelimiter, " ");
        s = s.Replace(CellDelimiter, " ");
      }
      resStr.Append(s);
      if (colIndex < ColumnsList.Count-1)
        resStr.Append(CellDelimiter);
      else
        resStr.Append(LineBreak);
    }

    protected override void ExportDataCell(int colIndex, DataGridColumn col, DataGridRow row)
    {
      string s = col.GetRowDisplayText(row);

      if (ModifyTextToFitFormat)
      {
        s = s.Replace(CellDelimiter, " ");
        s = s.Replace(CellDelimiter, " ");
      }
      resStr.Append(s);
      if (colIndex < ColumnsList.Count - 1)
        resStr.Append(CellDelimiter);
      else
        resStr.Append(LineBreak);
    }

    #endregion Methods

  }

  public class DataGridLibTableDataExchangeExporter : DataGridExporter
  {
    #region Privates
    readonly StringBuilder resStr = new StringBuilder(64);
    #endregion Privates

    public DataGridLibTableDataExchangeExporter()
    {
    }

    #region Properties
    #endregion Properties

    #region Methods
    protected override void BeforeExport()
    {
      resStr.Clear();
    }

    protected override void ExportPrefixData()
    {
      //resStr.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
    }

    protected override void AfterExport()
    {
    }

    protected override object GetExportObject()
    {
      return resStr.ToString();
      //UTF8Encoding utf8 = new UTF8Encoding();
      //byte[] encodedBytes = utf8.GetBytes(resStr.ToString());
      ////return encodedBytes;
      //MemoryStream stringInMemoryStream = new MemoryStream(encodedBytes);
      //return encodedBytes;
    }

    protected override void ExportTitle()
    {
      resStr.Append("<TableTitle ColCount=\"");
      resStr.Append(GetColCount().ToString());
      resStr.Append("\" RowCount=\"");
      resStr.Append("1");
      resStr.AppendLine("\">");
      resStr.AppendLine("  <Row>");

      base.ExportTitle();

      resStr.AppendLine("  </Row>");
      resStr.AppendLine("</TableTitle>");
    }

    protected override void ExportTitleCell(int colIndex, DataGridColumn column, DataGridTitleCellMan titleCell)
    {
      string s = titleCell.GetDisplayText(column.Index, 0);

      resStr.Append("    <Cell><Data Type=\"String\">");
      resStr.Append(s);
      resStr.AppendLine("</Data></Cell>");
    }

    protected override void ExportDataRows()
    {
      resStr.Append("<Table ColCount=\"");
      resStr.Append(GetColCount().ToString());
      resStr.Append("\" RowCount=\"");
      resStr.Append(GetRowCount().ToString());
      resStr.AppendLine("\" >");

      base.ExportDataRows();

      resStr.AppendLine("</Table>");
    }

    protected override void ExportDataRow(DataGridRow row)
    {
      resStr.AppendLine("  <Row>");
      base.ExportDataRow(row);
      resStr.AppendLine("  </Row>");
    }

    protected override void ExportDataCell(int colIndex, DataGridColumn col, DataGridRow row)
    {
      string s = col.GetRowDisplayText(row);

      resStr.Append("    <Cell><Data Type=\"String\">");
      resStr.Append(s);
      resStr.AppendLine("</Data></Cell>");
    }

    #endregion Methods

  }

  public class DataGridAggregator : DataGridExporter
  {
    #region privates
    private decimal sumValue;
    private decimal countValue;
    private decimal averageValue;

    private readonly SumCalculator sumCalculator;
    private readonly CountCalculator countCalculator;
    #endregion privates

    public DataGridAggregator()
    {
      sumCalculator = new SumCalculator();
      countCalculator = new CountCalculator();
    }

    #region Properties
    public decimal SumValue { get { return sumValue; } }
    public decimal CountValue { get { return countValue; } }
    public decimal AverageValue { get { return averageValue; } }
    #endregion Properties

    #region Methods
    protected override void BeforeExport()
    {
      sumValue = 0;
      sumCalculator.InitCalcData(typeof(decimal));
      countValue = 0;
      countCalculator.InitCalcData(typeof(decimal));
      averageValue = 0;
    }

    protected override void AfterExport()
    {
      object sumResult = sumCalculator.FinalizeCalcData();
      if (sumResult != null) sumValue = (decimal)sumResult;
      object countResult = countCalculator.FinalizeCalcData();
      if (countResult != null) countValue = Convert.ToDecimal(countResult);
      if (countValue > 0)
        averageValue = Math.Round(sumValue / countValue, 4);
    }

    protected override void ExportDataCell(int colIndex, DataGridColumn col, DataGridRow row)
    {
      object v = col.GetRowValue(row);
      sumCalculator.StepCalcData(v);
      countCalculator.StepCalcData(v);
    }

    #endregion Methods

  }

}

