public PlainValueCellCacheEntry GetPlainValueEntry(int bookIndex, int sheetIndex,
                                                           int rowIndex, int columnIndex, ValueEval value)
        {
            Loc loc = new Loc(bookIndex, sheetIndex, rowIndex, columnIndex);
            PlainValueCellCacheEntry result = _plainCellCache.Get(loc);

            if (result == null)
            {
                result = new PlainValueCellCacheEntry(value);
                _plainCellCache.Put(loc, result);
                if (_evaluationListener != null)
                {
                    _evaluationListener.OnReadPlainValue(sheetIndex, rowIndex, columnIndex, result);
                }
            }
            else
            {
                // TODO - if we are confident that this sanity check is not required, we can Remove 'value' from plain value cache entry
                if (!AreValuesEqual(result.GetValue(), value))
                {
                    throw new InvalidOperationException("value changed");
                }
                if (_evaluationListener != null)
                {
                    _evaluationListener.OnCacheHit(sheetIndex, rowIndex, columnIndex, value);
                }
            }
            return(result);
        }
        public void NotifyUpdateCell(int bookIndex, int sheetIndex, EvaluationCell cell)
        {
            FormulaCellCacheEntry fcce = _formulaCellCache.Get(cell);

            Loc loc = new Loc(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
            PlainValueCellCacheEntry pcce = _plainCellCache.Get(loc);

            if (cell.CellType == NPOI.SS.UserModel.CellType.FORMULA)
            {
                if (fcce == null)
                {
                    if (pcce == null)
                    {
                        UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
                    }
                    fcce = new FormulaCellCacheEntry();
                    _formulaCellCache.Put(cell, fcce);
                }
                else
                {
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    fcce.ClearFormulaEntry();
                }
                if (pcce == null)
                {
                    // was formula cell before - no Change of type
                }
                else
                {
                    // changing from plain cell To formula cell
                    pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    _plainCellCache.Remove(loc);
                }
            }
            else
            {
                ValueEval value = WorkbookEvaluator.GetValueFromNonFormulaCell(cell);
                if (pcce == null)
                {
                    if (fcce == null)
                    {
                        UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
                    }
                    pcce = new PlainValueCellCacheEntry(value);
                    _plainCellCache.Put(loc, pcce);
                    if (_evaluationListener != null)
                    {
                        _evaluationListener.OnReadPlainValue(sheetIndex, cell.RowIndex, cell.ColumnIndex, pcce);
                    }
                }
                else
                {
                    if (pcce.UpdateValue(value))
                    {
                        pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    }
                }
                if (fcce == null)
                {
                    // was plain cell before - no Change of type
                }
                else
                {
                    // was formula cell before - now a plain value
                    _formulaCellCache.Remove(cell);
                    fcce.SetSensitiveInputCells(null);
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                }
            }
        }