# Understanding How the Writer Works

The Writer system is designed to provide a flexible, reusable, and customizable way to handle file
writing. Here's how it works at a **base level** and how it can be **extended** with subclasses.

---

## **1. Base Level (BaseWriter)**

The `BaseWriter` is an **abstract base class (ABC)** that defines the core logic and structure for
writing files. It cannot be used directly but provides a foundation that subclasses can build upon.

### Key Components

1. **Root Directory**:
   - You must specify a `root_directory` where the files will be saved.
   - If the directory doesn’t exist and `create_dirs` is `True`, it will be automatically created.

2. **Filename Format**:
   - You define a `filename_format` that specifies how the file names should be structured.
   - The format can include placeholders like `{SubjectID}`, `{date}`, or any custom keys.
      - Format of placeholders is `{key}` or `%key` which allows for both python code and CLI usage.
   - These placeholders are replaced with actual values provided when calling the `save()` method (actual values passed in as keyword arguments(`**kwargs`)).

     ```python
       # Example filename_format
       filename_format = "Patient_{SubjectID}_{date}.txt"
     ```

3. **Pattern Resolution**:
   - The `BaseWriter` uses a `PatternResolver`, inherited from `Med-ImageTools` to validate and parse the `filename_format`.
   - It ensures all placeholders are valid and logs errors if any are missing during file creation.

4. **Core Methods**:
   - `resolve_path(**kwargs)`: Generates the file path by replacing placeholders in the
     `filename_format`.
   - `save(*args, **kwargs)`: Abstract method. Subclasses implement the logic for writing files.

     ```python
       # Example resolve_path usage for an ImplementedWriter subclass
       writer = ImplementedWriter(
           root_directory="output",
           filename_format="{SubjectID}_data_{date}.txt"
       )
       file_path = writer.resolve_path(SubjectID="JohnDoe", date="2024-01-01")
       print(file_path)
       # Output: output/JohnDoe_data_2024-01-01.txt
     ```

5. **Context Management**:
   - `BaseWriter` can be used as a context manager for setup and teardown logic.
   - Automatically cleans up empty directories created during file operations.

     ```python
       with writer:
           writer.save(...)
     ```

---

## **2. Subclass Level**

Subclasses of `BaseWriter` provide the actual file writing logic. Each subclass must implement the
`save()` method to define how files of a specific type are written.

### Subclass Responsibilities

1. **Implement the `save()` Method**:
   - This method takes in data (e.g., text, images, or other file types) and writes it to disk using
     the path generated by `resolve_path()`.

     ```python
       class TextWriter(BaseWriter):
           def save(self, content: str, **kwargs: Any) -> Path:
               output_path = self.resolve_path(**kwargs)
               with output_path.open("w") as file:
                   file.write(content)
               return output_path
     ```

2. **Handle File-Specific Logic**:
   - Each subclass can validate its data or handle specific requirements, such as compression or
     formatting.

     ```python
       class NIFTIWriter(BaseWriter):
           def save(self, image: sitk.Image, **kwargs: Any) -> Path:
               output_path = self.resolve_path(**kwargs)
               sitk.WriteImage(image, str(output_path), useCompression=True)
               return output_path
     ```

3. **Use Class-Level Validation**:
   - Subclasses can define their own validation for file extensions, required placeholders, etc.

---

## **Summary**

1. **BaseWriter**:
   - Defines the core functionality for handling directories, generating paths, and managing
     resources.
   - Requires `save()` to be implemented by subclasses.

2. **PatternResolver**:
   - Validates and parses filename formats.

3. **Subclasses**:
   - Provide specific file writing logic (e.g., text files, NIFTI images).
   - Implement validation, compression, or other requirements.

By extending `BaseWriter`, you can create flexible and reusable file writers for any type of data.
