//! This module contains a list of primitives that implement a [`Object`] trait.\
//! They help to locate a necessary segment on a [`Table`].
//!
//! # Example
//!
//! ```
//! use tabled::{
//!     settings::{
//!         object::{Columns, Object, Rows},
//!         Alignment,
//!     },
//!     Table,
//! };
//! use testing_table::assert_table;
//!
//! let data = [
//!     [1, 2, 3, 4, 5],
//!     [10, 20, 30, 40, 50],
//!     [100, 200, 300, 400, 500],
//! ];
//!
//! let mut table = Table::new(data);
//! table.modify(Rows::first().not(Columns::first()), Alignment::right());
//!
//! assert_table!(
//!     table,
//!     "+-----+-----+-----+-----+-----+"
//!     "| 0   |   1 |   2 |   3 |   4 |"
//!     "+-----+-----+-----+-----+-----+"
//!     "| 1   | 2   | 3   | 4   | 5   |"
//!     "+-----+-----+-----+-----+-----+"
//!     "| 10  | 20  | 30  | 40  | 50  |"
//!     "+-----+-----+-----+-----+-----+"
//!     "| 100 | 200 | 300 | 400 | 500 |"
//!     "+-----+-----+-----+-----+-----+"
//! );
//! ```
//!
//! [`Table`]: crate::Table

mod cell;
mod columns;
mod frame;
mod iterator;
mod rows;
mod segment;

pub(crate) mod util;

use std::{collections::HashSet, marker::PhantomData};

use self::segment::SectorCellsIter;

use crate::{
    grid::config::{Entity, EntityIterator},
    grid::records::{ExactRecords, Records},
};

pub use cell::{Cell, EntityOnce};
pub use columns::{Column, Columns, ColumnsIter, FirstColumn, LastColumn, LastColumnOffset};
pub use frame::{Frame, FrameIter};
pub use iterator::{
    FilterObject, FilterObjectIter, ObjectIterator, SkipObject, SkipObjectIter, StepByObject,
    StepByObjectIter,
};
use papergrid::config::Position;
pub use rows::{FirstRow, LastRow, LastRowOffset, Row, Rows, RowsIter};
pub use segment::{SectorIter, Segment, SegmentAll};

/// Object helps to locate a necessary part of a [`Table`].
///
/// [`Table`]: crate::Table
pub trait Object<R> {
    /// An [`Iterator`] which returns a list of cells.
    type Iter: Iterator<Item = Entity>;

    /// Cells returns a set of coordinates of cells.
    fn cells(&self, records: &R) -> Self::Iter;

    /// Combines cells.
    /// It doesn't repeat cells.
    fn and<O>(self, rhs: O) -> UnionCombination<Self, O, R>
    where
        Self: Sized,
    {
        UnionCombination::new(self, rhs)
    }

    /// Excludes rhs cells from this cells.
    fn not<O>(self, rhs: O) -> DiffCombination<Self, O, R>
    where
        Self: Sized,
    {
        DiffCombination::new(self, rhs)
    }

    /// Returns cells which are present in both [`Object`]s only.
    fn intersect<O>(self, rhs: O) -> IntersectionCombination<Self, O, R>
    where
        Self: Sized,
    {
        IntersectionCombination::new(self, rhs)
    }

    /// Returns cells which are not present in target [`Object`].
    fn inverse(self) -> InversionCombination<Self, R>
    where
        Self: Sized,
    {
        InversionCombination::new(self)
    }
}

/// Combination struct used for chaining [`Object`]'s.
///
/// Combines 2 sets of cells into one.
///
/// Duplicates are removed from the output set.
#[derive(Debug)]
pub struct UnionCombination<L, R, I> {
    lhs: L,
    rhs: R,
    _records: PhantomData<I>,
}

impl<L, R, I> UnionCombination<L, R, I> {
    fn new(lhs: L, rhs: R) -> Self {
        Self {
            lhs,
            rhs,
            _records: PhantomData,
        }
    }
}

impl<I, L, R> Object<I> for UnionCombination<L, R, I>
where
    L: Object<I>,
    R: Object<I>,
    I: Records + ExactRecords,
{
    type Iter = UnionIter<L::Iter, R::Iter>;

    fn cells(&self, records: &I) -> Self::Iter {
        let lhs = self.lhs.cells(records);
        let rhs = self.rhs.cells(records);

        UnionIter::new(lhs, rhs, records.count_rows(), records.count_columns())
    }
}

