| /******************************************************************************* | 
 |  * You may amend and distribute as you like, but don't remove this header! | 
 |  * | 
 |  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
 |  * See http://www.codeplex.com/EPPlus for details. | 
 |  * | 
 |  * Copyright (C) 2011  Jan Källman | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   | 
 |  * See the GNU Lesser General Public License for more details. | 
 |  * | 
 |  * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
 |  * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
 |  * | 
 |  * All code and executables are provided "as is" with no warranty either express or implied.  | 
 |  * The author accepts no liability for any damage or loss of business that this product may cause. | 
 |  * | 
 |  * Code change notes: | 
 |  *  | 
 |  * Author							Change						Date | 
 |  * ****************************************************************************** | 
 |  * Jan Källman		    Added       		        2012-11-25 | 
 |  *******************************************************************************/ | 
 | using System; | 
 | using System.Collections.Generic; | 
 | using System.Linq; | 
 | using System.Text; | 
 | using System.Collections; | 
 | using OfficeOpenXml; | 
 | using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; | 
 |  | 
 | internal class IndexBase : IComparable<IndexBase> | 
 |     {         | 
 |         internal short Index; | 
 |         public int CompareTo(IndexBase other) | 
 |         { | 
 |             return Index < other.Index ? -1 : Index > other.Index ? 1 : 0; | 
 |         } | 
 |     } | 
 |     internal class IndexItem :  IndexBase | 
 |     { | 
 |         internal int IndexPointer  | 
 |         { | 
 |             get;  | 
 |             set; | 
 |         } | 
 |     }         | 
 |     internal class ColumnIndex : IndexBase, IDisposable | 
 |     { | 
 |         internal IndexBase _searchIx=new IndexBase(); | 
 |         public ColumnIndex () | 
 | 	    { | 
 |             _pages=new PageIndex[CellStore<int>.PagesPerColumnMin]; | 
 |             PageCount=0; | 
 | 	    } | 
 |         ~ColumnIndex() | 
 | 	    { | 
 |             _pages=null;             | 
 | 	    } | 
 |         internal int GetPosition(int Row) | 
 |         { | 
 |             var page = (short)(Row >> CellStore<int>.pageBits); | 
 |             _searchIx.Index = page; | 
 |             var res = (_pages[page].Index == page) ? page : Array.BinarySearch(_pages, 0, PageCount, _searchIx); | 
 |             if (res >= 0) | 
 |             { | 
 |                 GetPage(Row, ref res); | 
 |                 return res; | 
 |             } | 
 |             else | 
 |             { | 
 |                 var p = ~res; | 
 |                  | 
 |                 if (GetPage(Row, ref p)) | 
 |                 { | 
 |                     return p; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return res; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         private bool GetPage(int Row, ref int res) | 
 |         { | 
 |             if (res < PageCount && _pages[res].MinIndex <= Row && _pages[res].MaxIndex >= Row) | 
 |             { | 
 |                 return true; | 
 |             } | 
 |             else | 
 |             { | 
 |                 if (res + 1 < PageCount && (_pages[res + 1].MinIndex <= Row)) | 
 |                 { | 
 |                     do | 
 |                     { | 
 |                         res++; | 
 |                     } | 
 |                     while (res + 1 < PageCount && _pages[res + 1].MinIndex <= Row); | 
 |                     //if (res + 1 < PageCount && _pages[res + 1].MaxIndex >= Row) | 
 |                     //{ | 
 |                         return true; | 
 |                     //} | 
 |                     //else | 
 |                     //{ | 
 |                     //    return false; | 
 |                     //} | 
 |                 } | 
 |                 else if (res - 1 >= 0 && _pages[res - 1].MaxIndex >= Row) | 
 |                 { | 
 |                     do | 
 |                     { | 
 |                         res--; | 
 |                     } | 
 |                     while (res-1 > 0 && _pages[res-1].MaxIndex >= Row); | 
 |                     //if (res > 0) | 
 |                     //{ | 
 |                         return true; | 
 |                     //} | 
 |                     //else | 
 |                     //{ | 
 |                     //    return false; | 
 |                     //} | 
 |                 } | 
 |                 return false; | 
 |             } | 
 |         } | 
 |         internal int GetNextRow(int row) | 
 |         { | 
 |             //var page = (int)((ulong)row >> CellStore<int>.pageBits); | 
 |             var p = GetPosition(row); | 
 |             if (p < 0) | 
 |             { | 
 |                 p = ~p; | 
 |                 if (p >= PageCount) | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |  | 
 |                     if (_pages[p].IndexOffset + _pages[p].Rows[0].Index < row) | 
 |                     { | 
 |                         if (p + 1 >= PageCount) | 
 |                         { | 
 |                             return -1; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             return _pages[p + 1].IndexOffset + _pages[p].Rows[0].Index; | 
 |                         } | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         return _pages[p].IndexOffset + _pages[p].Rows[0].Index; | 
 |                     } | 
 |                 } | 
 |             } | 
 |             else | 
 |             { | 
 |                 if (p < PageCount) | 
 |                 { | 
 |                     var r = _pages[p].GetNextRow(row); | 
 |                     if (r >= 0) | 
 |                     { | 
 |                         return _pages[p].IndexOffset + _pages[p].Rows[r].Index; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         if (++p < PageCount) | 
 |                         { | 
 |                             return _pages[p].IndexOffset + _pages[p].Rows[0].Index; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             return -1; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal int FindNext(int Page) | 
 |         { | 
 |             var p = GetPosition(Page); | 
 |             if (p < 0) | 
 |             { | 
 |                 return ~p; | 
 |             } | 
 |             return p; | 
 |         } | 
 |         internal PageIndex[] _pages; | 
 |         internal int PageCount; | 
 |  | 
 |         public void Dispose() | 
 |         { | 
 |             for (int p = 0; p < PageCount; p++) | 
 |             { | 
 |                 ((IDisposable)_pages[p]).Dispose(); | 
 |             } | 
 |             _pages = null; | 
 |         } | 
 |  | 
 |     } | 
 |     internal class PageIndex : IndexBase, IDisposable | 
 |     { | 
 |         internal IndexBase _searchIx = new IndexBase(); | 
 |         public PageIndex() | 
 | 	    { | 
 |             Rows = new IndexItem[CellStore<int>.PageSizeMin]; | 
 |             RowCount = 0; | 
 | 	    } | 
 |         public PageIndex(IndexItem[] rows, int count) | 
 |         { | 
 |             Rows = rows; | 
 |             RowCount = count; | 
 |         } | 
 |         public PageIndex(PageIndex pageItem, int start, int size) | 
 |             :this(pageItem, start, size, pageItem.Index, pageItem.Offset) | 
 |         { | 
 |  | 
 |         } | 
 |         public PageIndex(PageIndex pageItem, int start, int size, short index, int offset) | 
 |         { | 
 |             Rows = new IndexItem[CellStore<int>.GetSize(size)]; | 
 |             Array.Copy(pageItem.Rows, start, Rows,0,size); | 
 |             RowCount = size; | 
 |             Index = index; | 
 |             Offset = offset; | 
 |         } | 
 |         ~PageIndex() | 
 | 	    { | 
 |             Rows=null; | 
 | 	    } | 
 |         internal int Offset = 0; | 
 |         internal int IndexOffset | 
 |         { | 
 |             get | 
 |             { | 
 |                 return IndexExpanded + (int)Offset; | 
 |             } | 
 |         } | 
 |         internal int IndexExpanded | 
 |         { | 
 |             get | 
 |             { | 
 |                 return (Index << CellStore<int>.pageBits); | 
 |             } | 
 |         } | 
 |         internal IndexItem[] Rows { get; set; } | 
 |         internal int RowCount; | 
 |  | 
 |         internal int GetPosition(int offset) | 
 |         { | 
 |             _searchIx.Index = (short)offset; | 
 |             return (Rows[offset-1].Index == offset) ? offset-1 : Array.BinarySearch(Rows, 0, RowCount, _searchIx); | 
 |         } | 
 |         internal int GetNextRow(int row) | 
 |         { | 
 |             int offset = row - IndexOffset; | 
 |             var o= GetPosition(offset); | 
 |             if (o < 0) | 
 |             { | 
 |                 o = ~o; | 
 |                 if (o < RowCount) | 
 |                 { | 
 |                     return o; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |             } | 
 |             return o; | 
 |         } | 
 |  | 
 |         public int MinIndex | 
 |         { | 
 |             get | 
 |             { | 
 |                 if (Rows.Length > 0) | 
 |                 { | 
 |                     return IndexOffset + Rows[0].Index; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |             } | 
 |         } | 
 |         public int MaxIndex | 
 |         { | 
 |             get | 
 |             { | 
 |                 if (RowCount > 0) | 
 |                 { | 
 |                     return IndexOffset + Rows[RowCount-1].Index; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |             } | 
 |         } | 
 |         public int GetIndex(int pos) | 
 |         { | 
 |             return IndexOffset + Rows[pos].Index; | 
 |         } | 
 |         public void Dispose() | 
 |         { | 
 |             Rows = null; | 
 |         } | 
 |     } | 
 |     /// <summary> | 
 |     /// This is the store for all Rows, Columns and Cells. | 
 |     /// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID ) | 
 |     /// </summary> | 
 |     internal class CellStore<T> : IDisposable// : IEnumerable<ulong>, IEnumerator<ulong> | 
 |     { | 
 |         /**** Size constants ****/ | 
 |         internal const int pageBits = 10;   //13bits=8192  Note: Maximum is 13 bits since short is used (PageMax=16K) | 
 |         internal const int PageSize = 1 << pageBits; | 
 |         internal const int PageSizeMin = 1<<10; | 
 |         internal const int PageSizeMax = PageSize << 1; //Double page size | 
 |         internal const int ColSizeMin = 32; | 
 |         internal const int PagesPerColumnMin = 32; | 
 |  | 
 |         List<T> _values = new List<T>(); | 
 |         internal ColumnIndex[] _columnIndex; | 
 |         internal IndexBase _searchIx = new IndexBase(); | 
 |         internal int ColumnCount; | 
 |         public CellStore () | 
 | 	    { | 
 |             _columnIndex = new ColumnIndex[ColSizeMin]; | 
 | 	    } | 
 |         ~CellStore() | 
 | 	    { | 
 |             if (_values != null) | 
 |             { | 
 |                 _values.Clear(); | 
 |                 _values = null; | 
 |             } | 
 |             _columnIndex=null; | 
 | 	    } | 
 |         internal int GetPosition(int Column) | 
 |         { | 
 |             _searchIx.Index = (short)Column; | 
 |             return (_columnIndex[Column-1].Index == Column) ? Column-1 : Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx); | 
 |         } | 
 |         internal CellStore<T> Clone() | 
 |         { | 
 |             int row,col; | 
 |             var ret=new CellStore<T>(); | 
 |             for (int c = 0; c < ColumnCount; c++) | 
 |             { | 
 |                 col = _columnIndex[c].Index; | 
 |                 for (int p = 0;p < _columnIndex[c].PageCount; p++) | 
 |                 { | 
 |                     for (int r = 0; r < _columnIndex[c]._pages[p].RowCount; r++) | 
 |                     { | 
 |                         row = _columnIndex[c]._pages[p].IndexOffset + _columnIndex[c]._pages[p].Rows[r].Index; | 
 |                         ret.SetValue(row, col, _values[_columnIndex[c]._pages[p].Rows[r].IndexPointer]); | 
 |                     } | 
 |                 } | 
 |             } | 
 |             return ret; | 
 |         } | 
 |         internal int Count | 
 |         { | 
 |             get | 
 |             { | 
 |                 int count=0; | 
 |                 for (int c = 0; c < ColumnCount; c++) | 
 |                 { | 
 |                     for (int p = 0; p < _columnIndex[c].PageCount; p++) | 
 |                     { | 
 |                         count += _columnIndex[c]._pages[p].RowCount; | 
 |                     } | 
 |                 } | 
 |                 return count; | 
 |             } | 
 |         } | 
 |         internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) | 
 |         { | 
 |             if (ColumnCount == 0) | 
 |             { | 
 |                 fromRow = fromCol = toRow = toCol = 0; | 
 |                 return false; | 
 |             } | 
 |             else | 
 |             { | 
 |                 fromCol=_columnIndex[0].Index; | 
 |                 var fromIndex = 0; | 
 |                 if (fromCol <= 0 && ColumnCount > 1) | 
 |                 { | 
 |                     fromCol = _columnIndex[1].Index; | 
 |                     fromIndex = 1; | 
 |                 } | 
 |                 else if(ColumnCount == 1 && fromCol <= 0) | 
 |                 { | 
 |                     fromRow = fromCol = toRow = toCol = 0; | 
 |                     return false; | 
 |                 } | 
 |                 var col = ColumnCount - 1; | 
 |                 while (col > 0) | 
 |                 { | 
 |                     if (_columnIndex[col].PageCount == 0 || _columnIndex[col]._pages[0].RowCount > 1 || _columnIndex[col]._pages[0].Rows[0].Index > 0) | 
 |                     { | 
 |                         break; | 
 |                     } | 
 |                     col--; | 
 |                 } | 
 |                 toCol=_columnIndex[col].Index; | 
 |                 if (toCol == 0) | 
 |                 { | 
 |                     fromRow = fromCol = toRow = toCol = 0; | 
 |                     return false;                     | 
 |                 } | 
 |                 fromRow = toRow= 0; | 
 |  | 
 |                 for (int c = fromIndex; c < ColumnCount; c++) | 
 |                 {                     | 
 |                     int first, last; | 
 |                     if (_columnIndex[c].PageCount == 0) continue;                     | 
 |                     if (_columnIndex[c]._pages[0].RowCount > 0 && _columnIndex[c]._pages[0].Rows[0].Index > 0) | 
 |                     { | 
 |                         first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[0].Index; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         if(_columnIndex[c]._pages[0].RowCount>1) | 
 |                         { | 
 |                             first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[1].Index; | 
 |                         } | 
 |                         else if (_columnIndex[c].PageCount > 1) | 
 |                         { | 
 |                             first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[1].Rows[0].Index; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             first = 0; | 
 |                         } | 
 |                     } | 
 |                     var lp = _columnIndex[c].PageCount - 1; | 
 |                     while(_columnIndex[c]._pages[lp].RowCount==0 && lp!=0) | 
 |                     { | 
 |                         lp--; | 
 |                     } | 
 |                     var p = _columnIndex[c]._pages[lp]; | 
 |                     if (p.RowCount > 0) | 
 |                     { | 
 |                         last = p.IndexOffset + p.Rows[p.RowCount - 1].Index; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         last = first; | 
 |                     } | 
 |                     if (first > 0 && (first < fromRow || fromRow == 0)) | 
 |                     { | 
 |                         fromRow=first; | 
 |                     } | 
 |                     if (first>0 && (last > toRow || toRow == 0)) | 
 |                     { | 
 |                         toRow=last; | 
 |                     } | 
 |                 } | 
 |                 if (fromRow <= 0 || toRow <= 0) | 
 |                 { | 
 |                     fromRow = fromCol = toRow = toCol = 0; | 
 |                     return false; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     return true; | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal int FindNext(int Column) | 
 |         { | 
 |             var c = GetPosition(Column); | 
 |             if (c < 0) | 
 |             { | 
 |                 return ~c; | 
 |             } | 
 |             return c; | 
 |         } | 
 |         internal T GetValue(int Row, int Column) | 
 |         { | 
 |             int i = GetPointer(Row, Column); | 
 |             if (i >= 0) | 
 |             { | 
 |                 return _values[i]; | 
 |             } | 
 |             else | 
 |             { | 
 |                 return default(T);                 | 
 |             } | 
 |             //var col = GetPosition(Column); | 
 |             //if (col >= 0)   | 
 |             //{ | 
 |             //    var pos = _columnIndex[col].GetPosition(Row); | 
 |             //    if (pos >= 0)  | 
 |             //    { | 
 |             //        var pageItem = _columnIndex[col].Pages[pos]; | 
 |             //        if (pageItem.MinIndex > Row) | 
 |             //        { | 
 |             //            pos--; | 
 |             //            if (pos < 0) | 
 |             //            { | 
 |             //                return default(T); | 
 |             //            } | 
 |             //            else | 
 |             //            { | 
 |             //                pageItem = _columnIndex[col].Pages[pos]; | 
 |             //            } | 
 |             //        } | 
 |             //        short ix = (short)(Row - pageItem.IndexOffset); | 
 |             //        var cellPos = Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, new IndexBase() { Index = ix }); | 
 |             //        if (cellPos >= 0)  | 
 |             //        { | 
 |             //            return _values[pageItem.Rows[cellPos].IndexPointer]; | 
 |             //        } | 
 |             //        else //Cell does not exist | 
 |             //        { | 
 |             //            return default(T); | 
 |             //        } | 
 |             //    } | 
 |             //    else //Page does not exist | 
 |             //    { | 
 |             //        return default(T); | 
 |             //    } | 
 |             //} | 
 |             //else //Column does not exist | 
 |             //{ | 
 |             //    return default(T); | 
 |             //} | 
 |         } | 
 |         int GetPointer(int Row, int Column) | 
 |         { | 
 |             var col = GetPosition(Column); | 
 |             if (col >= 0) | 
 |             { | 
 |                 var pos = _columnIndex[col].GetPosition(Row); | 
 |                 if (pos >= 0 && pos < _columnIndex[col].PageCount) | 
 |                 { | 
 |                     var pageItem = _columnIndex[col]._pages[pos]; | 
 |                     if (pageItem.MinIndex > Row) | 
 |                     { | 
 |                         pos--; | 
 |                         if (pos < 0) | 
 |                         { | 
 |                             return -1; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             pageItem = _columnIndex[col]._pages[pos]; | 
 |                         } | 
 |                     } | 
 |                     short ix = (short)(Row - pageItem.IndexOffset); | 
 |                     _searchIx.Index = ix; | 
 |                     var cellPos = (pageItem.Rows[ix-1].Index == ix) ? ix-1 : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); | 
 |                     if (cellPos >= 0) | 
 |                     { | 
 |                         return pageItem.Rows[cellPos].IndexPointer; | 
 |                     } | 
 |                     else //Cell does not exist | 
 |                     { | 
 |                         return -1; | 
 |                     } | 
 |                 } | 
 |                 else //Page does not exist | 
 |                 { | 
 |                     return -1; | 
 |                 } | 
 |             } | 
 |             else //Column does not exist | 
 |             { | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |         internal bool Exists(int Row,int Column) | 
 |         { | 
 |             return GetPointer(Row, Column)>=0; | 
 |         } | 
 |         internal bool Exists(int Row, int Column, ref T value) | 
 |         { | 
 |             var p=GetPointer(Row, Column); | 
 |             if (p >= 0) | 
 |             { | 
 |                 value = _values[p]; | 
 |                 return true; | 
 |             } | 
 |             else | 
 |             {                 | 
 |                 return false; | 
 |             } | 
 |         } | 
 |         internal void SetValue(int Row, int Column, T Value) | 
 |         { | 
 |             lock (_columnIndex) | 
 |             { | 
 |                 var col = (_columnIndex[Column-1].Index == Column) ? Column-1 : Array.BinarySearch(_columnIndex, 0, ColumnCount, new IndexBase() { Index = (short)(Column) }); | 
 |                 var page = (short)(Row >> pageBits); | 
 |                 if (col >= 0) | 
 |                 { | 
 |                     //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page }); | 
 |                     var pos = _columnIndex[col].GetPosition(Row); | 
 |                     if (pos < 0) | 
 |                     { | 
 |                         pos = ~pos; | 
 |                         if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + PageSize - 1 < Row) | 
 |                         { | 
 |                             AddPage(_columnIndex[col], pos, page); | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             pos--; | 
 |                         } | 
 |                     } | 
 |                     if (pos >= _columnIndex[col].PageCount) | 
 |                     { | 
 |                         AddPage(_columnIndex[col], pos, page); | 
 |                     } | 
 |                     var pageItem = _columnIndex[col]._pages[pos]; | 
 |                     if (pageItem.IndexOffset > Row) | 
 |                     { | 
 |                         pos--; | 
 |                         page--; | 
 |                         if (pos < 0) | 
 |                         { | 
 |                             throw (new Exception("Unexpected error when setting value")); | 
 |                         } | 
 |                         pageItem = _columnIndex[col]._pages[pos]; | 
 |                     } | 
 |  | 
 |                     short ix = (short)(Row - ((pageItem.Index << pageBits) + pageItem.Offset)); | 
 |                     _searchIx.Index = ix; | 
 |                     var cellPos = (pageItem.Rows[ix].Index == ix) ? ix : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); | 
 |                     if (cellPos < 0) | 
 |                     { | 
 |                         cellPos = ~cellPos; | 
 |                         AddCell(_columnIndex[col], pos, cellPos, ix, Value); | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         _values[pageItem.Rows[cellPos].IndexPointer] = Value; | 
 |                     } | 
 |                 } | 
 |                 else //Column does not exist | 
 |                 { | 
 |                     col = ~col; | 
 |                     AddColumn(col, Column); | 
 |                     AddPage(_columnIndex[col], 0, page); | 
 |                     short ix = (short)(Row - (page << pageBits)); | 
 |                     AddCell(_columnIndex[col], 0, 0, ix, Value); | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         internal void Insert(int fromRow, int fromCol, int rows, int columns) | 
 |         { | 
 |             lock (_columnIndex) | 
 |             { | 
 |  | 
 |                 if (columns > 0) | 
 |                 { | 
 |                     var col = GetPosition(fromCol); | 
 |                     if (col < 0) | 
 |                     { | 
 |                         col = ~col; | 
 |                     } | 
 |                     for (var c = col; c < ColumnCount; c++) | 
 |                     { | 
 |                         _columnIndex[c].Index += (short)columns; | 
 |                     } | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var page = fromRow >> pageBits; | 
 |                     for (int c = 0; c < ColumnCount; c++) | 
 |                     { | 
 |                         var column = _columnIndex[c]; | 
 |                         var pagePos = column.GetPosition(fromRow); | 
 |                         if (pagePos >= 0) | 
 |                         { | 
 |                             if (fromRow >= column._pages[pagePos].MinIndex && fromRow <= column._pages[pagePos].MaxIndex) //The row is inside the page | 
 |                             { | 
 |                                 int offset = fromRow - column._pages[pagePos].IndexOffset; | 
 |                                 var rowPos = column._pages[pagePos].GetPosition(offset); | 
 |                                 if (rowPos < 0) | 
 |                                 { | 
 |                                     rowPos = ~rowPos; | 
 |                                 } | 
 |                                 UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); | 
 |                             } | 
 |                             else if (column._pages[pagePos].MinIndex > fromRow - 1 && pagePos > 0) //The row is on the page before. | 
 |                             { | 
 |                                 int offset = fromRow - ((page - 1) << pageBits); | 
 |                                 var rowPos = column._pages[pagePos - 1].GetPosition(offset); | 
 |                                 if (rowPos > 0 && pagePos > 0) | 
 |                                 { | 
 |                                     UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows); | 
 |                                 } | 
 |                             } | 
 |                             else if (column.PageCount >= pagePos + 1) | 
 |                             { | 
 |                                 int offset = fromRow - column._pages[pagePos].IndexOffset; | 
 |                                 var rowPos = column._pages[pagePos].GetPosition(offset); | 
 |                                 if (rowPos < 0) | 
 |                                 { | 
 |                                     rowPos = ~rowPos; | 
 |                                 } | 
 |                                 if (column._pages[pagePos].RowCount > rowPos) | 
 |                                 { | 
 |                                     UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); | 
 |                                 } | 
 |                                 else | 
 |                                 { | 
 |                                     UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows); | 
 |                                 } | 
 |                             } | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows); | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal void Clear(int fromRow, int fromCol, int rows, int columns) | 
 |         { | 
 |             Delete(fromRow, fromCol, rows, columns, false); | 
 |         } | 
 |         internal void Delete(int fromRow, int fromCol, int rows, int columns) | 
 |         { | 
 |             Delete(fromRow, fromCol, rows, columns, true); | 
 |         } | 
 |         internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) | 
 |         { | 
 |             lock (_columnIndex) | 
 |             { | 
 |                 if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) | 
 |                 { | 
 |                     DeleteColumns(fromCol, columns, shift); | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var toCol = fromCol + columns - 1; | 
 |                     var pageFromRow = fromRow >> pageBits; | 
 |                     for (int c = 0; c < ColumnCount; c++) | 
 |                     { | 
 |                         var column = _columnIndex[c]; | 
 |                         if (column.Index >= fromCol) | 
 |                         { | 
 |                             if (column.Index > toCol) break; | 
 |                             var pagePos = column.GetPosition(fromRow); | 
 |                             if (pagePos < 0) pagePos = ~pagePos; | 
 |                             if (pagePos < column.PageCount) | 
 |                             { | 
 |                                 var page = column._pages[pagePos]; | 
 |                                 if (shift && page.RowCount > 0 && page.MinIndex > fromRow && page.MaxIndex >= fromRow + rows) | 
 |                                 { | 
 |                                     var o=page.MinIndex - fromRow; | 
 |                                     if (o < rows) | 
 |                                     { | 
 |                                         rows -= o; | 
 |                                         page.Offset -= o; | 
 |                                         UpdatePageOffset(column, pagePos, o); | 
 |                                     } | 
 |                                     else | 
 |                                     { | 
 |                                         page.Offset -= rows; | 
 |                                         UpdatePageOffset(column, pagePos, rows); | 
 |                                         continue; | 
 |                                     } | 
 |                                 } | 
 |                                 if (page.RowCount > 0 && page.MinIndex <= fromRow+rows-1 && page.MaxIndex >= fromRow) //The row is inside the page | 
 |                                 { | 
 |                                     var endRow = fromRow + rows; | 
 |                                     var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift); | 
 |                                     if (shift && delEndRow != fromRow) UpdatePageOffset(column, pagePos, delEndRow - fromRow); | 
 |                                     if (endRow > delEndRow && pagePos < column.PageCount && column._pages[pagePos].MinIndex < endRow) | 
 |                                     { | 
 |                                         pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1); | 
 |                                         var rowsLeft = DeletePage(shift ? fromRow : delEndRow, endRow - delEndRow, column, pagePos, shift); | 
 |                                         //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft); | 
 |                                         if (rowsLeft > 0) | 
 |                                         { | 
 |                                             var fr = shift ? fromRow : endRow - rowsLeft; | 
 |                                             pagePos = column.GetPosition(fr); | 
 |                                             delEndRow = DeleteCells(column._pages[pagePos], fr, shift ? fr + rowsLeft : endRow, shift); | 
 |                                             if (shift) UpdatePageOffset(column, pagePos, rowsLeft); | 
 |                                         } | 
 |                                     } | 
 |                                 } | 
 |                                 else if (pagePos > 0 && column._pages[pagePos].IndexOffset > fromRow) //The row is on the page before. | 
 |                                 { | 
 |                                     int offset = fromRow + rows - 1 - ((pageFromRow - 1) << pageBits); | 
 |                                     var rowPos = column._pages[pagePos - 1].GetPosition(offset); | 
 |                                     if (rowPos > 0 && pagePos > 0) | 
 |                                     { | 
 |                                         if (shift) UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows); | 
 |                                     } | 
 |                                 } | 
 |                                 else | 
 |                                 { | 
 |                                     if (shift && pagePos + 1 < column.PageCount) UpdateIndexOffset(column, pagePos + 1, 0, column._pages[pagePos + 1].MinIndex, -rows); | 
 |                                 } | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         private void UpdatePageOffset(ColumnIndex column, int pagePos, int rows) | 
 |         { | 
 |             //Update Pageoffset | 
 |              | 
 |             if (++pagePos < column.PageCount) | 
 |             { | 
 |                 for (int p = pagePos; p < column.PageCount; p++) | 
 |                 { | 
 |                     if (column._pages[p].Offset - rows <= -PageSize) | 
 |                     { | 
 |                         column._pages[p].Index--; | 
 |                         column._pages[p].Offset -= rows-PageSize; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         column._pages[p].Offset -= rows; | 
 |                     } | 
 |                 } | 
 |  | 
 |                 if (Math.Abs(column._pages[pagePos].Offset) > PageSize || | 
 |                     Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount-1].Index) > PageSizeMax) //Split or Merge??? | 
 |                 { | 
 |                     rows=ResetPageOffset(column, pagePos, rows); | 
 |                     ////MergePages | 
 |                     //if (column.Pages[pagePos - 1].Index + 1 == column.Pages[pagePos].Index) | 
 |                     //{ | 
 |                     //    if (column.Pages[pagePos].IndexOffset + column.Pages[pagePos].Rows[column.Pages[pagePos].RowCount - 1].Index + rows - | 
 |                     //        column.Pages[pagePos - 1].IndexOffset + column.Pages[pagePos - 1].Rows[0].Index <= PageSize) | 
 |                     //    { | 
 |                     //        //Merge | 
 |                     //        MergePage(column, pagePos - 1, -rows); | 
 |                     //    } | 
 |                     //    else | 
 |                     //    { | 
 |                     //        //Split | 
 |                     //    } | 
 |                     //} | 
 |                     //rows -= PageSize; | 
 |                     //for (int p = pagePos; p < column.PageCount; p++) | 
 |                     //{                             | 
 |                     //    column.Pages[p].Index -= 1; | 
 |                     //} | 
 |                     return; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         private int ResetPageOffset(ColumnIndex column, int pagePos, int rows) | 
 |         { | 
 |             PageIndex fromPage=column._pages[pagePos]; | 
 |             PageIndex toPage; | 
 |             short pageAdd = 0; | 
 |             if (fromPage.Offset < -PageSize) | 
 |             { | 
 |                 toPage=column._pages[pagePos-1]; | 
 |                 pageAdd = -1; | 
 |                 if (fromPage.Index - 1 == toPage.Index) | 
 |                 { | 
 |                     if (fromPage.IndexOffset + fromPage.Rows[fromPage.RowCount - 1].Index - | 
 |                         toPage.IndexOffset + toPage.Rows[0].Index <= PageSizeMax) | 
 |                     { | 
 |                         MergePage(column, pagePos - 1); | 
 |                         //var newPage = new PageIndex(toPage, 0, GetSize(fromPage.RowCount + toPage.RowCount)); | 
 |                         //newPage.RowCount = fromPage.RowCount + fromPage.RowCount; | 
 |                         //Array.Copy(toPage.Rows, 0, newPage.Rows, 0, toPage.RowCount); | 
 |                         //Array.Copy(fromPage.Rows, 0, newPage.Rows, toPage.RowCount, fromPage.RowCount); | 
 |                         //for (int r = toPage.RowCount; r < newPage.RowCount; r++) | 
 |                         //{ | 
 |                         //    newPage.Rows[r].Index += (short)(fromPage.IndexOffset - toPage.IndexOffset); | 
 |                         //} | 
 |                          | 
 |                     } | 
 |                 } | 
 |                 else //No page after  | 
 |                 { | 
 |                     fromPage.Index -= pageAdd; | 
 |                     fromPage.Offset += PageSize; | 
 |                 } | 
 |             } | 
 |             else if (fromPage.Offset > PageSize) | 
 |             { | 
 |                 toPage = column._pages[pagePos + 1]; | 
 |                 pageAdd = 1; | 
 |                 if (fromPage.Index + 1 == toPage.Index) | 
 |                 { | 
 |  | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     fromPage.Index += pageAdd; | 
 |                     fromPage.Offset += PageSize; | 
 |                 } | 
 |             } | 
 |             return rows; | 
 |         } | 
 |  | 
 |         private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) | 
 |         { | 
 |             PageIndex page = column._pages[pagePos]; | 
 |             var startRows = rows; | 
 |             while (page != null && page.MinIndex >= fromRow && ((shift && page.MaxIndex < fromRow + rows) || (!shift && page.MaxIndex < fromRow + startRows))) | 
 |             { | 
 |                 //Delete entire page. | 
 |                 var delSize=page.MaxIndex - page.MinIndex+1; | 
 |                 rows -= delSize; | 
 |                 var prevOffset = page.Offset; | 
 |                 Array.Copy(column._pages, pagePos + 1, column._pages, pagePos, column.PageCount - pagePos + 1); | 
 |                 column.PageCount--; | 
 |                 if (column.PageCount == 0) | 
 |                 { | 
 |                     return 0; | 
 |                 } | 
 |                 if(shift) | 
 |                 { | 
 |                     for (int i = pagePos; i < column.PageCount; i++) | 
 |                     { | 
 |                         column._pages[i].Offset -= delSize; | 
 |                         if (column._pages[i].Offset <= -PageSize) | 
 |                         { | 
 |                             column._pages[i].Index--; | 
 |                             column._pages[i].Offset += PageSize; | 
 |                         } | 
 |                     } | 
 |                 }                 | 
 |                 if (column.PageCount > pagePos) | 
 |                 { | 
 |                     page = column._pages[pagePos]; | 
 |                     //page.Offset = pagePos == 0 ? 1 : prevOffset;  //First page can only reference to rows starting from Index == 1 | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     //No more pages, return 0 | 
 |                     return 0; | 
 |                 } | 
 |             } | 
 |             return rows; | 
 |         } | 
 |         /// | 
 |         private int DeleteCells(PageIndex page,  int fromRow, int toRow, bool shift) | 
 |         { | 
 |             var fromPos = page.GetPosition(fromRow - (page.IndexOffset)); | 
 |             if (fromPos < 0) | 
 |             { | 
 |                 fromPos = ~fromPos; | 
 |             } | 
 |             var maxRow = page.MaxIndex; | 
 |             var offset = toRow - page.IndexOffset; | 
 |             if (offset > PageSizeMax) offset = PageSizeMax; | 
 |             var toPos = page.GetPosition(offset); | 
 |             if (toPos < 0) | 
 |             { | 
 |                 toPos = ~toPos; | 
 |             } | 
 |  | 
 |             if (fromPos <= toPos && fromPos < page.RowCount && page.GetIndex(fromPos) < toRow) | 
 |             { | 
 |                 if (toRow > page.MaxIndex) | 
 |                 { | 
 |                     if (fromRow == page.MinIndex) //Delete entire page, late in the page delete method | 
 |                     { | 
 |                         return fromRow; | 
 |                     } | 
 |                     var r = page.MaxIndex; | 
 |                     var deletedRow = page.RowCount - fromPos;  | 
 |                     page.RowCount -= deletedRow; | 
 |                     return r+1; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var rows = toRow - fromRow; | 
 |                     if(shift) UpdateRowIndex(page, toPos, rows); | 
 |                     Array.Copy(page.Rows, toPos, page.Rows, fromPos, page.RowCount - toPos); | 
 |                     page.RowCount -= toPos-fromPos; | 
 |  | 
 |                     return toRow; | 
 |                 } | 
 |             } | 
 |             else if(shift) | 
 |             { | 
 |                 UpdateRowIndex(page, toPos, toRow - fromRow); | 
 |             } | 
 |             return toRow < maxRow ? toRow : maxRow; | 
 |         } | 
 |  | 
 |         private static void UpdateRowIndex(PageIndex page, int toPos, int rows) | 
 |         { | 
 |             for (int r = toPos; r < page.RowCount; r++) | 
 |             { | 
 |                 page.Rows[r].Index -= (short) rows; | 
 |             } | 
 |         } | 
 |  | 
 |         private void DeleteColumns(int fromCol, int columns, bool shift) | 
 |         { | 
 |             var fPos = GetPosition(fromCol); | 
 |             if (fPos < 0) | 
 |             { | 
 |                 fPos = ~fPos; | 
 |             } | 
 |             int tPos = fPos; | 
 |             for (var c = fPos; c <= ColumnCount; c++) | 
 |             { | 
 |                 tPos = c; | 
 |                 if (tPos==ColumnCount || _columnIndex[c].Index >= fromCol + columns) | 
 |                 { | 
 |                     break; | 
 |                 } | 
 |             } | 
 |  | 
 |             if (ColumnCount <= fPos) | 
 |             { | 
 |                 return; | 
 |             } | 
 |  | 
 |             if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) | 
 |             { | 
 |                 //if (_columnIndex[fPos].Index < ColumnCount) | 
 |                 //{ | 
 |                     if (tPos < ColumnCount) | 
 |                     { | 
 |                         Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos); | 
 |                     } | 
 |                     ColumnCount -= (tPos - fPos); | 
 |                 //} | 
 |             } | 
 |             if (shift) | 
 |             { | 
 |                 for (var c = fPos; c < ColumnCount; c++) | 
 |                 { | 
 |                     _columnIndex[c].Index -= (short)columns; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         private void UpdateIndexOffset(ColumnIndex column, int pagePos, int rowPos, int row, int rows) | 
 |         { | 
 |             if (pagePos >= column.PageCount) return;    //A page after last cell. | 
 |             var page = column._pages[pagePos]; | 
 |             if (rows > PageSize) | 
 |             { | 
 |                 short addPages = (short)(rows >> pageBits); | 
 |                 int offset = +(int)(rows - (PageSize*addPages)); | 
 |                 for (int p = pagePos + 1; p < column.PageCount; p++) | 
 |                 { | 
 |                     if (column._pages[p].Offset + offset > PageSize) | 
 |                     { | 
 |                         column._pages[p].Index += (short)(addPages + 1); | 
 |                         column._pages[p].Offset += offset - PageSize; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         column._pages[p].Index += addPages; | 
 |                         column._pages[p].Offset += offset; | 
 |                     } | 
 |                      | 
 |                 } | 
 |  | 
 |                 var size = page.RowCount - rowPos; | 
 |                 if (page.RowCount > rowPos) | 
 |                 { | 
 |                     if (column.PageCount-1 == pagePos) //No page after, create a new one. | 
 |                     { | 
 |                         //Copy rows to next page. | 
 |                         var newPage = CopyNew(page, rowPos, size); | 
 |                         newPage.Index = (short)((row + rows) >> pageBits); | 
 |                         newPage.Offset = row + rows - (newPage.Index * PageSize) - newPage.Rows[0].Index; | 
 |                         if (newPage.Offset > PageSize) | 
 |                         { | 
 |                             newPage.Index++; | 
 |                             newPage.Offset -= PageSize; | 
 |                         } | 
 |                         AddPage(column, pagePos + 1, newPage); | 
 |                         page.RowCount = rowPos; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         if (column._pages[pagePos + 1].RowCount + size > PageSizeMax) //Split Page | 
 |                         { | 
 |                             SplitPageInsert(column,pagePos, rowPos, rows, size, addPages); | 
 |                         } | 
 |                         else //Copy Page. | 
 |                         { | 
 |                             CopyMergePage(page, rowPos, rows, size, column._pages[pagePos + 1]);                             | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |             else | 
 |             { | 
 |                 //Add to Pages. | 
 |                 for (int r = rowPos; r < page.RowCount; r++) | 
 |                 { | 
 |                     page.Rows[r].Index += (short)rows; | 
 |                 } | 
 |                 if (page.Offset + page.Rows[page.RowCount-1].Index >= PageSizeMax)   //Can not be larger than the max size of the page. | 
 |                 { | 
 |                     AdjustIndex(column, pagePos); | 
 |                     if (page.Offset + page.Rows[page.RowCount - 1].Index >= PageSizeMax) | 
 |                     { | 
 |                         pagePos=SplitPage(column, pagePos); | 
 |                     } | 
 |                     //IndexItem[] newRows = new IndexItem[GetSize(page.RowCount - page.Rows[r].Index)]; | 
 |                     //var newPage = new PageIndex(newRows, r); | 
 |                     //newPage.Index = (short)(pagePos + 1); | 
 |                     //TODO: MoveRows to next page. | 
 |                 } | 
 |  | 
 |                 for (int p = pagePos + 1; p < column.PageCount; p++) | 
 |                 { | 
 |                     if (column._pages[p].Offset + rows < PageSize) | 
 |                     { | 
 |                         column._pages[p].Offset += rows; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         column._pages[p].Index++; | 
 |                         column._pages[p].Offset = (column._pages[p].Offset+rows) % PageSize; | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         private void SplitPageInsert(ColumnIndex column,int pagePos, int rowPos, int rows, int size, int addPages) | 
 |         { | 
 |             var newRows = new IndexItem[GetSize(size)]; | 
 |             var page=column._pages[pagePos]; | 
 |  | 
 |             var rStart=-1; | 
 |             for (int r = rowPos; r < page.RowCount; r++) | 
 |             { | 
 |                 if (page.IndexExpanded - (page.Rows[r].Index + rows) > PageSize) | 
 |                 { | 
 |                     rStart = r; | 
 |                     break; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     page.Rows[r].Index += (short)rows; | 
 |                 } | 
 |             } | 
 |             var rc = page.RowCount - rStart; | 
 |             page.RowCount=rStart; | 
 |             if(rc>0) | 
 |             { | 
 |                 //Copy to a new page | 
 |                 var row = page.IndexOffset; | 
 |                 var newPage=CopyNew(page,rStart,rc); | 
 |                 var ix = (short)(page.Index + addPages); | 
 |                 var offset = page.IndexOffset + rows - (ix * PageSize); | 
 |                 if (offset > PageSize) | 
 |                 { | 
 |                     ix += (short)(offset / PageSize); | 
 |                     offset %= PageSize; | 
 |                 } | 
 |                 newPage.Index = ix; | 
 |                 newPage.Offset = offset; | 
 |                 AddPage(column, pagePos + 1, newPage); | 
 |             } | 
 |  | 
 |             //Copy from next Row | 
 |         } | 
 |  | 
 |         private void CopyMergePage(PageIndex page, int rowPos, int rows, int size, PageIndex ToPage) | 
 |         { | 
 |             var startRow = page.IndexOffset + page.Rows[rowPos].Index + rows; | 
 |             var newRows = new IndexItem[GetSize(ToPage.RowCount + size)]; | 
 |             page.RowCount -= size; | 
 |             Array.Copy(page.Rows, rowPos, newRows, 0, size); | 
 |             for (int r = 0; r < size; r++) | 
 |             { | 
 |                 newRows[r].Index += (short)(page.IndexOffset + rows - ToPage.IndexOffset); | 
 |             } | 
 |  | 
 |             Array.Copy(ToPage.Rows, 0, newRows, size, ToPage.RowCount); | 
 |             ToPage.Rows = newRows; | 
 |             ToPage.RowCount += size; | 
 |         } | 
 |         private void MergePage(ColumnIndex column, int pagePos) | 
 |         { | 
 |             PageIndex Page1=column._pages[pagePos]; | 
 |             PageIndex Page2 = column._pages[pagePos + 1]; | 
 |  | 
 |             var newPage = new PageIndex(Page1, 0, Page1.RowCount + Page2.RowCount); | 
 |             newPage.RowCount = Page1.RowCount + Page2.RowCount; | 
 |             Array.Copy(Page1.Rows, 0, newPage.Rows, 0, Page1.RowCount); | 
 |             Array.Copy(Page2.Rows, 0, newPage.Rows, Page1.RowCount, Page2.RowCount); | 
 |             for (int r = Page1.RowCount; r < newPage.RowCount; r++) | 
 |             { | 
 |                 newPage.Rows[r].Index += (short)(Page2.IndexOffset - Page1.IndexOffset); | 
 |             } | 
 |  | 
 |             column._pages[pagePos] = newPage; | 
 |             column.PageCount--; | 
 |  | 
 |             if (column.PageCount > (pagePos + 1)) | 
 |             { | 
 |                 Array.Copy(column._pages, pagePos+2, column._pages,pagePos+1,column.PageCount-(pagePos+1)); | 
 |                 for (int p = pagePos + 1; p < column.PageCount; p++) | 
 |                 { | 
 |                     column._pages[p].Index--; | 
 |                     column._pages[p].Offset += PageSize; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         private PageIndex CopyNew(PageIndex pageFrom, int rowPos, int size) | 
 |         { | 
 |             IndexItem[] newRows = new IndexItem[GetSize(size)]; | 
 |             Array.Copy(pageFrom.Rows, rowPos, newRows, 0, size); | 
 |             return new PageIndex(newRows, size); | 
 |         } | 
 |  | 
 |         internal static int GetSize(int size) | 
 |         { | 
 |             var newSize=256; | 
 |             while (newSize < size) | 
 |             { | 
 |                 newSize <<= 1; | 
 |             } | 
 |             return newSize; | 
 |         } | 
 |         private void AddCell(ColumnIndex columnIndex, int pagePos, int pos, short ix, T value) | 
 |         { | 
 |             PageIndex pageItem = columnIndex._pages[pagePos]; | 
 |             if (pageItem.RowCount == pageItem.Rows.Length) | 
 |             { | 
 |                 if (pageItem.RowCount == PageSizeMax) //Max size-->Split | 
 |                 { | 
 |                     pagePos=SplitPage(columnIndex, pagePos); | 
 |                     if (columnIndex._pages[pagePos - 1].RowCount > pos) | 
 |                     { | 
 |                         pagePos--;                         | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         pos -= columnIndex._pages[pagePos - 1].RowCount; | 
 |                     } | 
 |                     pageItem = columnIndex._pages[pagePos]; | 
 |                 } | 
 |                 else //Expand to double size. | 
 |                 { | 
 |                     var rowsTmp = new IndexItem[pageItem.Rows.Length << 1]; | 
 |                     Array.Copy(pageItem.Rows, 0, rowsTmp, 0, pageItem.RowCount); | 
 |                     pageItem.Rows = rowsTmp; | 
 |                 } | 
 |             } | 
 |             if (pos < pageItem.RowCount) | 
 |             { | 
 |                 Array.Copy(pageItem.Rows, pos, pageItem.Rows, pos + 1, pageItem.RowCount - pos); | 
 |             } | 
 |             pageItem.Rows[pos] = new IndexItem() { Index = ix,IndexPointer=_values.Count }; | 
 |             _values.Add(value); | 
 |             pageItem.RowCount++; | 
 |         } | 
 |  | 
 |         private int SplitPage(ColumnIndex columnIndex, int pagePos) | 
 |         { | 
 |             var page = columnIndex._pages[pagePos]; | 
 |             if (page.Offset != 0) | 
 |             { | 
 |                 var offset = page.Offset; | 
 |                 page.Offset = 0; | 
 |                 for (int r = 0; r < page.RowCount; r++) | 
 |                 { | 
 |                     page.Rows[r].Index -= (short)offset; | 
 |                 } | 
 |             } | 
 |             //Find Split pos | 
 |             int splitPos=0;             | 
 |             for (int r = 0; r < page.RowCount; r++) | 
 |             { | 
 |                 if (page.Rows[r].Index > PageSize) | 
 |                 { | 
 |                     splitPos=r; | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             var newPage = new PageIndex(page, 0, splitPos); | 
 |             var nextPage = new PageIndex(page, splitPos, page.RowCount - splitPos, (short)(page.Index + 1), page.Offset); | 
 |  | 
 |             for (int r = 0; r < nextPage.RowCount; r++) | 
 |             { | 
 |                 nextPage.Rows[r].Index = (short)(nextPage.Rows[r].Index - PageSize); | 
 |             } | 
 |              | 
 |             columnIndex._pages[pagePos] = newPage; | 
 |             if (columnIndex.PageCount + 1 > columnIndex._pages.Length) | 
 |             { | 
 |                 var pageTmp = new PageIndex[columnIndex._pages.Length << 1]; | 
 |                 Array.Copy(columnIndex._pages, 0, pageTmp, 0, columnIndex.PageCount); | 
 |                 columnIndex._pages = pageTmp; | 
 |             } | 
 |             Array.Copy(columnIndex._pages, pagePos + 1, columnIndex._pages, pagePos + 2, columnIndex.PageCount - pagePos - 1); | 
 |             columnIndex._pages[pagePos + 1] = nextPage; | 
 |             page = nextPage; | 
 |             //pos -= PageSize; | 
 |             columnIndex.PageCount++; | 
 |             return pagePos+1; | 
 |         } | 
 |  | 
 |         private PageIndex AdjustIndex(ColumnIndex columnIndex, int pagePos) | 
 |         { | 
 |             PageIndex page = columnIndex._pages[pagePos]; | 
 |             //First Adjust indexes | 
 |             if (page.Offset + page.Rows[0].Index >= PageSize || | 
 |                 page.Offset >= PageSize || | 
 |                 page.Rows[0].Index >= PageSize) | 
 |             { | 
 |                 page.Index++; | 
 |                 page.Offset -= PageSize; | 
 |             } | 
 |             else if (page.Offset + page.Rows[0].Index  <= -PageSize ||  | 
 |                      page.Offset <= -PageSize || | 
 |                      page.Rows[0].Index <= -PageSize) | 
 |             { | 
 |                 page.Index--; | 
 |                 page.Offset += PageSize; | 
 |             } | 
 |             //else if (page.Rows[0].Index >= PageSize) //Delete | 
 |             //{ | 
 |             //    page.Index++; | 
 |             //    AddPageRowOffset(page, -PageSize); | 
 |             //} | 
 |             //else if (page.Rows[0].Index <= -PageSize)   //Delete | 
 |             //{ | 
 |             //    page.Index--; | 
 |             //    AddPageRowOffset(page, PageSize); | 
 |             //} | 
 |             return page; | 
 |         } | 
 |  | 
 |         private void AddPageRowOffset(PageIndex page, short offset) | 
 |         { | 
 |             for (int r = 0; r < page.RowCount; r++) | 
 |             { | 
 |                 page.Rows[r].Index += offset; | 
 |             } | 
 |         } | 
 |         private void AddPage(ColumnIndex column, int pos, short index) | 
 |         { | 
 |             AddPage(column, pos); | 
 |             column._pages[pos] = new PageIndex() { Index = index }; | 
 |             if (pos > 0) | 
 |             { | 
 |                 var pp=column._pages[pos-1]; | 
 |                 if(pp.RowCount>0 && pp.Rows[pp.RowCount-1].Index > PageSize) | 
 |                 { | 
 |                     column._pages[pos].Offset = pp.Rows[pp.RowCount-1].Index-PageSize; | 
 |                 } | 
 |             } | 
 |         } | 
 |         /// <summary> | 
 |         /// Add a new page to the collection | 
 |         /// </summary> | 
 |         /// <param name="column">The column</param> | 
 |         /// <param name="pos">Position</param> | 
 |         /// <param name="page">The new page object to add</param> | 
 |         private void AddPage(ColumnIndex column, int pos, PageIndex page) | 
 |         { | 
 |             AddPage(column, pos); | 
 |             column._pages[pos] = page ; | 
 |         } | 
 |         /// <summary> | 
 |         /// Add a new page to the collection | 
 |         /// </summary> | 
 |         /// <param name="column">The column</param> | 
 |         /// <param name="pos">Position</param> | 
 |         private void AddPage(ColumnIndex column, int pos) | 
 |         { | 
 |             if (column.PageCount ==column._pages.Length) | 
 |             { | 
 |                 var pageTmp = new PageIndex[column._pages.Length * 2]; | 
 |                 Array.Copy(column._pages, 0, pageTmp, 0, column.PageCount); | 
 |                 column._pages = pageTmp; | 
 |             } | 
 |             if (pos < column.PageCount) | 
 |             { | 
 |                 Array.Copy(column._pages, pos, column._pages, pos + 1, column.PageCount - pos); | 
 |             } | 
 |             column.PageCount++; | 
 |         } | 
 |         private void AddColumn(int pos, int Column) | 
 |         { | 
 |             if (ColumnCount == _columnIndex.Length) | 
 |             { | 
 |                 var colTmp = new ColumnIndex[_columnIndex.Length*2]; | 
 |                 Array.Copy(_columnIndex, 0, colTmp, 0, ColumnCount); | 
 |                 _columnIndex = colTmp; | 
 |             } | 
 |             if (pos < ColumnCount) | 
 |             { | 
 |                 Array.Copy(_columnIndex, pos, _columnIndex, pos + 1, ColumnCount - pos); | 
 |             } | 
 |             _columnIndex[pos] = new ColumnIndex() { Index = (short)(Column) }; | 
 |             ColumnCount++; | 
 |         }         | 
 |         int _colPos = -1, _row; | 
 |         public ulong Current | 
 |         { | 
 |             get | 
 |             { | 
 |                 return ((ulong)_row << 32) | (uint)(_columnIndex[_colPos].Index); | 
 |             } | 
 |         } | 
 |  | 
 |         public void Dispose() | 
 |         { | 
 |             if(_values!=null) _values.Clear(); | 
 |             for(var c=0;c<ColumnCount;c++) | 
 |             { | 
 |                 if (_columnIndex[c] != null) | 
 |                 { | 
 |                     ((IDisposable)_columnIndex[c]).Dispose(); | 
 |                 } | 
 |             } | 
 |             _values = null; | 
 |             _columnIndex = null; | 
 |         } | 
 |  | 
 |         //object IEnumerator.Current | 
 |         //{ | 
 |         //    get  | 
 |         //    { | 
 |         //        return GetValue(_row+1, _columnIndex[_colPos].Index); | 
 |         //    } | 
 |         //} | 
 |         public bool MoveNext() | 
 |         { | 
 |             return GetNextCell(ref _row, ref _colPos, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); | 
 |         } | 
 |         internal bool NextCell(ref int row, ref int col) | 
 |         { | 
 |              | 
 |             return NextCell(ref row, ref col, 0,0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); | 
 |         } | 
 |         internal bool NextCell(ref int row, ref int col, int minRow, int minColPos,int maxRow, int maxColPos) | 
 |         { | 
 |             if (minColPos >= ColumnCount) | 
 |             { | 
 |                 return false; | 
 |             } | 
 |             if (maxColPos >= ColumnCount) | 
 |             { | 
 |                 maxColPos = ColumnCount-1; | 
 |             } | 
 |             var c=GetPosition(col); | 
 |             if(c>=0) | 
 |             { | 
 |                 if (c > maxColPos) | 
 |                 { | 
 |                     if (col <= minColPos) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     col = minColPos; | 
 |                     return NextCell(ref row, ref col); | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var r=GetNextCell(ref row, ref c, minColPos, maxRow, maxColPos); | 
 |                     col = _columnIndex[c].Index; | 
 |                     return r; | 
 |                 } | 
 |             } | 
 |             else | 
 |             { | 
 |                 c=~c; | 
 |                 if (c > _columnIndex[c].Index) | 
 |                 { | 
 |                     if (col <= minColPos) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     col = minColPos; | 
 |                     return NextCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); | 
 |                 } | 
 |                 else | 
 |                 {                     | 
 |                     var r=GetNextCell(ref c, ref row, minColPos, maxRow, maxColPos); | 
 |                     col = _columnIndex[c].Index; | 
 |                     return r; | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal bool GetNextCell(ref int row, ref int colPos, int startColPos, int endRow, int endColPos) | 
 |         { | 
 |             if (ColumnCount == 0) | 
 |             { | 
 |                 return false; | 
 |             } | 
 |             else | 
 |             { | 
 |                 if (++colPos < ColumnCount && colPos <=endColPos) | 
 |                 { | 
 |                     var r = _columnIndex[colPos].GetNextRow(row); | 
 |                     if (r == row) //Exists next Row | 
 |                     { | 
 |                         return true; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         int minRow, minCol; | 
 |                         if (r > row) | 
 |                         { | 
 |                             minRow = r; | 
 |                             minCol = colPos; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             minRow = int.MaxValue; | 
 |                             minCol = 0; | 
 |                         } | 
 |  | 
 |                         var c = colPos + 1; | 
 |                         while (c < ColumnCount && c <= endColPos) | 
 |                         { | 
 |                             r = _columnIndex[c].GetNextRow(row); | 
 |                             if (r == row) //Exists next Row | 
 |                             { | 
 |                                 colPos = c; | 
 |                                 return true; | 
 |                             } | 
 |                             if (r > row && r < minRow) | 
 |                             { | 
 |                                 minRow = r; | 
 |                                 minCol = c; | 
 |                             } | 
 |                             c++; | 
 |                         } | 
 |                         c = startColPos; | 
 |                         if (row < endRow) | 
 |                         { | 
 |                             row++; | 
 |                             while (c < colPos) | 
 |                             { | 
 |                                 r = _columnIndex[c].GetNextRow(row); | 
 |                                 if (r == row) //Exists next Row | 
 |                                 { | 
 |                                     colPos = c; | 
 |                                     return true; | 
 |                                 } | 
 |                                 if (r > row && (r < minRow || (r==minRow && c<minCol)) && r <= endRow) | 
 |                                 { | 
 |                                     minRow = r; | 
 |                                     minCol = c; | 
 |                                 } | 
 |                                 c++; | 
 |                             } | 
 |                         } | 
 |  | 
 |                         if (minRow == int.MaxValue || minRow > endRow) | 
 |                         { | 
 |                             return false; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             row = minRow; | 
 |                             colPos = minCol; | 
 |                             return true; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     if (colPos <= startColPos || row>=endRow) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     colPos = startColPos - 1; | 
 |                     row++; | 
 |                     return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos); | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal bool GetNextCell(ref int row, ref int colPos, int startColPos, int endRow, int endColPos, ref int[] pagePos, ref int[] cellPos) | 
 |         { | 
 |             if (colPos == endColPos) | 
 |             { | 
 |                 colPos = startColPos; | 
 |                 row++; | 
 |             } | 
 |             else | 
 |             { | 
 |                 colPos++; | 
 |             } | 
 |  | 
 |             if (pagePos[colPos] < 0) | 
 |             { | 
 |                 if(pagePos[colPos]==-1) | 
 |                 { | 
 |                     pagePos[colPos] = _columnIndex[colPos].GetPosition(row); | 
 |                 } | 
 |             } | 
 |             else if (_columnIndex[colPos]._pages[pagePos[colPos]].RowCount <= row) | 
 |             { | 
 |                 if (_columnIndex[colPos].PageCount > pagePos[colPos]) | 
 |                     pagePos[colPos]++; | 
 |                 else | 
 |                 { | 
 |                     pagePos[colPos]=-2; | 
 |                 } | 
 |             } | 
 |              | 
 |             var r = _columnIndex[colPos]._pages[pagePos[colPos]].IndexOffset + _columnIndex[colPos]._pages[pagePos[colPos]].Rows[cellPos[colPos]].Index; | 
 |             if (r == row) | 
 |             { | 
 |                 row = r; | 
 |             } | 
 |             else | 
 |             { | 
 |             } | 
 |             return true; | 
 |         } | 
 |         internal bool PrevCell(ref int row, ref int col) | 
 |         { | 
 |             return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); | 
 |         } | 
 |         internal bool PrevCell(ref int row, ref int col, int minRow, int minColPos, int maxRow, int maxColPos) | 
 |         { | 
 |             if (minColPos >= ColumnCount) | 
 |             { | 
 |                 return false; | 
 |             } | 
 |             if (maxColPos >= ColumnCount) | 
 |             { | 
 |                 maxColPos = ColumnCount - 1; | 
 |             } | 
 |             var c = GetPosition(col); | 
 |             if(c>=0) | 
 |             { | 
 |                 if (c == 0) | 
 |                 { | 
 |                     if (col >= maxColPos) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     if (row == minRow) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     row--; | 
 |                     col = maxColPos;                     | 
 |                     return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var ret=GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); | 
 |                     if (ret) | 
 |                     { | 
 |                         col = _columnIndex[c].Index; | 
 |                     } | 
 |                     return ret; | 
 |                 } | 
 |             } | 
 |             else | 
 |             { | 
 |                 c=~c; | 
 |                 if (c == 0) | 
 |                 { | 
 |                     if (col >= maxColPos || row<=0) | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                     col = maxColPos; | 
 |                     row--; | 
 |                     return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); | 
 |                     if (ret) | 
 |                     { | 
 |                         col = _columnIndex[c].Index; | 
 |                     } | 
 |                     return ret; | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal bool GetPrevCell(ref int row, ref int colPos, int startRow, int startColPos, int endColPos) | 
 |         { | 
 |             if (ColumnCount == 0) | 
 |             { | 
 |                 return false; | 
 |             } | 
 |             else | 
 |             { | 
 |                 if (--colPos >= startColPos) | 
 | //                if (++colPos < ColumnCount && colPos <= endColPos) | 
 |                 { | 
 |                     var r = _columnIndex[colPos].GetNextRow(row); | 
 |                     if (r == row) //Exists next Row | 
 |                     { | 
 |                         return true; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         int minRow, minCol; | 
 |                         if (r > row && r >= startRow) | 
 |                         { | 
 |                             minRow = r; | 
 |                             minCol = colPos; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             minRow = int.MaxValue; | 
 |                             minCol = 0; | 
 |                         } | 
 |  | 
 |                         var c = colPos - 1; | 
 |                         if (c >= startColPos) | 
 |                         { | 
 |                             while (c >= startColPos) | 
 |                             { | 
 |                                 r = _columnIndex[c].GetNextRow(row); | 
 |                                 if (r == row) //Exists next Row | 
 |                                 { | 
 |                                     colPos = c; | 
 |                                     return true; | 
 |                                 } | 
 |                                 if (r > row && r < minRow && r >= startRow) | 
 |                                 { | 
 |                                     minRow = r; | 
 |                                     minCol = c; | 
 |                                 } | 
 |                                 c--; | 
 |                             } | 
 |                         } | 
 |                         if (row > startRow) | 
 |                         { | 
 |                             c = endColPos; | 
 |                             row--; | 
 |                             while (c > colPos) | 
 |                             { | 
 |                                 r = _columnIndex[c].GetNextRow(row); | 
 |                                 if (r == row) //Exists next Row | 
 |                                 { | 
 |                                     colPos = c; | 
 |                                     return true; | 
 |                                 } | 
 |                                 if (r > row && r < minRow && r >= startRow) | 
 |                                 { | 
 |                                     minRow = r; | 
 |                                     minCol = c; | 
 |                                 } | 
 |                                 c--; | 
 |                             } | 
 |                         } | 
 |                         if (minRow == int.MaxValue || startRow < minRow) | 
 |                         { | 
 |                             return false; | 
 |                         } | 
 |                         else | 
 |                         { | 
 |                             row = minRow; | 
 |                             colPos = minCol; | 
 |                             return true; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     colPos = ColumnCount; | 
 |                     row--; | 
 |                     if (row < startRow) | 
 |                     { | 
 |                         Reset(); | 
 |                         return false; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos); | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         public void Reset() | 
 |         { | 
 |             _colPos = -1;             | 
 |             _row= 0; | 
 |         } | 
 |  | 
 |         //public IEnumerator<ulong> GetEnumerator() | 
 |         //{ | 
 |         //    this.Reset(); | 
 |         //    return this; | 
 |         //} | 
 |  | 
 |         //IEnumerator IEnumerable.GetEnumerator() | 
 |         //{ | 
 |         //    this.Reset(); | 
 |         //    return this; | 
 |         //} | 
 |  | 
 |     } | 
 |     internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> | 
 |     { | 
 |         CellStore<T> _cellStore; | 
 |         int row, colPos; | 
 |         int[] pagePos, cellPos; | 
 |         int _startRow, _startCol, _endRow, _endCol; | 
 |         int minRow, minColPos, maxRow, maxColPos; | 
 |         public CellsStoreEnumerator(CellStore<T> cellStore) : | 
 |             this(cellStore, 0,0,ExcelPackage.MaxRows, ExcelPackage.MaxColumns)         | 
 |         { | 
 |         } | 
 |         public CellsStoreEnumerator(CellStore<T> cellStore, int StartRow, int StartCol, int EndRow, int EndCol) | 
 |         { | 
 |             _cellStore = cellStore; | 
 |              | 
 |             _startRow=StartRow; | 
 |             _startCol=StartCol; | 
 |             _endRow=EndRow; | 
 |             _endCol=EndCol; | 
 |  | 
 |             Init(); | 
 |  | 
 |         } | 
 |  | 
 |         internal void Init() | 
 |         { | 
 |             minRow = _startRow; | 
 |             maxRow = _endRow; | 
 |  | 
 |             minColPos = _cellStore.GetPosition(_startCol); | 
 |             if (minColPos < 0) minColPos = ~minColPos; | 
 |             maxColPos = _cellStore.GetPosition(_endCol); | 
 |             if (maxColPos < 0) maxColPos = ~maxColPos-1; | 
 |             row = minRow; | 
 |             colPos = minColPos - 1; | 
 |  | 
 |             var cols = maxColPos - minColPos + 1; | 
 |             pagePos = new int[cols]; | 
 |             cellPos = new int[cols]; | 
 |             for (int i = 0; i < cols; i++) | 
 |             { | 
 |                 pagePos[i] = -1; | 
 |                 cellPos[i] = -1; | 
 |             } | 
 |         } | 
 |         internal int Row  | 
 |         { | 
 |             get | 
 |             { | 
 |                 return row; | 
 |             } | 
 |         } | 
 |         internal int Column | 
 |         { | 
 |             get | 
 |             { | 
 |                 if (colPos == -1) MoveNext(); | 
 |                 if (colPos == -1) return 0; | 
 |                 return _cellStore._columnIndex[colPos].Index; | 
 |             } | 
 |         } | 
 |         internal T Value | 
 |         { | 
 |             get | 
 |             { | 
 |                 lock (_cellStore) | 
 |                 { | 
 |                     return _cellStore.GetValue(row, Column); | 
 |                 } | 
 |             } | 
 |             set | 
 |             { | 
 |                 lock (_cellStore) | 
 |                 { | 
 |                     _cellStore.SetValue(row, Column, value); | 
 |                 } | 
 |             } | 
 |         } | 
 |         internal bool Next() | 
 |         { | 
 |             //return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); | 
 |             return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); | 
 |         } | 
 |         internal bool Previous() | 
 |         { | 
 |             lock (_cellStore) | 
 |             { | 
 |                 return _cellStore.GetPrevCell(ref row, ref colPos, minRow, minColPos, maxColPos); | 
 |             } | 
 |         } | 
 |  | 
 |         public string CellAddress  | 
 |         { | 
 |             get | 
 |             { | 
 |                 return ExcelAddressBase.GetAddress(Row, Column); | 
 |             } | 
 |         } | 
 |  | 
 |         public IEnumerator<T> GetEnumerator() | 
 |         { | 
 |             Reset(); | 
 |             return this; | 
 |         } | 
 |  | 
 |         IEnumerator IEnumerable.GetEnumerator() | 
 |         { | 
 |             Reset(); | 
 |             return this; | 
 |         } | 
 |  | 
 |         public T Current | 
 |         { | 
 |             get | 
 |             { | 
 |                 return Value; | 
 |             } | 
 |         } | 
 |  | 
 |         public void Dispose() | 
 |         { | 
 |             //_cellStore=null; | 
 |         } | 
 |  | 
 |         object IEnumerator.Current | 
 |         { | 
 |             get  | 
 |             { | 
 |                 Reset(); | 
 |                 return this; | 
 |             } | 
 |         } | 
 |  | 
 |         public bool MoveNext() | 
 |         { | 
 |             return Next(); | 
 |         } | 
 |  | 
 |         public void Reset() | 
 |         { | 
 |             Init(); | 
 |         } | 
 |     } | 
 |     internal class FlagCellStore : CellStore<byte> | 
 |     { | 
 |         internal void SetFlagValue(int Row, int Col, bool value, CellFlags cellFlags) | 
 |         { | 
 |             CellFlags currentValue = (CellFlags) GetValue(Row, Col); | 
 |             if (value) | 
 |             { | 
 |                 SetValue(Row, Col, (byte)(currentValue | cellFlags)); // add the CellFlag bit | 
 |             } | 
 |             else | 
 |             { | 
 |                 SetValue(Row, Col, (byte)(currentValue & ~cellFlags)); // remove the CellFlag bit | 
 |             } | 
 |         } | 
 |         internal bool GetFlagValue(int Row, int Col, CellFlags cellFlags) | 
 |         { | 
 |             return !(((byte)cellFlags & GetValue(Row, Col)) == 0); | 
 |         } | 
 |     } |