private static void PrintListRows(DataTable dataTable, IEnumerable <DataRow> dataRows, bool rowOrdinals, int top, ValueToStringHandler toString, int repeatColumns, RepeatDirection repeatDirection, string delimiter, string[] columnNames, string ordinalColumnName = null)
        {
            if (dataTable != null && string.IsNullOrEmpty(dataTable.TableName) == false)
            {
                WriteLine("{0}:", dataTable.TableName);
            }

            if (dataRows.Count() == 0)
            {
                WriteLine("No rows were selected");
                WriteLine();
                return;
            }

            DataColumn[] columns = GetColumns(dataTable, columnNames, ordinalColumnName);
            if (columns.Length == 0)
            {
                WriteLine("No columns were selected");
                WriteLine();
                return;
            }

            if (top > 0)
            {
                dataRows = dataRows.Take(top);
            }

            int columnsLength = columns.Select(c => c.ColumnName.Length).Max();

            int[] lengths = new int[columns.Length];
            foreach (DataRow row in dataRows)
            {
                CalculateLengths(row, columns, lengths, toString);
            }
            int rowsLength = lengths.Max();

            if (rowOrdinals)
            {
                if (dataRows.Count() > 0)
                {
                    if (columnsLength < 7) // "Ordinal".Length
                    {
                        columnsLength = 7;
                    }

                    int maxRowOrdinal = 0;
                    if (string.IsNullOrEmpty(ordinalColumnName))
                    {
                        maxRowOrdinal = dataRows.Select(row => row.Table.Rows.IndexOf(row)).Max();
                    }
                    else
                    {
                        maxRowOrdinal = dataRows.Select(row => (int)row[ordinalColumnName]).Max();
                    }

                    if (maxRowOrdinal > -1)
                    {
                        int rowOrdinalsLength = maxRowOrdinal.ToString().Length;
                        if (rowsLength < rowOrdinalsLength)
                        {
                            rowsLength = rowOrdinalsLength;
                        }
                    }
                }
            }

            if (repeatColumns < 1)
            {
                repeatColumns = 1;
            }

            if (repeatColumns > dataRows.Count())
            {
                repeatColumns = dataRows.Count();
            }

            int lastRowFilledCellsCount = dataRows.Count() % repeatColumns;

            if (lastRowFilledCellsCount == 0)
            {
                lastRowFilledCellsCount = repeatColumns;
            }
            int lastRowEmptyCellsCount = repeatColumns - lastRowFilledCellsCount;
            int rowsCount = (dataRows.Count() / repeatColumns) + (dataRows.Count() % repeatColumns > 0 ? 1 : 0);

            if (delimiter == null)
            {
                delimiter = string.Empty;
            }

            string cellFormat = string.Format(" {{{{0,-{0}}}}}{1}{{{{{{0}},-{2}}}}} {3}", columnsLength, delimiter, rowsLength, Verticl_Bar);
            string horizontal = new String(Horizontal_Bar, columnsLength + delimiter.Length + rowsLength + 2);

            string header    = Top_Left.ToString();
            string separator = Middle_Left.ToString();
            string footer    = Bottom_Left.ToString();
            string format    = Verticl_Bar.ToString();

            int k = 0;

            for (; k < repeatColumns - 1; k++)
            {
                header    += horizontal + Top_Center;
                separator += horizontal + Middle_Center;
                footer    += horizontal + Bottom_Center;
                format    += string.Format(cellFormat, k + 1);
            }

            k = repeatColumns - 1;
            if (k >= 0)
            {
                header    += horizontal + Top_Right;
                separator += horizontal + Middle_Right;
                footer    += horizontal + Bottom_Right;
                format    += string.Format(cellFormat, k + 1);
            }

            string formatPartial = format;

            if (lastRowEmptyCellsCount > 0)
            {
                formatPartial = Verticl_Bar.ToString();
                for (int i = 0; i < lastRowFilledCellsCount; i++)
                {
                    formatPartial += string.Format(cellFormat, i + 1);
                }
                for (int i = 0; i < lastRowEmptyCellsCount; i++)
                {
                    formatPartial += new String(' ', columnsLength + delimiter.Length + rowsLength + 2) + Verticl_Bar;
                }
            }

            object[] objects = new object[repeatColumns + 1];

            if (repeatDirection == RepeatDirection.Horizontal)
            {
                for (int i = 0; i < rowsCount; i++)
                {
                    WriteLine(i == 0 ? header : separator);
                    var rows = dataRows.Skip(i * repeatColumns).Take(repeatColumns);
                    PrintListRow(rows, columns, objects, (i < rowsCount - 1 ? format : formatPartial), rowOrdinals, toString, ordinalColumnName);
                }
            }
            else if (repeatDirection == RepeatDirection.Vertical && lastRowEmptyCellsCount == 0)
            {
                for (int i = 0; i < rowsCount; i++)
                {
                    WriteLine(i == 0 ? header : separator);
                    var rows = dataRows.Where((r, n) => n % rowsCount == i);
                    PrintListRow(rows, columns, objects, (i < rowsCount - 1 ? format : formatPartial), rowOrdinals, toString, ordinalColumnName);
                }
            }
            else if (repeatDirection == RepeatDirection.Vertical && lastRowEmptyCellsCount > 0)
            {
                for (int i = 0; i < rowsCount; i++)
                {
                    WriteLine(i == 0 ? header : separator);
                    var rows = dataRows.Where((r, n) =>
                                              (n < lastRowFilledCellsCount * rowsCount && n % rowsCount == i) ||
                                              (n >= lastRowFilledCellsCount * rowsCount && (n - (lastRowFilledCellsCount * rowsCount)) % (rowsCount - 1) == i)
                                              );
                    PrintListRow(rows, columns, objects, (i < rowsCount - 1 ? format : formatPartial), rowOrdinals, toString, ordinalColumnName);
                }
            }

            WriteLine(footer);

            WriteLine();
        }
        private static void PrintRows(DataTable dataTable, IEnumerable <DataRow> dataRows, bool rowOrdinals, int top, ValueToStringHandler toString, string[] columnNames, string ordinalColumnName = null)
        {
            if (dataTable == null && dataRows.Count() == 0)
            {
                WriteLine("No rows were selected");
                WriteLine();
                return;
            }

            if (dataTable != null && string.IsNullOrEmpty(dataTable.TableName) == false)
            {
                WriteLine("{0}:", dataTable.TableName);
            }

            DataColumn[] columns = GetColumns(dataTable, columnNames, ordinalColumnName);
            if (columns.Length == 0)
            {
                WriteLine("No columns were selected");
                WriteLine();
                return;
            }

            if (top > 0)
            {
                dataRows = dataRows.Take(top);
            }

            int[] lengths = columns.Select(c => c.ColumnName.Length).ToArray();
            foreach (DataRow row in dataRows)
            {
                CalculateLengths(row, columns, lengths, toString);
            }

            int rowOrdinalsLength = 0;

            if (rowOrdinals)
            {
                if (dataRows.Count() > 0)
                {
                    int maxRowOrdinal = 0;
                    if (string.IsNullOrEmpty(ordinalColumnName))
                    {
                        maxRowOrdinal = dataRows.Select(row => row.Table.Rows.IndexOf(row)).Max();
                    }
                    else
                    {
                        maxRowOrdinal = dataRows.Select(row => (int)row[ordinalColumnName]).Max();
                    }

                    if (maxRowOrdinal > -1)
                    {
                        rowOrdinalsLength = maxRowOrdinal.ToString().Length;
                    }
                }
            }

            string header        = Top_Left.ToString();
            string separator     = Middle_Left.ToString();
            string footer        = Bottom_Left.ToString();
            string formatHeaders = Verticl_Bar.ToString();
            string format        = Verticl_Bar.ToString();

            if (rowOrdinals)
            {
                string horizontal = new String(Horizontal_Bar, rowOrdinalsLength + 2);
                header        += horizontal + Top_Center;
                separator     += horizontal + Middle_Center;
                footer        += horizontal + Bottom_Center;
                formatHeaders += string.Format(" {{0,-{0}}} {1}", rowOrdinalsLength, Verticl_Bar);
                format        += string.Format(" {{0,{0}}} {1}", rowOrdinalsLength, Verticl_Bar);
            }

            int k = 0;

            for (; k < columns.Length - 1; k++)
            {
                string horizontal = new String(Horizontal_Bar, lengths[k] + 2);
                header    += horizontal + Top_Center;
                separator += horizontal + Middle_Center;
                footer    += horizontal + Bottom_Center;

                string cellFormat = string.Format(" {{{0},-{1}}} {2}", k + 1, lengths[k], Verticl_Bar);
                formatHeaders += cellFormat;
                format        += cellFormat;
            }

            k = columns.Length - 1;
            if (k >= 0)
            {
                string horizontal = new String(Horizontal_Bar, lengths[k] + 2);
                header    += horizontal + Top_Right;
                separator += horizontal + Middle_Right;
                footer    += horizontal + Bottom_Right;

                string cellFormat = string.Format(" {{{0},-{1}}} {2}", k + 1, lengths[k], Verticl_Bar);
                formatHeaders += cellFormat;
                format        += cellFormat;
            }

            object[] objects = new object[columns.Length + 1];

            WriteLine(header);

            objects[0] = string.Empty;
            for (int i = 0; i < columns.Length; i++)
            {
                objects[i + 1] = columns[i];
            }
            WriteLine(formatHeaders, objects);

            WriteLine(separator);

            foreach (DataRow row in dataRows)
            {
                if (rowOrdinals)
                {
                    int ordinal = 0;
                    if (string.IsNullOrEmpty(ordinalColumnName))
                    {
                        ordinal = row.Table.Rows.IndexOf(row);
                    }
                    else
                    {
                        ordinal = (int)row[ordinalColumnName];
                    }
                    objects[0] = (ordinal > -1 ? ordinal : (int?)null);
                }

                for (int i = 0; i < columns.Length; i++)
                {
                    object obj = row[columns[i]];

                    string str = null;
                    if (toString != null)
                    {
                        str = toString(obj, row, columns[i]);
                        if (str == null)
                        {
                            str = "null";
                        }
                    }
                    else
                    {
                        str = string.Format("{0}", (obj == DBNull.Value || obj == null ? "null" : obj));
                    }

                    objects[i + 1] = str;
                }

                WriteLine(format, objects);
            }

            WriteLine(footer);

            WriteLine();
        }