class DataDetector implements CellDetector<IntegerRange> {

    @Override
    public ValuesWithConfidence<IntegerRange> detect(CellSampler sampler)
    {
        int expectedCellCount = getExpectedCount(sampler);

        NonEmptyPredicate nonEmptyPredicate = new NonEmptyPredicate();

        // Find first data rows
        int firstDataRow = -1;
        for (int r = 0, n = sampler.getBeginningSampleCells().size(); r < n; r++)
        {
            List<? extends String> row = sampler.getBeginningSampleCells().get(r);
            boolean isDataRow = row.size() == expectedCellCount && row.stream().anyMatch(nonEmptyPredicate);
            if (isDataRow)
            {
                firstDataRow = r;
                break;
            }
        }

        // Find last data rows
        int lastDataRow = -1;
        for (int r = sampler.getEndingSampleCells().size() - 1; r >= 0; --r)
        {
            List<? extends String> row = sampler.getEndingSampleCells().get(r);
            boolean isDataRow = row.size() == expectedCellCount && row.stream().anyMatch(nonEmptyPredicate);
            if (isDataRow)
            {
                lastDataRow = r + sampler.getEndingSampleLinesIndexOffset();
                break;
            }
        }

        float confidence = firstDataRow == -1 ? 0f : 1f;
        return new ValuesWithConfidence<IntegerRange>(new IntegerRange(firstDataRow, lastDataRow), confidence);
    }

}