/// Difference struct used for chaining [`Object`]'s.
///
/// Returns cells from 1st set with removed ones from the 2nd set.
#[derive(Debug)]
pub struct DiffCombination<L, R, I> {
    lhs: L,
    rhs: R,
    _records: PhantomData<I>,
}

impl<L, R, I> DiffCombination<L, R, I> {
    fn new(lhs: L, rhs: R) -> Self {
        Self {
            lhs,
            rhs,
            _records: PhantomData,
        }
    }
}

impl<I, L, R> Object<I> for DiffCombination<L, R, I>
where
    L: Object<I>,
    R: Object<I>,
    I: Records + ExactRecords,
{
    type Iter = DiffIter<L::Iter>;

    fn cells(&self, records: &I) -> Self::Iter {
        let lhs = self.lhs.cells(records);
        let rhs = self.rhs.cells(records);

        DiffIter::new(lhs, rhs, records.count_rows(), records.count_columns())
    }
}

/// Intersection struct used for chaining [`Object`]'s.
///
/// Returns cells which are present in 2 sets.
/// But not in one of them
#[derive(Debug)]
pub struct IntersectionCombination<L, R, I> {
    lhs: L,
    rhs: R,
    _records: PhantomData<I>,
}

impl<L, R, I> IntersectionCombination<L, R, I> {
    fn new(lhs: L, rhs: R) -> Self {
        Self {
            lhs,
            rhs,
            _records: PhantomData,
        }
    }
}

impl<I, L, R> Object<I> for IntersectionCombination<L, R, I>
where
    L: Object<I>,
    R: Object<I>,
    I: Records + ExactRecords,
{
    type Iter = IntersectIter<L::Iter>;

    fn cells(&self, records: &I) -> Self::Iter {
        let lhs = self.lhs.cells(records);
        let rhs = self.rhs.cells(records);

        IntersectIter::new(lhs, rhs, records.count_rows(), records.count_columns())
    }
}

/// Inversion struct used for chaining [`Object`]'s.
///
/// Returns cells which are present in 2 sets.
/// But not in one of them
#[derive(Debug)]
pub struct InversionCombination<O, I> {
    obj: O,
    _records: PhantomData<I>,
}

impl<O, I> InversionCombination<O, I> {
    fn new(obj: O) -> Self {
        Self {
            obj,
            _records: PhantomData,
        }
    }
}

impl<I, O> Object<I> for InversionCombination<O, I>
where
    O: Object<I>,
    I: Records + ExactRecords,
{
    type Iter = InversionIter;

    fn cells(&self, records: &I) -> Self::Iter {
        let obj = self.obj.cells(records);

        InversionIter::new(obj, records.count_rows(), records.count_columns())
    }
}

/// An [`Iterator`] which goes over a combination [`Object::Iter`].
#[derive(Debug)]
pub struct UnionIter<L, R> {
    lhs: Option<L>,
    rhs: R,
    seen: HashSet<Position>,
    current: Option<EntityIterator>,
    count_rows: usize,
    count_cols: usize,
}

impl<L, R> UnionIter<L, R>
where
    L: Iterator<Item = Entity>,
    R: Iterator<Item = Entity>,
{
    fn new(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self {
        let size = match lhs.size_hint() {
            (s1, Some(s2)) if s1 == s2 => s1,
            _ => 0,
        };

        Self {
            lhs: Some(lhs),
            rhs,
            seen: HashSet::with_capacity(size),
            current: None,
            count_rows,
            count_cols,
        }
    }
}

impl<L, R> Iterator for UnionIter<L, R>
where
    L: Iterator<Item = Entity>,
    R: Iterator<Item = Entity>,
{
    type Item = Entity;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(iter) = self.current.as_mut() {
            for p in iter.by_ref() {
                if self.lhs.is_none() && self.seen.contains(&p) {
                    continue;
                }

                let _ = self.seen.insert(p);

                return Some(p.into());
            }
        }

        if let Some(lhs) = self.lhs.as_mut() {
            for entity in lhs.by_ref() {
                let mut iter = entity.iter(self.count_rows, self.count_cols);
                if let Some(p) = iter.by_ref().next() {
                    let _ = self.seen.insert(p);
                    self.current = Some(iter);

                    return Some(p.into());
                }
            }

            self.lhs = None;
        }

        for entity in self.rhs.by_ref() {
            let mut iter = entity.iter(self.count_rows, self.count_cols);

            for p in iter.by_ref() {
                if !self.seen.contains(&p) {
                    let _ = self.seen.insert(p);
                    self.current = Some(iter);

                    return Some(p.into());
                }
            }
        }

        None
    }
}

