logisheets_controller 0.7.0

the core of LogiSheets
Documentation
use crate::lock::locked_write;
use im::HashMap;
use logisheets_base::{
    errors::BasicError, BlockCellId, BlockId, CellId, ColId, NormalCellId, RowId, SheetId,
};

pub use self::{block::BlockPlace, sheet_nav::SheetNav};

mod block;
pub mod ctx;
mod executor;
mod fetcher;
mod id_manager;
mod sheet_nav;
pub use executor::NavExecutor;

#[derive(Debug, Clone, Default)]
pub struct Navigator {
    pub sheet_navs: HashMap<SheetId, SheetNav>,
}

impl Navigator {
    pub fn fetch_row_id(&self, sheet_id: &SheetId, row: usize) -> Result<RowId, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        let row_id = fetcher.get_row_id(row);
        Ok(row_id)
    }

    pub fn fetch_row_idx(&self, sheet_id: &SheetId, row: &RowId) -> Result<usize, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_row_idx(*row)
    }

    pub fn fetch_col_id(&self, sheet_id: &SheetId, col: usize) -> Result<ColId, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        let col_id = fetcher.get_col_id(col.clone());
        Ok(col_id)
    }

    pub fn fetch_col_idx(&self, sheet_id: &SheetId, col: &ColId) -> Result<usize, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_col_idx(*col)
    }

    pub fn fetch_cell_id(
        &self,
        sheet_id: &SheetId,
        row: usize,
        col: usize,
    ) -> Result<CellId, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_cell_id(row, col)
    }

    pub fn fetch_block_cell_id(
        &self,
        sheet_id: &SheetId,
        block_id: &BlockId,
        row: usize,
        col: usize,
    ) -> Result<BlockCellId, BasicError> {
        let bp = self.get_block_place(sheet_id, block_id)?;
        if let Some((rid, cid)) = bp.get_inner_id(row, col) {
            Ok(BlockCellId {
                block_id: block_id.clone(),
                row: rid,
                col: cid,
            })
        } else {
            Err(BasicError::BlockCellIdNotFound(
                *sheet_id, *block_id, row, col,
            ))
        }
    }

    pub fn fetch_norm_cell_id(
        &self,
        sheet_id: &SheetId,
        row: usize,
        col: usize,
    ) -> Result<NormalCellId, BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        Ok(fetcher.get_norm_cell_id(row, col))
    }

    pub fn fetch_cell_idx(
        &self,
        sheet_id: &SheetId,
        cell_id: &CellId,
    ) -> Result<(usize, usize), BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_cell_idx(&cell_id)
    }

    pub fn fetch_normal_cell_idx(
        &self,
        sheet_id: &SheetId,
        cell_id: &NormalCellId,
    ) -> Result<(usize, usize), BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_norm_cell_idx(cell_id)
    }

    pub fn fetch_block_cell_idx(
        &self,
        sheet_id: &SheetId,
        cell_id: &BlockCellId,
    ) -> Result<(usize, usize), BasicError> {
        let fetcher = self.get_sheet_nav(sheet_id)?.get_fetcher();
        fetcher.get_block_cell_idx(cell_id)
    }

    pub fn create_block(
        &mut self,
        sheet_id: &SheetId,
        master: NormalCellId,
        row_cnt: usize,
        col_cnt: usize,
    ) {
        let sheet_nav = self.get_sheet_nav_mut(sheet_id);
        let block_place = BlockPlace::new(master, row_cnt as u32, col_cnt as u32);
        let block_id = sheet_nav.id_manager.get_block_id();
        sheet_nav.data.blocks.insert(block_id, block_place);
        sheet_nav.cache = Default::default();
    }

    pub fn remove_block(&mut self, sheet_id: &SheetId, block_id: &BlockId) {
        let sheet_nav = self.get_sheet_nav_mut(sheet_id);
        sheet_nav.data.blocks.remove(&block_id);
        sheet_nav.cache = Default::default();
    }

    pub fn move_block(
        &mut self,
        sheet_id: &SheetId,
        block_id: &BlockId,
        row_idx: usize,
        col_idx: usize,
    ) {
        if let Ok((row_cnt, col_cnt)) = self.get_block_size(sheet_id, block_id) {
            if !self.any_other_blocks_in(
                *sheet_id,
                *block_id,
                row_idx,
                col_idx,
                row_idx + row_cnt - 1,
                col_idx + col_cnt - 1,
            ) {
                let new_master = self
                    .fetch_norm_cell_id(&sheet_id, row_idx, col_idx)
                    .unwrap();
                let sheet_nav = self.get_sheet_nav_mut(sheet_id);
                if let Some(bp) = sheet_nav.data.blocks.get_mut(&block_id) {
                    bp.master = new_master;
                    sheet_nav.cache = Default::default();
                }
            }
        }
    }

    pub fn delete_sheet(&mut self, sheet_id: &SheetId) {
        self.sheet_navs.remove(&sheet_id);
    }

    pub fn create_sheet(&mut self, sheet_id: SheetId) {
        self.sheet_navs.insert(sheet_id, SheetNav::default());
    }

    pub fn get_affected_blockplace(
        &self,
        sheet_id: &SheetId,
        line_idx: usize,
        cnt: usize,
        is_row: bool,
    ) -> Result<Vec<BlockId>, BasicError> {
        let sheet_nav = self
            .sheet_navs
            .get(&sheet_id)
            .ok_or(BasicError::SheetIdNotFound(*sheet_id))?;
        let mut result: Vec<BlockId> = vec![];
        sheet_nav.data.blocks.iter().for_each(|(b_id, bp)| {
            let master = &bp.master;
            let master_idx = self.fetch_normal_cell_idx(sheet_id, &master);
            if let Ok((m_row, m_col)) = master_idx {
                let (row_cnt, col_cnt) = bp.get_block_size();
                if is_row && intersect(m_row, m_row + row_cnt - 1, line_idx, line_idx + cnt - 1) {
                    result.push(b_id.clone())
                } else if !is_row
                    && intersect(m_col, m_col + col_cnt - 1, line_idx, line_idx + cnt - 1)
                {
                    result.push(b_id.clone())
                }
            }
        });
        Ok(result)
    }

    #[inline]
    pub fn get_block_place(
        &self,
        sheet_id: &SheetId,
        block_id: &BlockId,
    ) -> Result<&BlockPlace, BasicError> {
        let sheet_nav = self
            .sheet_navs
            .get(sheet_id)
            .ok_or(BasicError::SheetIdNotFound(*sheet_id))?;
        let block_place = sheet_nav
            .data
            .blocks
            .get(block_id)
            .ok_or(BasicError::BlockIdNotFound(*sheet_id, *block_id))?;
        Ok(block_place)
    }

    #[inline]
    pub fn get_block_size(
        &self,
        sheet_id: &SheetId,
        block_id: &BlockId,
    ) -> Result<(usize, usize), BasicError> {
        let bp = self.get_block_place(sheet_id, block_id)?;
        Ok(bp.get_block_size())
    }

    #[inline]
    pub fn get_master_cell(
        &self,
        sheet_id: &SheetId,
        block_id: &BlockId,
    ) -> Result<NormalCellId, BasicError> {
        let bp = self.get_block_place(sheet_id, block_id)?;
        let nc = bp.master;
        Ok(nc)
    }

    pub fn add_sheet_id(&mut self, sheet_id: &SheetId) {
        self.get_sheet_nav_mut(sheet_id);
    }

    fn get_sheet_nav_mut(&mut self, sheet_id: &SheetId) -> &mut SheetNav {
        if let Some(_) = self.sheet_navs.get(&sheet_id) {
            self.sheet_navs.get_mut(&sheet_id).unwrap()
        } else {
            self.sheet_navs
                .insert(sheet_id.clone(), SheetNav::default());
            self.sheet_navs.get_mut(&sheet_id).unwrap()
        }
    }

    fn get_sheet_nav(&self, sheet_id: &SheetId) -> Result<&SheetNav, BasicError> {
        self.sheet_navs
            .get(sheet_id)
            .ok_or(BasicError::SheetIdNotFound(*sheet_id))
    }

    pub fn add_block_place(self, sheet_id: SheetId, block_id: BlockId, bp: BlockPlace) -> Self {
        let mut res = self;
        let sheet_nav = res.sheet_navs.get_mut(&sheet_id);
        match sheet_nav {
            Some(sn) => {
                sn.data.blocks.insert(block_id, bp);
                let mut cache = locked_write(&sn.cache);
                cache.clean_cell();
                drop(cache);
                res
            }
            None => res,
        }
    }

    pub fn clean_cache(&mut self, sheet_id: SheetId) {
        if let Some(sn) = self.sheet_navs.get_mut(&sheet_id) {
            sn.cache = Default::default();
        }
    }

    pub fn any_other_blocks_in(
        &self,
        sheet_id: SheetId,
        block_id: BlockId,
        start_row: usize,
        end_row: usize,
        start_col: usize,
        end_col: usize,
    ) -> bool {
        for i in start_row..=start_col {
            for j in end_row..=end_col {
                let cell_id = self.fetch_cell_id(&sheet_id, i, j).unwrap();
                if let CellId::BlockCell(b) = cell_id {
                    if b.block_id != block_id {
                        return true;
                    }
                }
            }
        }
        false
    }
}

fn intersect(start1: usize, end1: usize, start2: usize, end2: usize) -> bool {
    if start1 > end2 || start2 > end1 {
        false
    } else {
        true
    }
}