//
        // Population
        //

        protected bool CheckMatcherCells(
            IImportTableProvider table,
            ImportCellMatchContextBase context,
            int rowofs,
            List <ImportCellMatcherBase> matcher,
            int matcherRows)
        {
            // access
            if (table == null || matcher == null || matcherRows < 1)
            {
                return(false);
            }

            // over rows?
            if (rowofs + matcherRows > table.MaxRows)
            {
                return(false);
            }

            for (int r = 0; r < matcherRows; r++)
            {
                for (int c = 0; c < _job.Cols; c++)
                {
                    var cell = table.Cell(r + rowofs, c);
                    if (cell == null)
                    {
                        cell = "";
                    }

                    var mi  = (1 + r) * (1 + _job.Cols) + 1 + c;
                    var mat = (mi >= matcher.Count) ? null : matcher[mi];
                    if (mat == null)
                    {
                        _log?.Info($"    invalid matcher at top ({1 + r}, {1 + c})");
                        return(false);
                    }
                    if (!mat.Matches(context, cell))
                    {
                        _log?.Info("{0}", $"    matcher was false ({1 + r}, {1 + c}) " +
                                   $"preset='{mat.Preset}' cell='{cell}'");
                        return(false);
                    }
                }
            }

            // ok
            return(true);
        }
        protected bool CheckRowIsEmpty(IImportTableProvider table, int rowofs)
        {
            // access
            if (table == null || rowofs >= table.MaxRows)
            {
                return(true);
            }

            // check
            var isEmpty = true;

            for (int c = 0; c < _job.Cols; c++)
            {
                if (table.Cell(rowofs, c).HasContent())
                {
                    isEmpty = false;
                }
            }
            return(isEmpty);
        }
        public void PopulateBy(IImportTableProvider table)
        {
            // access
            if (!IsValid || table == null || table.MaxRows < 1 || table.MaxCols < 1 ||
                _matcherTop == null || _matcherBody == null)
            {
                return;
            }

            _log?.Info("Starting populating from NEW TABLE");

            // use 2 contexts to collect information during the matching
            var contextTop  = new ImportCellMatchContextBase();
            var contextBody = new ImportCellMatchContextBase();

            // simply scan over potential tops and bodies
            int rowofs          = 0;
            int conseqEmptyRows = 0;

            while (rowofs + _job.RowsTop + _job.RealRowsBody <= table.MaxRows)
            {
                // log
                _log?.Info("{0}", $"  check row {rowofs} starting with {"" + table.Cell(rowofs, 0)} for top ..");

                // first do a evaluation, if the complete row is empty
                if (CheckRowIsEmpty(table, rowofs))
                {
                    // break the full scanning process (using absurd high limit)?
                    conseqEmptyRows++;
                    if (conseqEmptyRows >= 100)
                    {
                        break;
                    }

                    // now, but still empty: take a shortcut to next row
                    rowofs++;
                    continue;
                }
                conseqEmptyRows = 0;

                // top matches?
                contextTop.Clear();
                if (CheckMatcherCells(table, contextTop, rowofs, _matcherTop, _job.RowsTop))
                {
                    // log
                    _log?.Info($"  found matching TOP!");

                    // care for the (containg) top element
                    var refTop = CreateTopReferable(contextTop, actInHierarchy: _job.ActInHierarchy);
                    if (refTop == null)
                    {
                        _log?.Info($"  error creating data for TOP! Skipping!");
                        rowofs++;
                        continue;
                    }

                    // try find elements
                    var rowofs2     = rowofs + _job.RowsTop;
                    var lastGoodRow = rowofs;

                    while (rowofs2 < table.MaxRows)
                    {
                        // log
                        _log?.Info("{0}", $"  check row {rowofs2} starting with " +
                                   $"{"" + table.Cell(rowofs2, 0)} for body ..");

                        // be definition, a completely empty line will break the matching
                        if (CheckRowIsEmpty(table, rowofs2))
                        {
                            break;
                        }

                        // matches
                        contextBody.Clear();
                        if (CheckMatcherCells(table, contextBody, rowofs2, _matcherBody, _job.RowsBody))
                        {
                            // log again
                            _log?.Info($"    found matching BODY as well!");

                            // remember to never visit again
                            lastGoodRow = rowofs2;

                            // an CD with empty identification will cause a new id, therefore
                            // the SME.semanticId will be altered accordingly and will be
                            // written later
                            var cdBody = CreateBodyCD(contextBody, _env);
                            if (cdBody == null)
                            {
                                _log?.Info($"  error creating ConceptDescription for BODY! Skipping!");
                                rowofs2 += _job.RowsBody;
                                continue;
                            }

                            // create SME
                            var refBody = CreateBodySme(contextBody, refTop);
                            if (refBody == null)
                            {
                                _log?.Info($"  error creating SubmodelElement for BODY! Skipping!");
                                rowofs2 += _job.RowsBody;
                                continue;
                            }
                        }

                        // find next row?
                        rowofs2 += _job.RowsBody;
                    }

                    // advance at least to last good row + 1
                    rowofs = lastGoodRow + 1;
                }

                // default
                rowofs++;
            }
        }