/// An [`Iterator`] which goes over only cells which are present in first [`Object::Iter`] but not second.
#[derive(Debug)]
pub struct DiffIter<L> {
    lhs: L,
    seen: HashSet<Position>,
    count_rows: usize,
    count_cols: usize,
    current: Option<EntityIterator>,
}

impl<L> DiffIter<L>
where
    L: Iterator<Item = Entity>,
{
    fn new<R>(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self
    where
        R: Iterator<Item = Entity>,
    {
        let size = match rhs.size_hint() {
            (s1, Some(s2)) if s1 == s2 => s1,
            _ => 0,
        };

        let mut seen = HashSet::with_capacity(size);
        for entity in rhs {
            seen.extend(entity.iter(count_rows, count_cols));
        }

        Self {
            lhs,
            seen,
            count_rows,
            count_cols,
            current: None,
        }
    }
}

impl<L> Iterator for DiffIter<L>
where
    L: Iterator<Item = Entity>,
{
    type Item = Entity;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(iter) = self.current.as_mut() {
            for p in iter.by_ref() {
                if !self.seen.contains(&p) {
                    return Some(p.into());
                }
            }
        }

        for entity in self.lhs.by_ref() {
            let mut iter = entity.iter(self.count_rows, self.count_cols);

            for p in iter.by_ref() {
                if !self.seen.contains(&p) {
                    self.current = Some(iter);
                    return Some(p.into());
                }
            }
        }

        None
    }
}

/// An [`Iterator`] which goes goes over cells which are present in both [`Object::Iter`]ators.
#[derive(Debug)]
pub struct IntersectIter<L> {
    lhs: L,
    seen: HashSet<Position>,
    count_rows: usize,
    count_cols: usize,
    current: Option<EntityIterator>,
}

impl<L> IntersectIter<L>
where
    L: Iterator<Item = Entity>,
{
    fn new<R>(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self
    where
        R: Iterator<Item = Entity>,
    {
        let size = match rhs.size_hint() {
            (s1, Some(s2)) if s1 == s2 => s1,
            _ => 0,
        };

        let mut seen = HashSet::with_capacity(size);
        for entity in rhs {
            seen.extend(entity.iter(count_rows, count_cols));
        }

        Self {
            lhs,
            seen,
            count_rows,
            count_cols,
            current: None,
        }
    }
}

impl<L> Iterator for IntersectIter<L>
where
    L: Iterator<Item = Entity>,
{
    type Item = Entity;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(iter) = self.current.as_mut() {
            for p in iter.by_ref() {
                if self.seen.contains(&p) {
                    return Some(p.into());
                }
            }
        }

        for entity in self.lhs.by_ref() {
            let mut iter = entity.iter(self.count_rows, self.count_cols);

            for p in iter.by_ref() {
                if self.seen.contains(&p) {
                    self.current = Some(iter);
                    return Some(p.into());
                }
            }
        }

        None
    }
}

/// An [`Iterator`] which goes goes over cells which are not present an [`Object::Iter`]ator.
#[derive(Debug)]
pub struct InversionIter {
    all: SectorCellsIter,
    seen: HashSet<Position>,
}

impl InversionIter {
    fn new<O>(obj: O, count_rows: usize, count_columns: usize) -> Self
    where
        O: Iterator<Item = Entity>,
    {
        let size = match obj.size_hint() {
            (s1, Some(s2)) if s1 == s2 => s1,
            _ => 0,
        };

        let mut seen = HashSet::with_capacity(size);
        for entity in obj {
            seen.extend(entity.iter(count_rows, count_columns));
        }

        let all = SectorCellsIter::new(0, count_rows, 0, count_columns);

        Self { all, seen }
    }
}

impl Iterator for InversionIter {
    type Item = Entity;

