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

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

namespace EhLib
{
  public class DataGridImporter
  {
    #region Privates
    private readonly List<DataGridColumn> columnsList;
    private int colCount;
    //protected int maxRowCount;
    #endregion Privates

    public DataGridImporter()
    {
      columnsList = new List<DataGridColumn>();
    }

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


    #region Methods
    protected void DoImport()
    {
      Debug.Assert(Grid != null, "DataGridImporter.DoImport() Grid must be assigned");

      colCount = FetchColCount();
      columnsList.Clear();

      if ((Grid.Selection.SelectionType == GridSelectionType.All) ||
          (Grid.Selection.SelectionType == GridSelectionType.Rows))
      {
        for (int i = 0; i < Grid.VisibleColumns.Count && i < colCount; i++)
          columnsList.Add(Grid.VisibleColumns[i]);
      }
      else
      {
        switch (Grid.Selection.SelectionType)
        {
          case GridSelectionType.None:
            for (int i = Grid.CurrentColumnIndex; i < Grid.VisibleColumns.Count; i++)
            {
              if ((i - Grid.CurrentColumnIndex) >= colCount)
                break;
              columnsList.Add(Grid.VisibleColumns[i]);
            }
            break;
          case GridSelectionType.Columns:
            {
              int i = 0;
              foreach (DataGridColumn col in Grid.VisibleColumns)
                if ((col.Selected) && (i < colCount))
                {
                  columnsList.Add(col);
                  i++;
                }
              break;
            }
          case GridSelectionType.CellsBox:
            GridRect selBox = Grid.Selection.SelectedBox;
            int cc = 0;
            for (int i = selBox.Left; i <= selBox.Right; i++)
              if (cc < colCount)
              {
                columnsList.Add(Grid.VisibleColumns[i]);
                cc++;
              }
            break;
        }
      }

      BeforeImport();
      ImportPrefixData();
      ImportDataRows();
      ImportSuffixData();
      AfterImport();
    }

    protected virtual int FetchColCount()
    {
      return 0;
    }

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

        while (rowIndex < Grid.VisibleRows.Count)
        {
          row = Grid.VisibleRows[rowIndex];
          ImportDataRow(row);
          if (EndOfFile()) return;
          rowIndex++;
        }
      }
    }

    protected virtual bool EndOfFile()
    {
      return false; 
    }

    protected virtual void ImportDataRow(DataGridRow row)
    {
      Grid.DataLink.Position = row.Index;
      Grid.BeginCurrentEdit();
      for (int i = 0; i < columnsList.Count; i++)
      {
        ImportDataCell(i, columnsList[i], row);
        if (EndOfRow()) break;
      }
      SkipRestOfRow();
      Grid.EndCurrentEdit();
    }

    protected virtual bool EndOfRow()
    {
      return false;
    }

    protected virtual void SkipRestOfRow()
    {
    }

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

    protected virtual void ImportPrefixData()
    {
    }

    protected virtual void ImportSuffixData()
    {
    }

    protected virtual void AfterImport()
    {
    }

    protected virtual void BeforeImport()
    {
    }

    #endregion Methods

  }

  public class DataGridTextImporter : DataGridImporter, IDisposable
  {
    #region Privates
    private string cellDelimiter;
    private string lineBreak;
    private string quoteChar;

    //private bool endOfValue;
    private bool endOfRow;
    private bool endOfFile;
    private bool disposed;

    string sData;
    StringReader sReader;
    #endregion Privates

    #region constructor
    public DataGridTextImporter()
    {
      cellDelimiter = ((char)Keys.Tab).ToString();
      lineBreak = "" + (char)Keys.Return + (char)Keys.LineFeed;
      quoteChar = "";
    }

    ~DataGridTextImporter()
    {
      Dispose(false);
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposed)
        return;
      if (disposing)
      {
        if (sReader != null)
          sReader.Dispose();
      }
      disposed = true;
    }
    #endregion constructor

    #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; }
    }
    #endregion Properties

    #region Methods
    public void DoImport(string s)
    {
      this.sData = s;
      base.DoImport();
    }

    protected override void BeforeImport()
    {
      sReader = new StringReader(sData);
    }

    protected override void AfterImport()
    {
      sReader.Dispose();
      sReader = null;
    }

    protected override void ImportDataRow(DataGridRow row)
    {
      if (PeekEndOfFile())
      {
        endOfFile = true;
        return;
      }
      endOfRow = false;
      base.ImportDataRow(row);
    }

    protected override void ImportDataCell(int colIndex, DataGridColumn col, DataGridRow row)
    {
      //endOfValue = false;
      Exception exception;
      string s = ReadTextValue(sReader);
      if (col.CanModifyValueAtRow(row))
        Grid.PushValue(col, s, out exception);
    }

    protected string ReadTextValue(StringReader sReader)
    {
      StringBuilder sb = new StringBuilder();
      //StringBuilder lbb = new StringBuilder();
      char charValue;
      int intChar;

      while (true)
      {
        intChar = sReader.Read();
        if (intChar == -1)
        {
          endOfFile = true;
          break;
        }
        charValue = (char)intChar;
        if (charValue.ToString() == CellDelimiter)
        {
          //endOfValue = true;
          break;
        }
        else if (charValue.ToString() == LineBreak)
        {
          endOfRow = true;
          break;
        }
        else if ((LineBreak.Length > 0) && charValue == LineBreak[0])
        {
          int intChar2 = sReader.Peek();
          char charValue2;
          if (intChar != -1)
          {
            charValue2 = (char)intChar2;
            if ((LineBreak.Length > 1) && (charValue2 == LineBreak[1]))
            {
              endOfRow = true;
              sReader.Read();
              break;
            }
          }
        }
        sb.Append(charValue);
      }

      return sb.ToString();
    }

    protected bool PeekEndOfFile()
    {
      if (sReader.Peek() == -1)
        return true;
      else
        return false;
    }

    protected override bool EndOfRow()
    {
      return endOfRow;
    }

    protected override bool EndOfFile()
    {
      return endOfFile;
    }

    protected override int FetchColCount()
    {
      StringReader sccReader = new StringReader(sData);
      string s;
      int cCount = 0;

      while(true)
      {
        s = ReadTextValue(sccReader);
        if (EndOfRow())
        {
          cCount++;
          break;
        }
        else if (EndOfFile())
        {
          if ((cCount != 0) || (!String.IsNullOrEmpty(s)))
            cCount++;
          break;
        }
        cCount++;
      }
      return cCount;
    }

    #endregion Methods

  }

}
