/**
  * Converts all {@link FormulaRecord}s handled by <tt>sharedFormulaRecord</tt> to plain unshared
  * formulas
  */
 public void unlink(SharedFormulaRecord sharedFormulaRecord) {
   SharedFormulaGroup svg = _groupsBySharedFormulaRecord.remove(sharedFormulaRecord);
   if (svg == null) {
     throw new IllegalStateException("Failed to find formulas for shared formula");
   }
   _groupsCache = null; // be sure to reset cached value
   svg.unlinkSharedFormulas();
 }
 /**
  * @param firstCell as extracted from the {@link ExpPtg} from the cell's formula.
  * @return never <code>null</code>
  */
 public SharedFormulaRecord linkSharedFormulaRecord(
     CellReference firstCell, FormulaRecordAggregate agg) {
   SharedFormulaGroup result = findFormulaGroupForCell(firstCell);
   if (null == result) {
     throw new RuntimeException("Failed to find a matching shared formula record");
   }
   result.add(agg);
   return result.getSFR();
 }
  /**
   * Gets the {@link SharedValueRecordBase} record if it should be encoded immediately after the
   * formula record contained in the specified {@link FormulaRecordAggregate} agg. Note - the shared
   * value record always appears after the first formula record in the group. For arrays and tables
   * the first formula is always the in the top left cell. However, since shared formula groups can
   * be sparse and/or overlap, the first formula may not actually be in the top left cell.
   *
   * @return the SHRFMLA, TABLE or ARRAY record for the formula cell, if it is the first cell of a
   *     table or array region. <code>null</code> if the formula cell is not shared/array/table, or
   *     if the specified formula is not the the first in the group.
   */
  public SharedValueRecordBase getRecordForFirstCell(FormulaRecordAggregate agg) {
    CellReference firstCell = agg.getFormulaRecord().getFormula().getExpReference();
    // perhaps this could be optimised by consulting the (somewhat unreliable) isShared flag
    // and/or distinguishing between tExp and tTbl.
    if (firstCell == null) {
      // not a shared/array/table formula
      return null;
    }

    int row = firstCell.getRow();
    int column = firstCell.getCol();
    if (agg.getRow() != row || agg.getColumn() != column) {
      // not the first formula cell in the group
      return null;
    }

    if (!_groupsBySharedFormulaRecord.isEmpty()) {
      SharedFormulaGroup sfg = findFormulaGroupForCell(firstCell);
      if (null != sfg) {
        return sfg.getSFR();
      }
    }

    // Since arrays and tables cannot be sparse (all cells in range participate)
    // The first cell will be the top left in the range.  So we can match the
    // ARRAY/TABLE record directly.

    for (TableRecord tr : _tableRecords) {
      if (tr.isFirstCell(row, column)) {
        return tr;
      }
    }
    for (ArrayRecord ar : _arrayRecords) {
      if (ar.isFirstCell(row, column)) {
        return ar;
      }
    }
    return null;
  }