    fn next(&mut self) -> Option<Self::Item> {
        for p in self.all.by_ref() {
            if !self.seen.contains(&p) {
                return Some(p.into());
            }
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use crate::grid::records::vec_records::VecRecords;

    use super::*;

    #[test]
    fn cell_test() {
        assert_eq!(vec_cells((0, 0), 2, 3), [Entity::Cell(0, 0)]);
        assert_eq!(vec_cells((1, 1), 2, 3), [Entity::Cell(1, 1)]);
        assert_eq!(vec_cells((1, 1), 0, 0), [Entity::Cell(1, 1)]);
        assert_eq!(vec_cells((1, 100), 2, 3), [Entity::Cell(1, 100)]);
        assert_eq!(vec_cells((100, 1), 2, 3), [Entity::Cell(100, 1)]);
    }

    #[test]
    fn columns_test() {
        assert_eq!(
            vec_cells(Columns::new(..), 2, 3),
            [Entity::Column(0), Entity::Column(1), Entity::Column(2)]
        );
        assert_eq!(
            vec_cells(Columns::new(1..), 2, 3),
            [Entity::Column(1), Entity::Column(2)]
        );
        assert_eq!(vec_cells(Columns::new(2..), 2, 3), [Entity::Column(2)]);
        assert_eq!(vec_cells(Columns::new(3..), 2, 3), []);
        assert_eq!(vec_cells(Columns::new(3..), 0, 0), []);
        assert_eq!(vec_cells(Columns::new(0..1), 2, 3), [Entity::Column(0)]);
        assert_eq!(vec_cells(Columns::new(1..2), 2, 3), [Entity::Column(1)]);
        assert_eq!(vec_cells(Columns::new(2..3), 2, 3), [Entity::Column(2)]);
        assert_eq!(vec_cells(Columns::new(..), 0, 0), []);
        assert_eq!(vec_cells(Columns::new(..), 2, 0), []);
        assert_eq!(vec_cells(Columns::new(..), 0, 3), []);
    }

    #[test]
    fn first_column_test() {
        assert_eq!(vec_cells(Columns::first(), 5, 2), [Entity::Column(0)]);
        assert_eq!(vec_cells(Columns::first(), 0, 0), []);
        assert_eq!(vec_cells(Columns::first(), 10, 0), []);
        assert_eq!(vec_cells(Columns::first(), 0, 10), []);
    }

    #[test]
    fn last_column_test() {
        assert_eq!(vec_cells(Columns::last(), 5, 2), [Entity::Column(1)]);
        assert_eq!(vec_cells(Columns::last(), 5, 29), [Entity::Column(28)]);
        assert_eq!(vec_cells(Columns::last(), 0, 0), []);
        assert_eq!(vec_cells(Columns::last(), 10, 0), []);
        assert_eq!(vec_cells(Columns::last(), 0, 10), []);
    }

    #[test]
    fn last_column_sub_test() {
        assert_eq!(vec_cells(Columns::last(), 5, 2), [Entity::Column(1)]);
        assert_eq!(vec_cells(Columns::last() - 0, 5, 2), [Entity::Column(1)]);
        assert_eq!(vec_cells(Columns::last() - 1, 5, 2), [Entity::Column(0)]);
        assert_eq!(vec_cells(Columns::last() - 2, 5, 2), []);
        assert_eq!(vec_cells(Columns::last() - 100, 5, 2), []);
    }

    #[test]
    fn first_column_add_test() {
        assert_eq!(vec_cells(Columns::first(), 5, 2), [Entity::Column(0)]);
        assert_eq!(vec_cells(Columns::first() + 0, 5, 2), [Entity::Column(0)]);
        assert_eq!(vec_cells(Columns::first() + 1, 5, 2), [Entity::Column(1)]);
        assert_eq!(vec_cells(Columns::first() + 2, 5, 2), [Entity::Column(2)]);
        assert_eq!(
            vec_cells(Columns::first() + 100, 5, 2),
            [Entity::Column(100)]
        );
    }

    #[test]
    fn rows_test() {
        assert_eq!(
            vec_cells(Rows::new(..), 2, 3),
            [Entity::Row(0), Entity::Row(1)]
        );
        assert_eq!(vec_cells(Rows::new(1..), 2, 3), [Entity::Row(1)]);
        assert_eq!(vec_cells(Rows::new(2..), 2, 3), []);
        assert_eq!(vec_cells(Rows::new(2..), 0, 0), []);
        assert_eq!(vec_cells(Rows::new(0..1), 2, 3), [Entity::Row(0)],);
        assert_eq!(vec_cells(Rows::new(1..2), 2, 3), [Entity::Row(1)],);
        assert_eq!(vec_cells(Rows::new(..), 0, 0), []);
        assert_eq!(vec_cells(Rows::new(..), 0, 3), []);
        assert_eq!(
            vec_cells(Rows::new(..), 2, 0),
            [Entity::Row(0), Entity::Row(1)]
        );
    }

    #[test]
    fn last_row_test() {
        assert_eq!(vec_cells(Rows::last(), 5, 2), [Entity::Row(4)]);
        assert_eq!(vec_cells(Rows::last(), 100, 2), [Entity::Row(99)]);
        assert_eq!(vec_cells(Rows::last(), 0, 0), []);
        assert_eq!(vec_cells(Rows::last(), 5, 0), []);
        assert_eq!(vec_cells(Rows::last(), 0, 2), []);
    }

    #[test]
    fn first_row_test() {
        assert_eq!(vec_cells(Rows::first(), 5, 2), [Entity::Row(0)]);
        assert_eq!(vec_cells(Rows::first(), 100, 2), [Entity::Row(0)]);
        assert_eq!(vec_cells(Rows::first(), 0, 0), []);
        assert_eq!(vec_cells(Rows::first(), 5, 0), []);
        assert_eq!(vec_cells(Rows::first(), 0, 2), []);
    }

    #[test]
    fn last_row_sub_test() {
        assert_eq!(vec_cells(Rows::last(), 5, 2), [Entity::Row(4)]);
        assert_eq!(vec_cells(Rows::last() - 0, 5, 2), [Entity::Row(4)]);
        assert_eq!(vec_cells(Rows::last() - 1, 5, 2), [Entity::Row(3)]);
        assert_eq!(vec_cells(Rows::last() - 2, 5, 2), [Entity::Row(2)]);
        assert_eq!(vec_cells(Rows::last() - 3, 5, 2), [Entity::Row(1)]);
        assert_eq!(vec_cells(Rows::last() - 4, 5, 2), [Entity::Row(0)]);
        assert_eq!(vec_cells(Rows::last() - 5, 5, 2), []);
        assert_eq!(vec_cells(Rows::last() - 100, 5, 2), []);
        assert_eq!(vec_cells(Rows::last() - 1, 0, 0), []);
        assert_eq!(vec_cells(Rows::last() - 1, 5, 0), []);
        assert_eq!(vec_cells(Rows::last() - 1, 0, 2), []);
    }

    #[test]
    fn first_row_add_test() {
        assert_eq!(vec_cells(Rows::first(), 5, 2), [Entity::Row(0)]);
        assert_eq!(vec_cells(Rows::first() + 0, 5, 2), [Entity::Row(0)]);
        assert_eq!(vec_cells(Rows::first() + 1, 5, 2), [Entity::Row(1)]);
        assert_eq!(vec_cells(Rows::first() + 2, 5, 2), [Entity::Row(2)]);
        assert_eq!(vec_cells(Rows::first() + 3, 5, 2), [Entity::Row(3)]);
        assert_eq!(vec_cells(Rows::first() + 4, 5, 2), [Entity::Row(4)]);
        assert_eq!(vec_cells(Rows::first() + 5, 5, 2), [Entity::Row(5)]);
        assert_eq!(vec_cells(Rows::first() + 100, 5, 2), [Entity::Row(100)]);
        assert_eq!(vec_cells(Rows::first() + 1, 0, 0), [Entity::Row(1)]);
        assert_eq!(vec_cells(Rows::first() + 1, 5, 0), [Entity::Row(1)]);
        assert_eq!(vec_cells(Rows::first() + 1, 0, 2), [Entity::Row(1)]);
    }

    #[test]
    fn frame_test() {
        assert_eq!(
            vec_cells(Frame, 2, 3),
            [
                Entity::Cell(0, 0),
                Entity::Cell(0, 1),
                Entity::Cell(0, 2),
                Entity::Cell(1, 0),
                Entity::Cell(1, 1),
                Entity::Cell(1, 2)
            ]
        );
        assert_eq!(vec_cells(Frame, 0, 0), []);
        assert_eq!(vec_cells(Frame, 2, 0), []);
        assert_eq!(vec_cells(Frame, 0, 2), []);
    }

    #[test]
    fn segment_test() {
        assert_eq!(
            vec_cells(Segment::new(.., ..), 2, 3),
            [
                Entity::Cell(0, 0),
                Entity::Cell(0, 1),
                Entity::Cell(0, 2),
                Entity::Cell(1, 0),
                Entity::Cell(1, 1),
                Entity::Cell(1, 2)
            ]
        );
        assert_eq!(
            vec_cells(Segment::new(1.., ..), 2, 3),
            [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)]
        );
        assert_eq!(vec_cells(Segment::new(2.., ..), 2, 3), []);

        assert_eq!(
            vec_cells(Segment::new(.., 1..), 2, 3),
            [
                Entity::Cell(0, 1),
                Entity::Cell(0, 2),
                Entity::Cell(1, 1),
                Entity::Cell(1, 2)
            ]
        );
        assert_eq!(
            vec_cells(Segment::new(.., 2..), 2, 3),
            [Entity::Cell(0, 2), Entity::Cell(1, 2)]
        );
        assert_eq!(vec_cells(Segment::new(.., 3..), 2, 3), []);

        assert_eq!(
            vec_cells(Segment::new(1.., 1..), 2, 3),
            [Entity::Cell(1, 1), Entity::Cell(1, 2)]
        );
        assert_eq!(
            vec_cells(Segment::new(1..2, 1..2), 2, 3),
            [Entity::Cell(1, 1)]
        );

        assert_eq!(vec_cells(Segment::new(5.., 5..), 2, 3), []);
    }

    #[test]
    fn object_and_test() {
        assert_eq!(
            vec_cells(Cell::new(0, 0).and(Cell::new(0, 0)), 2, 3),
            [Entity::Cell(0, 0)]
        );
        assert_eq!(
            vec_cells(Cell::new(0, 0).and(Cell::new(1, 2)), 2, 3),
            [Entity::Cell(0, 0), Entity::Cell(1, 2)]
        );
        assert_eq!(vec_cells(Cell::new(0, 0).and(Cell::new(1, 2)), 0, 0), []);
    }

    #[test]
    fn object_not_test() {
        assert_eq!(vec_cells(Rows::first().not(Cell::new(0, 0)), 0, 0), []);
        assert_eq!(vec_cells(Cell::new(0, 0).not(Cell::new(0, 0)), 2, 3), []);
        assert_eq!(
            vec_cells(Rows::first().not(Cell::new(0, 0)), 2, 3),
            [Entity::Cell(0, 1), Entity::Cell(0, 2)]
        );
        assert_eq!(
            vec_cells(Columns::single(1).not(Rows::single(1)), 3, 3),
            [Entity::Cell(0, 1), Entity::Cell(2, 1)]
        );
        assert_eq!(
            vec_cells(Rows::single(1).not(Columns::single(1)), 3, 3),
            [Entity::Cell(1, 0), Entity::Cell(1, 2)]
        );
    }

    #[test]
    fn object_intersect_test() {
        assert_eq!(
            vec_cells(Rows::first().intersect(Cell::new(0, 0)), 0, 0),
            []
        );
        assert_eq!(
            vec_cells(Segment::all().intersect(Rows::single(1)), 2, 3),
            [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)]
        );
        assert_eq!(
            vec_cells(Cell::new(0, 0).intersect(Cell::new(0, 0)), 2, 3),
            [Entity::Cell(0, 0)]
        );
        assert_eq!(
            vec_cells(Rows::first().intersect(Cell::new(0, 0)), 2, 3),
            [Entity::Cell(0, 0)]
        );
        // maybe we somehow shall not limit the rows/columns by the max count?
        assert_eq!(
            vec_cells(Rows::single(1).intersect(Columns::single(1)), 2, 1),
            []
        );
    }

    #[test]
    fn object_inverse_test() {
        assert_eq!(vec_cells(Segment::all().inverse(), 2, 3), []);
        assert_eq!(
            vec_cells(Cell::new(0, 0).inverse(), 2, 3),
            [
                Entity::Cell(0, 1),
                Entity::Cell(0, 2),
                Entity::Cell(1, 0),
                Entity::Cell(1, 1),
                Entity::Cell(1, 2)
            ]
        );
        assert_eq!(
            vec_cells(Rows::first().inverse(), 2, 3),
            [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)]
        );
        assert_eq!(vec_cells(Rows::first().inverse(), 0, 0), []);
    }

    fn vec_cells<O: Object<VecRecords<String>>>(
        o: O,
        count_rows: usize,
        count_cols: usize,
    ) -> Vec<Entity> {
        let data = vec![vec![String::default(); count_cols]; count_rows];
        let records = VecRecords::new(data);
        o.cells(&records).collect::<Vec<_>>()
    }
}
