# Save Module data flow

## What It Does
Handles serialization and export of workbook data to client or server. The Workbook layer (`WorkbookSave`) builds the export payload, applies sheet-level processing and worker pipelines, and performs HTTP or form POST downloads. The Spreadsheet layer (`Save`) provides UI dialogs, spinner/feedback and error handling.

Primary implementation files: `src/workbook/integrations/save.ts` (Core/WorkbookSave) and `src/spreadsheet/integrations/save.ts` (UI/Save).

## Entry Points (UI)
**Class:** `Save` (Spreadsheet layer)
- Listens: `beginSave`, `saveCompleted`, `saveError`, `exportDialog`, registering handlers via `addEventListener()`.
- Key handlers:
  - `initiateSave()` — show spinner when save starts.
  - `saveCompleted()` — hide spinner after save finishes.
  - `exportDialog(args)` — render "Save As" dialog, validate filename and call `parent.save()` with chosen `SaveType` and filename.
  - `showErrorDialog(args)` — show modal dialog with export/save error content.
  - Helpers: `checkValidName()` and `OpenContent(type)` create/validate UI elements for filename entry.
- Lifecycle: `addEventListener()` / `removeEventListener()` and `destroy()` to remove DOM and listeners.

## Entry Points (Core)
**Class:** `WorkbookSave` (Workbook layer)
- Listens: `beginSave`, and internal stringify request `getStringifyObject`.
- Key responsibilities:
  - `initiateSave(args)` — accept save configuration (saveType, url, fileName, pdfLayoutSettings), configure pipeline flags, and call `processSheets()`.
  - `processSheets(autoDetectFormat, jsonConfig, skipWorker)` — iterate sheets and schedule sheet serialization; optionally wait for data sources to load and use worker pipeline (`executeTaskAsync`) for processing.
  - `getStringifyObject()` / `performStringifyAction()` — produce JSON string of workbook or individual sheet(s) while omitting skipProps and handling special conversions (dates, charts, conditional formats). Also invoked by other modules requesting workbook JSON.
  - `processSave()` / `initiateFullPostSave()` / `ClientFileDownload()` — perform final save action: worker-based processing, form POST for full post, or client download using generated Blob URL; also handles `needBlobData` path.
  - `updateSaveResult(result)` — normalize save results, raise `saveComplete`/`saveCompleted` events, trigger download or return blob to caller, and show save errors via `saveError` notification.
  - Helpers: `updateBasicSettings()`, `updateSheet()` (collect per-sheet output), `getDateAsNumber()`, `getFileNameWithExtension()`, and `getFileExtension()`.

## ASCII Core Logic Flow
User triggers save (UI) → Spreadsheet `Save` shows spinner and may open dialog → `parent.save()` fires `beginSave` → `WorkbookSave.initiateSave()` configures pipeline
         ↓
`processSheets()` serializes each sheet (skipping props as requested) possibly using worker pipeline → `updateSheet()` aggregates per-sheet results
         ↓
Once all sheets processed: `save()` performs either full post or worker-based `processSave()` → `updateSaveResult()` handles result
         ↓
Result paths: client download (anchor + object URL) or return Blob (when `needBlobData`) or POST to server; UI `Save.saveCompleted()` hides spinner and `saveError` may show dialogs

## Operations (functions & responsibilities)
- `initiateSave(args)` (Core)
  - Normalize save parameters; set flags for `isFullPost`, `needBlobData`, `skipWorkerPipeline`, and initiate sheet processing.

- `processSheets(autoDetectFormat, jsonConfig, isSkipWorkerPipeline)` (Core)
  - For each sheet decide whether to wait for data-bound ranges to load; schedule `processSheet` on worker or main thread; collect results via `updateSheet()`.

- `getStringifyObject(model, skipProps, sheetIdx, autoDetectFormat, isSaveAction)` (Core)
  - Custom JSON.stringify replacer that omits skipProps, converts formulas, serializes charts/images conditionally, and calls notification hooks (e.g., `removeUniquecol`, `workbookFormulaOperation`) to ensure model correctness before export.

- `processSave()` / `updateSaveResult()` (Core)
  - Execute final serialization & transfer; normalize result object, invoke `saveComplete` event, and notify `saveCompleted`/`saveError` for UI.

- `exportDialog(args)` (UI)
  - Build "Save As" dialog, validate file name, and trigger `parent.save({ saveType, fileName })` when confirmed.

## Validation & Safety
- Skip properties: `processSheets()` accepts `jsonConfig` that can exclude styles, formulas, formats, charts, images, etc., reducing payload and preserving privacy or size constraints.
- Data-binding readiness: if a sheet contains dataSource ranges not yet loaded, `processSheets()` waits and registers `loadComplete` callback to ensure integrity.
- CSP / Worker policy: honor `isSkipWorkerPipeline` to avoid using WebWorkers in restricted environments; otherwise prefer `executeTaskAsync` for CPU-heavy serialization.
- Filename validation: `checkValidName()` enforces forbidden characters and maximum length before proceeding with save.
- Error handling: save workers can return dialog content via result; `updateSaveResult()` maps errors to `saveError` notifications for the UI.

## Desired Outputs
- User-facing: downloaded workbook file with correct filename/extension or a blob returned to caller when requested; progress spinner and error dialogs as appropriate.
- System-level: `saveComplete` and `saveCompleted` events emitted with status and metadata; serialized JSON payload compliant with server expectations (or client-side full-post form submission).
- Model artifacts: per-sheet JSON entries assembled under `saveJSON.sheets` with charts/images normalized and date/format conversions applied.

## Implementation Notes (short)
- Prefer worker pipeline for large workbooks to keep UI responsive; fall back to main-thread serialization when `skipWorkerPipeline` set.
- Maintain deterministic ordering of sheets in `saveJSON.sheets` and ensure `getFileNameWithExtension()` appends the correct extension for chosen `SaveType`.
- When producing the final Blob for download, revoke the object URL after click to avoid memory leaks (`URL.revokeObjectURL`).
- Use `parent.notify(events.onSave, args)` to allow other modules to cancel or modify the `saveJSON` before transmission.
- Ensure `performStringifyAction` supports both workbook-level and sheet-level stringify requests used by other integration pieces.

---