private static Map<Object, IRecord> getRecordsById(
     List<IRecord> updatedOrAdded, int idFieldIndex) {
   Map<Object, IRecord> res = new HashMap<Object, IRecord>(updatedOrAdded.size());
   for (IRecord iRecord : updatedOrAdded) {
     IField fieldId = iRecord.getFieldAt(idFieldIndex);
     Assert.assertNotNull(fieldId, "fieldId");
     Object value = fieldId.getValue();
     Assert.assertNotNull(value, "value");
     res.put(value, iRecord);
   }
   return res;
 }
 private static List<IRecord> getAdded(
     IDataStore prev, RecordRetriever currRetr, int prevFieldIndex) {
   List<IRecord> added = new ArrayList<IRecord>();
   for (int i = 0; i < currRetr.countRecords(); i++) {
     IRecord currRec = currRetr.getRecord(i);
     IField currIdField = currRec.getFieldAt(prevFieldIndex);
     Assert.assertNotNull(currIdField, "currId");
     Object id = currIdField.getValue();
     Assert.assertNotNull(id, "id");
     if (prev.getRecordByID(id) == null) {
       added.add(currRec);
     }
   }
   return added;
 }
 private static List<IRecord> getDeleted(IDataStore prev, IDataStore curr, int prevFieldIndex) {
   List<IRecord> deleted = new ArrayList<IRecord>();
   for (int i = 0; i < prev.getRecordsCount(); i++) {
     IRecord prevRec = prev.getRecordAt(i);
     IField prevIdField = prevRec.getFieldAt(prevFieldIndex);
     Assert.assertNotNull(prevIdField, "prevIdField");
     Object prevId = prevIdField.getValue();
     Assert.assertNotNull(prevId, "prevId");
     IRecord currRec = curr.getRecordByID(prevId);
     if (currRec == null) {
       deleted.add(prevRec);
       continue;
     }
   }
   return deleted;
 }
  private static List<IRecord> getUpdated(
      IDataStore prev, RecordIdRetriever currRetr, int prevFieldIndex) {
    List<IRecord> updated = new ArrayList<IRecord>();
    for (int i = 0; i < prev.getRecordsCount(); i++) {
      IRecord prevRec = prev.getRecordAt(i);
      IField prevIdField = prevRec.getFieldAt(prevFieldIndex);
      Assert.assertNotNull(prevIdField, "prevIdField");
      Object prevId = prevIdField.getValue();
      Assert.assertNotNull(prevId, "prevId");
      IRecord currRec = currRetr.getRecordById(prevId);
      if (currRec == null) {
        // deleted
        continue;
      }

      // check updated by position of field
      // a impossible improvement: check the changes by field meta's name
      List<IField> prevFields = prevRec.getFields();
      List<IField> currFields = currRec.getFields();
      if (prevFields.size() != currFields.size()) {
        updated.add(currRec);
        continue;
      }

      // check updated by checking fields values
      for (int j = 0; j < prevFields.size(); j++) {
        IField prevField = prevFields.get(j);
        IField currField = currFields.get(j);

        Assert.assertNotNull(prevField, "prevField");
        Assert.assertNotNull(currField, "currField");

        Object prevValue = prevField.getValue();
        Object currValue = currField.getValue();

        boolean equals = areEquals(prevValue, currValue);
        if (!equals) {
          updated.add(currRec);
          break;
        }
      }
    }
    return updated;
  }
  private void addSumRows(IDataStore dataStore) {
    logger.debug("IN");

    summaryColorCellsArray = new JSONArray();
    summaryCellsArray = new JSONArray();

    ArrayList<Integer> columnsIndexToMerge = new ArrayList<Integer>();
    ArrayList<Integer> columnsIndexToEmpty = new ArrayList<Integer>();
    ArrayList<Integer> columnsIndexToAfter = new ArrayList<Integer>();
    HashMap<Integer, Object> columnsIndexToSum2Counter = new HashMap<Integer, Object>();

    // collect columns to merge and columns to sum and colummsn to empty:
    // -- columns to merge have merge attributes until a columns with summaryFunc is found
    // then other columns that have merge attribute but no
    List<Column> columns = registryConfig.getColumns();

    Integer index = 0;
    boolean summaryFuncFound = false;
    boolean measureFound = false;

    for (Iterator iterator = columns.iterator(); iterator.hasNext(); ) {
      Column column = (Column) iterator.next();

      if (column.isMerge() && summaryFuncFound == false) {
        columnsIndexToMerge.add(index);
      } else if (summaryFuncFound == true && !column.isMeasure() && !measureFound) {
        columnsIndexToEmpty.add(index);
      } else if (summaryFuncFound == true && !column.isMeasure() && measureFound) {
        columnsIndexToAfter.add(index);
      } else if (column.isMeasure()) {
        columnsIndexToSum2Counter.put(index, 0);
        measureFound = true;
      }
      if (column.getSummaryFunction() != null && column.getSummaryFunction().equals("sum"))
        summaryFuncFound = true;
      index++;
    }

    // Map to store previous merge values on iteration
    HashMap<Integer, Object> previousMergeValues = new HashMap<Integer, Object>();
    for (Iterator iterator = columnsIndexToMerge.iterator(); iterator.hasNext(); ) {
      Integer columnIndex = (Integer) iterator.next();
      previousMergeValues.put(columnIndex, null);
    }

    TreeMap<Integer, Record> recordsToAddMap = new TreeMap<Integer, Record>();

    int sumCounter = 0; // add total row only if grouping has more than one member

    // iterate on each store row
    for (int i = 0; i < dataStore.getRecordsCount(); i++) {
      IRecord record = dataStore.getRecordAt(i);

      // get current values of column to merge
      HashMap<Integer, Object> currentMergeValues = new HashMap<Integer, Object>();

      // iterate on each column to merge and store values
      for (Iterator iterator = columnsIndexToMerge.iterator(); iterator.hasNext(); ) {
        Integer columnIndex = (Integer) iterator.next();
        Object value = record.getFieldAt(columnIndex).getValue();
        currentMergeValues.put(columnIndex, value);
      }

      // compare current values with previous ones
      boolean isEqual = compareValuesMaps(previousMergeValues, currentMergeValues);

      // if merging goes on update counters else add summarization line
      if (isEqual) {
        sumCounter++;
        for (Iterator iterator = columnsIndexToSum2Counter.keySet().iterator();
            iterator.hasNext(); ) {
          Integer indexMeasure = (Integer) iterator.next();
          Object value = record.getFieldAt(indexMeasure).getValue();

          // TODO treat the case this is not a number, should keep it to null
          if (value != null) {
            // get previous value

            Object result = operateWithNumbers(columnsIndexToSum2Counter.get(indexMeasure), value);

            columnsIndexToSum2Counter.put(indexMeasure, result);
          } else {
            columnsIndexToSum2Counter.put(indexMeasure, null);
          }
        }
      } else {
        // breaking point, add summarization lines at previous index; i-1

        // add a new record only if sumCounter > 0
        if (sumCounter > 0) {
          addTotalRecord(
              dataStore,
              i,
              columnsIndexToMerge,
              columnsIndexToEmpty,
              columnsIndexToAfter,
              columnsIndexToSum2Counter,
              previousMergeValues,
              recordsToAddMap);
        }

        // put the counters to actual values
        for (Iterator iterator = columnsIndexToSum2Counter.keySet().iterator();
            iterator.hasNext(); ) {
          Integer columnInd = (Integer) iterator.next();
          Object v = record.getFieldAt(columnInd).getValue();
          columnsIndexToSum2Counter.put(columnInd, v);
        }

        sumCounter = 0;
      }

      // update previousValues
      previousMergeValues = currentMergeValues;
    }

    // add  final total if last records were merged
    if (sumCounter > 0) {
      addTotalRecord(
          dataStore,
          null,
          columnsIndexToMerge,
          columnsIndexToEmpty,
          columnsIndexToAfter,
          columnsIndexToSum2Counter,
          previousMergeValues,
          recordsToAddMap);
    }

    // finally add the record (could not add them while cycling the store)
    for (Iterator iterator = recordsToAddMap.keySet().iterator(); iterator.hasNext(); ) {
      Integer indexR = (Integer) iterator.next();
      Record rec = recordsToAddMap.get(indexR);
      if (indexR == -1) {
        dataStore.appendRecord(rec);
      } else {
        dataStore.insertRecord(indexR, rec);
      }
    }

    logger.debug("OUT");
  }