logisheets_controller 0.7.0

the core of LogiSheets
Documentation
use std::collections::HashSet;

use logisheets_base::{CellId, CellValue, SheetId};
use logisheets_workbook::prelude::*;

use crate::{
    cell::Cell,
    cell_attachments::{comment::Comment, CellAttachmentsManager},
    connectors::FormulaConnector,
    container::{col_info_manager::ColInfo, row_info_manager::RowInfo, DataContainer},
    cube_manager::CubeManager,
    ext_book_manager::ExtBooksManager,
    ext_ref_manager::ExtRefManager,
    formula_manager::FormulaManager,
    id_manager::{FuncIdManager, NameIdManager, SheetIdManager, TextIdManager},
    navigator::Navigator,
    range_manager::RangeManager,
    settings::Settings,
    workbook::sheet_pos_manager::SheetPosManager,
};

use super::{
    styles::StyleLoader,
    utils::{parse_cell, parse_range},
    vertex::{load_normal_formula, load_shared_formulas},
};

pub fn load_cols(
    sheet_id: SheetId,
    cols: &Vec<CtCol>,
    container: &mut DataContainer,
    style_loader: &mut StyleLoader,
    navigator: &mut Navigator,
) {
    cols.iter().for_each(|col| {
        let min = col.min - 1;
        let max = col.max - 1;
        let col_style_id = if col.style > 0 {
            style_loader.load_xf(col.style)
        } else {
            0
        };
        (min..max + 1).into_iter().for_each(|col_idx| {
            let col_id = navigator
                .fetch_col_id(&sheet_id, col_idx as usize)
                .unwrap_or(0);
            let col_info = ColInfo {
                best_fit: col.best_fit,
                collapsed: col.collapsed,
                custom_width: col.custom_width,
                hidden: col.hidden,
                outline_level: col.outline_level as u8,
                style: col_style_id,
                width: col.width,
            };
            container.set_col_info(sheet_id, col_id, col_info);
        });
    });
}

pub fn load_merge_cells(
    sheet_id: SheetId,
    merge_cells: &CtMergeCells,
    navigator: &mut Navigator,
    cell_attachment_manager: &mut CellAttachmentsManager,
) {
    merge_cells.merge_cells.iter().for_each(|mc| {
        let r = &mc.reference;
        if let Some(((start_row, start_col), (end_row, end_col))) = parse_range(&r) {
            let start_id = navigator.fetch_cell_id(&sheet_id, start_row, start_col);
            let end_id = navigator.fetch_cell_id(&sheet_id, end_row, end_col);
            match (start_id, end_id) {
                (Ok(start), Ok(end)) => match (start, end) {
                    (CellId::NormalCell(s), CellId::NormalCell(e)) => {
                        cell_attachment_manager
                            .merge_cells
                            .add_merge_cell(sheet_id, s, e);
                    }
                    _ => {}
                },
                _ => {}
            }
        }
    })
}

pub fn load_comments(
    sheet_id: SheetId,
    comments: &Comments,
    navigator: &mut Navigator,
    cell_attachment_manager: &mut CellAttachmentsManager,
) {
    let authors = comments
        .authors
        .authors
        .iter()
        .map(|plain_text| plain_text.value.to_string())
        .collect::<Vec<_>>();
    comments
        .comment_list
        .comments
        .iter()
        .for_each(|c| match parse_cell(&c.reference) {
            Some((row, col)) => {
                if let Ok(cell_id) = navigator.fetch_cell_id(&sheet_id, row, col) {
                    let text = rst_to_plain_text(&c.text);
                    let author = authors.get(c.author_id as usize).unwrap();
                    let author_id = cell_attachment_manager
                        .comments
                        .authors
                        .get_or_register_id(author);
                    let comment = Comment {
                        author: author_id,
                        text,
                    };
                    cell_attachment_manager
                        .comments
                        .add_comment(sheet_id, cell_id, comment);
                }
            }
            None => {}
        })
}

pub fn load_sheet_data(
    sheet_id: SheetId,
    book_name: &str,
    sheet_data: &CtSheetData,
    navigator: &mut Navigator,
    sheet_id_manager: &mut SheetIdManager,
    sheet_pos_manager: &mut SheetPosManager,
    text_id_manager: &mut TextIdManager,
    func_id_manager: &mut FuncIdManager,
    name_id_manager: &mut NameIdManager,
    ext_books_manager: &mut ExtBooksManager,
    container: &mut DataContainer,
    formula_manager: &mut FormulaManager,
    range_manager: &mut RangeManager,
    cube_manager: &mut CubeManager,
    ext_ref_manager: &mut ExtRefManager,
    style_loader: &mut StyleLoader,
    workbook: &Wb,
) {
    navigator.add_sheet_id(&sheet_id);

    let mut base_curr_idx = 0;
    let mut offset = 0;
    sheet_data.rows.iter().for_each(|row| {
        let style_id = style_loader.load_xf(row.s);
        if let Some(idx) = row.r {
            base_curr_idx = idx;
            offset = 0;
        }

        let row_info = RowInfo {
            collapsed: row.collapsed,
            custom_format: row.custom_format,
            custom_height: row.custom_height,
            hidden: row.hidden,
            ht: row.ht,
            outline_level: row.outline_level,
            style: style_id,
        };
        let idx = base_curr_idx + offset;
        let id = navigator.fetch_row_id(&sheet_id, idx as usize).unwrap();
        container.set_row_info(sheet_id, id, row_info);

        offset += 1;

        row.cells.iter().for_each(|ct_cell| {
            if let Some(r) = &ct_cell.r {
                if let Some((row, col)) = parse_cell(r) {
                    let cv = CellValue::from_cell(ct_cell, |idx| {
                        let rst = workbook.xl.sst.as_ref().unwrap().1.si.get(idx).unwrap();
                        let string = rst_to_plain_text(rst);
                        text_id_manager.get_or_register_id(&string)
                    });
                    let id = navigator.fetch_cell_id(&sheet_id, row, col).unwrap();
                    let style_id = style_loader.load_xf(ct_cell.s);
                    let cell = Cell {
                        value: cv,
                        style: style_id,
                    };
                    container.add_cell(sheet_id, id, cell);
                    if let Some(formula) = &ct_cell.f {
                        let mut connector = FormulaConnector {
                            book_name,
                            container,
                            sheet_pos_manager,
                            sheet_id_manager,
                            text_id_manager,
                            func_id_manager,
                            name_id_manager,
                            id_navigator: &mut navigator.clone(),
                            idx_navigator: navigator,
                            external_links_manager: ext_books_manager,
                            range_manager,
                            cube_manager,
                            ext_ref_manager,
                            dirty_ranges: HashSet::new(),
                            dirty_cubes: HashSet::new(),
                        };
                        if let Some(f) = &formula.formula {
                            if let Some(reference) = &formula.reference {
                                if let Some(((row_start, col_start), (row_end, col_end))) =
                                    parse_range(reference)
                                {
                                    load_shared_formulas(
                                        formula_manager,
                                        sheet_id,
                                        row_start,
                                        col_start,
                                        row_start,
                                        col_start,
                                        row_end,
                                        col_end,
                                        f,
                                        &mut connector,
                                    )
                                } else if let Some((row_idx, col_idx)) = parse_cell(reference) {
                                    load_normal_formula(
                                        formula_manager,
                                        sheet_id,
                                        row_idx,
                                        col_idx,
                                        f,
                                        &mut connector,
                                    )
                                }
                            } else {
                                load_normal_formula(
                                    formula_manager,
                                    sheet_id,
                                    row,
                                    col,
                                    f,
                                    &mut connector,
                                )
                            }
                        }
                    }
                }
            }
        })
    });
}

pub fn load_sheet_format_pr(
    settings: &mut Settings,
    sheet_id: SheetId,
    sheet_format_pr: &CtSheetFormatPr,
) {
    settings
        .sheet_format_pr
        .insert(sheet_id, sheet_format_pr.clone());
}

pub fn load_sheet_views(settings: &mut Settings, sheet_id: SheetId, sheet_views: &CtSheetViews) {
    settings.sheet_views.insert(sheet_id, sheet_views.clone());
}

fn rst_to_plain_text(rst: &CtRst) -> String {
    match &rst.t {
        Some(p) => p.value.to_string(),
        None => {
            let mut result = String::from("");
            rst.r.iter().for_each(|relt| {
                let s = relt.t.value.to_string();
                result.push_str(s.as_str());
            });
            result
        }
    }
}