# PLAN-FILEORGANIZATION — HC Launcher: Managed File Organization

## Context

HC Launcher currently treats all file dialogs (BattleSets, scenarios, databases, saves, logs) as flat file pickers defaulting to the HC game directory. There is no managed directory structure for organizing downloaded artifacts (from harpgamer.com, community sources) or game-generated files (saves, logs, iterative saves). Users must manually sort files into the GE's expected locations.

The HC game directory is typically cluttered (e.g., `C:\Games\HC` contains ~410 items in a flat mix of `.RES`, `.RSR`, `.hpq`, `.scs`, `.scq`, `.sco`, `.zip`, `.exe`, `.bat`, `.xml`, `.log`, `.dll`, and various ad-hoc subdirectories). This makes it difficult to find, organize, or manage specific artifact types.

**Why:** As the HC community shares BattleSets, scenarios, platform databases, ExportDLLs, sounds, graphics, and maps, users need an organized, version-aware directory tree that the Launcher can manage — browsing, importing, and referencing artifacts by category. This also provides a clean separation between the HC game installation and user-curated content.

**Outcome:** A well-defined directory layout under `<basedir>\HCLauncher\` with per-category subdirectories, download caches, version support, and Launcher UI for configuring and browsing the managed tree.

---

## Definitions

- **`<gamedir>`** — The HC game installation directory (e.g., `C:\Games\HC`). This is the existing `edtHCDirGE.Text` / INI key `[Main] DirHC`.
- **`<basedir>`** — The root for the managed file tree. Defaults to `<gamedir>` but can be overridden by the user. Persisted in `[Main] BaseDir` in `Launcher.ini`. When blank/unset, falls back to `<gamedir>`.
- **Managed root** — `<basedir>\HCLauncher\` — all managed content lives under this single directory.

---

## Directory Layout

The tree has two main branches for game content — **BattleSets** (embedded-DB, self-contained) and **PlatformDBs** (commondb, EC2003+). Both follow the same nesting pattern down to saved games: `Scenarios\<name>\SavedGames\`. The remaining categories (ExportDLLs, Sounds, Graphics, Maps, Logs) are flat peers.

```
<basedir>\HCLauncher\
│
│  ══════════════════════════════════════════════════════════════
│  GAME CONTENT — two parallel branches by DB model
│  ══════════════════════════════════════════════════════════════
│
├── BattleSets\                              ← embedded-DB BattleSets (self-contained)
│   ├── cache\                               ← downloaded ZIPs
│   └── <battleset-name>\
│       ├── *.res + *.rsr (pair)              ← BattleSet resource + resource-string files
│       ├── *.HCBS                            ← BSBuilder settings (if BSBuilder-created)
│       └── Scenarios\
│           └── <scenario-name>\
│               ├── *.sc? + *.xml             ← scenario files + sidecar metadata
│               ├── *.BK?                    ← scenario backups
│               ├── *.BL?, *.RD?             ← orders files (Blue/Red)
│               └── SavedGames\
│                   ├── *.hp?                 ← user-generated saves
│                   └── AutoSaves\
│                       └── *.hp?             ← GE auto-saves
│
├── PlatformDBs\                             ← commondb BattleSets (EC2003+)
│   ├── cache\                               ← downloaded ZIPs (e.g., HCDB-160414.zip)
│   └── <db-version>\                        ← versioned (e.g., HCDB-160414, HCDB-220101)
│       ├── res\                             ← annex CSV files + DatabaseStructureVersion.txt
│       │   └── annex_*.csv, ...
│       ├── rsr\                             ← resource BMPs + DatabaseStructureVersion.txt
│       │   └── res*.bmp, ...
│       ├── pfData2005.mdb                   ← source Access files (when distributed)
│       ├── pfBuild2005.mdb
│       └── Scenarios\
│           └── <scenario-name>\
│               ├── *.sc? + *.xml             ← scenario files + sidecar metadata
│               ├── *.BK?                    ← scenario backups
│               ├── *.BL?, *.RD?             ← orders files (Blue/Red)
│               └── SavedGames\
│                   ├── *.hp?                 ← user-generated saves
│                   └── AutoSaves\
│                       └── *.hp?             ← GE auto-saves
│
│  ══════════════════════════════════════════════════════════════
│  SUPPORTING ASSETS — flat peers with download caches
│  ══════════════════════════════════════════════════════════════
│
├── ExportDLLs\                              ← mirrors GE's ExportDLLs structure
│   ├── cache\                               ← downloaded ZIPs
│   ├── *.dll, *.ini, *.txt                  ← common (GE + SE) + configs
│   ├── GE\
│   │   ├── *.dll                            ← GE-only DLLs
│   │   └── <DLLName>\                       ← per-DLL asset subdirs (e.g., MapWindow\)
│   └── SE\
│       ├── *.dll                            ← SE-only DLLs
│       └── <DLLName>\
│
├── Sounds\
│   ├── cache\                               ← downloaded ZIPs
│   └── *.wav                                ← SND_* naming convention
│
├── Graphics\
│   ├── cache\                               ← downloaded ZIPs
│   └── *.bmp                                ← GR_* naming, 8/16-bit, CDB variants
│
├── Maps\
│   ├── cache\                               ← downloaded ZIPs
│   └── <map-name>\
│       ├── *.tif                            ← BSBuilder map images
│       └── 2048-16bit.bmp                   ← quick thumbnail texture
│
├── Tools\                                   ← misc./fallback artifact type
│   ├── cache\                               ← downloaded ZIPs
│   └── <tool-name>\
│       └── ...                              ← contents vary; generic filenames, one dir per artifact
│
└── Logs\                                    ← game-generated only (no cache)
    └── *.log, *.txt
```

### BattleSet-to-Scenario-to-PlatformDB Relationships

A commondb scenario references a BattleSet (map/geography) but that `.res`/`.rsr` pair does **not** live within the `PlatformDBs\` tree. The BattleSet-to-PlatformDB association is tracked by:
- Filename convention (scenario name often includes BattleSet name)
- BattleSet number embedded in scenario file content (sometimes)
- External metadata (harpgamer download page, distributed README, etc.)

The directory structure does not encode this cross-reference. A future metadata/catalog layer (Phase 4+) will resolve it programmatically.

### One Directory Per Artifact (collision avoidance)

BattleSets, Scenarios, and PlatformDBs each get their own named subdirectory — this is a **requirement**, not optional nesting. The reason: multiple artifacts within the same category can have identical filenames.

- **BattleSets**: All BSBuilder-created BattleSets produce `hdsu.res` / `hdsu.rsr`. Without separate directories, they overwrite each other. The directory name (e.g., `MedCrisis\`, `GIUK-Custom\`) is the user's label that distinguishes them.
- **Scenarios**: Companion files (`.sc?` + `.xml` + `.BK?` + `.BL?` + `.RD?` + `SavedGames\`) form a unit. Separate directories keep them grouped and prevent name collisions between scenarios with similar base names.
- **PlatformDBs**: All commondb versions contain identically-named internal files (`res\annex_a1.csv`, `rsr\res0000.bmp`, etc.). The version directory (e.g., `HCDB-160414\`) is the only thing distinguishing them.

### Notes on the Layout

- **cache\ directories** hold original downloaded archives. They are never modified after download. This allows re-extraction and verifying integrity.
- **Version directories under PlatformDBs** allow multiple commondb versions to coexist (required because different BattleSets may reference different DB family/version minimums).
- **ExportDLLs mirrors the GE structure** (common root, `GE/`, `SE/`) so the launcher can copy or symlink directly into `<gamedir>\ExportDLLs\` when deploying.
- **Maps** uses the BSBuilder convention: `.tif` map images in a subdirectory, with `2048-16bit.bmp` as the thumbnail texture.
- **Logs** has no cache — these are generated locally, not downloaded (the code, however, creates a `cache\` subdirectory uniformly for every category including Logs; the diagram is aspirational on this one point).
- **Subdirectory naming** within each category is user-defined (free-form folder names). The launcher does not enforce a naming convention beyond the top-level categories.

---

## Artifact Details (from live `C:\Games\HC`)

### Sounds (`<gamedir>\Sounds\`)

24 WAV files with `SND_*` naming convention plus `Sounds.txt` description file. Each sound maps to a game event; users replace a WAV file to customize the sound for that event.

| File pattern | Game event |
|-------------|------------|
| `SND_EXP_*.WAV` | Weapon hit (gun, missile, nuke, torpedo) |
| `SND_LAUNCH_*.WAV` | Launch (missile, ASW, gun, torpedo, helo, prop, jet) |
| `SND_DETECT_*.WAV` | Detection (active radar, active sonar, passive sonar, ESM, missile) |
| `SND_GQ.WAV` | General Quarters |
| `SND_CBN.WAV` | Chemical/Biological/Nuclear release |
| `SND_PLANE_*.WAV` | Plane events (crash, killed, ready) |
| `SND_SPLASH.WAV` | Clean miss (unused) |
| `SND_ERROR.WAV` | Error (unused) |
| `SND_COLLISION.WAV` | Collision (unused) |

### Graphics (`<gamedir>\Graphics\`)

37 BMP files with `GR_*` naming convention plus `Graphics.txt` description file. 8-bit (256 color) suggested, 16-bit also works. Files with `CDB` in the name are shown for CommonDB BattleSets (EC2003+). Side variants: `BLUE`/`RED`. Numbered variants (e.g., `_1`, `_2`) rotate per BattleSet.

| File pattern | Purpose |
|-------------|---------|
| `GR_CIC_*.BMP` | Staff Assistant window backgrounds |
| `GR_LOGO_*.BMP` | Splash screen graphics (GE_1..4, SE, AGSI) |
| `GR_SUNK_CV_*.BMP` | Carrier sunk event image |
| `GR_SUNK_SHIP_*.BMP` | Ship sunk event image |
| `GR_SUNK_SUB_*.BMP` | Submarine sunk event image |
| `GR_VIC_*.BMP` | Victory condition dialog image |
| `GR_ICONS.BMP` | Unit/group icons used in-game |

### Maps (`<gamedir>\BSBuilder\`)

BSBuilder stores map data:
- `map_img\elevation.tif` + `map_img\texture.tif` — full map images
- `2048-16bit.bmp` — quick thumbnail texture at root level
- Also at root: `elevation.tif`, `texture.tif`, `output.tif`, `WholeWorld.HCBS`, `TGlobe.sdb`

### PlatformDBs (`<gamedir>\commondb\`)

The GE's commondb uses subdirectories, not single binary files:
- `commondb\res\` — CSV annex files (`annex_a1.csv`, `annex_b1.csv`, etc.) + `DatabaseStructureVersion.txt`
- `commondb\rsr\` — BMP resource files (`res0000.bmp`, `res0001.bmp`, etc.) + `DatabaseStructureVersion.txt`

The `.mdb` source files (`pfData2005.mdb`, `pfBuild2005.mdb`) may or may not be distributed alongside.

### ExportDLLs (`<gamedir>\ExportDLLs\`)

Three tiers:
- Root: common DLLs loaded by both GE and SE (plus `.ini` config files, `.log` files, `.txt` docs)
- `GE\`: GE-only DLLs (e.g., `DigMilArt.dll`, `EduMetrics.dll`, `MapWindow.dll`) with per-DLL subdirectories for assets
- `SE\`: SE-only DLLs (currently empty in this installation)

Notable: some DLLs have companion subdirectories (e.g., `GE\EduMetrics\`, `GE\MapWindow\`) and config files (e.g., `DigMilArt.ini`).

---

## GE Directory Cross-Reference

The managed tree parallels the GE's own directory expectations:

| Managed location | GE equivalent at `<gamedir>\` | File types |
|-----------------|-------------------------------|------------|
| BattleSets\\`<name>`\ | root (flat, mixed with everything) | .res + .rsr (pair), .HCBS (BSBuilder) |
| ...\Scenarios\\`<name>`\ | root (flat) | .sc? + .xml sidecar + .BK? backups |
| ...\Scenarios\\`<name>`\SavedGames\ | root (flat) or AutoSaves\ | .hp? |
| PlatformDBs\\`<version>`\ | commondb\res\, commondb\rsr\ | .csv, .bmp, .txt; also .mdb source |
| PlatformDBs\\...\\Scenarios\SavedGames\ | (same as above) | (same as above) |
| ExportDLLs\ | ExportDLLs\, ExportDLLs\GE\, ExportDLLs\SE\ | .dll, .ini, .log, .txt, asset subdirs |
| Sounds\ | Sounds\ | .wav (SND_* convention) |
| Graphics\ | Graphics\ | .bmp (GR_* convention, 8/16-bit) |
| Maps\ | BSBuilder\map_img\, BSBuilder\ | .tif, .bmp, .HCBS, .sdb |
| Logs\ | root (flat, via -f/-m flags) | .log, .txt |

### HC File Extensions Quick Reference

| Extension | Meaning | Notes |
|-----------|---------|-------|
| .RES / .RSR | BattleSet resource + resource-string (pair) | Always a pair; `commondb.res`/`commondb.rsr` is the only PlatformDB pair |
| .HCBS | BSBuilder settings file | Stores BSBuilder configuration for a BattleSet |
| .sc? | Scenario files | .scs, .scq, .sco, .scm, .SCi — wildcard `*.sc?` matches all |
| .xml | Scenario sidecar metadata | Same base name as .sc? file |
| .BK? | Scenario backups | .BKs, .BKo, .BKq — backup of corresponding .sc? file |
| .BL? / .RD? | Orders files | Blue (.BL?) and Red (.RD?) side orders for a scenario |
| .hp? | Saved game files | .hpq, .hp0, .hp1, .hpo, .hpg — wildcard `*.hp?` matches all |
| .mdb | Access database | Platform DB source (pfData2005, pfBuild2005) |
| .csv | Annex data | Inside commondb\res\ |
| .sdb | TGlobe database | Map database |

---

## Settings Persistence

### New INI Keys

```ini
[Main]
DirHC=C:\Games\HC              ; existing — HC game directory
BaseDir=                        ; NEW — managed root override (blank = use DirHC)
FileGE=HCE.exe                 ; existing — GE executable name
```

### Behavior

- On startup, resolve `<basedir>`:
  1. Read `[Main] BaseDir` from INI
  2. If blank or missing, fall back to `[Main] DirHC`
  3. Managed root = `<basedir>\HCLauncher\`
- The managed root path is displayed in the UI and editable via a directory picker
- Changing `<basedir>` does **not** move existing files — it simply points to a different tree. The user is responsible for moving content if they change the base.

---

## Phase 1 — Directory Management Unit ✓ COMPLETE

**File:** `uHCLFileOrganization.pas` (new)

### 1.1 Constants and Types

```pascal
type
  /// <summary>Top-level managed directory categories.</summary>
  THCLCategory = (
    hclBattleSets,    // BattleSets\        — embedded-DB BattleSets
    hclPlatformDBs,   // PlatformDBs\       — commondb versions
    hclExportDLLs,    // ExportDLLs\        — DLL plugins (mirrors GE structure)
    hclSounds,        // Sounds\            — WAV sound replacements
    hclGraphics,      // Graphics\          — BMP graphic replacements
    hclMaps,          // Maps\              — BSBuilder map images
    hclLogs           // Logs\              — game-generated logs
  );
```

Note: Scenarios and SavedGames are **not** top-level categories — they are nested under their parent BattleSet or PlatformDB. The interface provides path-building helpers for the nested structure.

### 1.2 IHCLFileOrganization Interface

```pascal
IHCLFileOrganization = interface
  // Root
  function GetManagedRoot: String;

  // Top-level categories
  function GetCategoryPath(ACategory: THCLCategory): String;
  function GetCachePath(ACategory: THCLCategory): String;

  // Nested paths — BattleSets branch
  function GetBattleSetPath(const ABattleSetName: String): String;
  function GetBattleSetScenariosPath(const ABattleSetName: String): String;
  function GetBattleSetScenarioPath(const ABattleSetName, AScenarioName: String): String;
  function GetBattleSetSavedGamesPath(const ABattleSetName, AScenarioName: String): String;

  // Nested paths — PlatformDBs branch
  function GetPlatformDBPath(const ADBVersion: String): String;
  function GetPlatformDBScenariosPath(const ADBVersion: String): String;
  function GetPlatformDBScenarioPath(const ADBVersion, AScenarioName: String): String;
  function GetPlatformDBSavedGamesPath(const ADBVersion, AScenarioName: String): String;

  // Directory operations
  function EnsureCategoryExists(ACategory: THCLCategory): Boolean;
  function EnsureAllCategoriesExist: Boolean;
  function EnsureScenarioPath(const ABattleSetOrDBVersion, AScenarioName: String;
    AIsCommonDB: Boolean): Boolean;

  // Listing
  function ListSubdirectories(const APath: String): TStringArray;
  function ListFiles(const APath: String; const AExtFilter: String): TStringArray;
end;
```

### 1.3 THCLFileOrganization Implementation

- Constructor takes `ABaseDir: String` parameter
- All path construction is centralized (no path building scattered across the form)
- Nested path helpers compose: e.g., `GetBattleSetSavedGamesPath('MedCrisis', 'Day1')` → `<root>\BattleSets\MedCrisis\Scenarios\Day1\SavedGames`
- `EnsureCategoryExists` / `EnsureAllCategoriesExist` creates top-level + cache directories on demand (`ForceDirectories`)
- `EnsureScenarioPath` creates the full nested path down to `SavedGames\`
- `ListFiles` supports filtering by extension (e.g., `'.res'`, `'.sc?'`)
- Zero UI dependency (uses SysUtils, Classes only)

### 1.4 Tests

`tests/test_FileOrganization.pas` — FPCUnit tests:
- Managed root construction from basedir
- Category path resolution for all 7 top-level categories
- Cache path resolution for all top-level categories
- BattleSet nested path: `<root>\BattleSets\X\Scenarios\Y\SavedGames`
- PlatformDB nested path: `<root>\PlatformDBs\V\Scenarios\Y\SavedGames`
- EnsureCategoryExists creates correct directory tree in a temp dir
- EnsureScenarioPath creates full nested structure in a temp dir
- ListFiles with extension filtering
- ListSubdirectories
- Edge cases: trailing PathDelim, empty basedir, names with spaces

---

## Phase 2 — UI Integration ✓ COMPLETE

### 2.1 BaseDir Control on Main Form

Add to the top-bar area of `uMain1.pas` / `uMain1.lfm`:
- `lblBaseDir: TLabel` — "Managed Files:"
- `edtBaseDir: TEdit` — displays resolved `<basedir>\HCLauncher\`
- `btnBaseDir: TButton` — directory picker to override basedir
- `ckbBaseDirOverride: TCheckBox` — "Use custom location" (when unchecked, follows HC dir)

### 2.2 Settings Load/Save

- `SettingsLoad`: read `[Main] BaseDir`, resolve managed root, create `IHCLFileOrganization`
- `SettingsSave`: write `[Main] BaseDir`
- On HC dir change (`edtHCDirGEChange`): if basedir is not overridden, update managed root

### 2.3 File Dialog Default Paths

Update all file dialog `InitialDir` assignments to use managed paths from `IHCLFileOrganization` instead of the flat `edtHCDirGE.Text`:

| Dialog | Current InitialDir | New InitialDir |
|--------|-------------------|----------------|
| dlgBSFNGE | edtHCDirGE.Text | FileOrg.GetCategoryPath(hclBattleSets) |
| dlgScenFNGE | edtHCDirGE.Text | Context-dependent: BattleSet or PlatformDB Scenarios path |
| dlgCDBresFNGE | edtHCDirGE.Text | FileOrg.GetCategoryPath(hclPlatformDBs) |
| dlgCDBrsrFNGE | edtHCDirGE.Text | FileOrg.GetCategoryPath(hclPlatformDBs) |
| dlgSavFNGE | edtHCDirGE.Text | Context-dependent: current scenario's SavedGames path |
| dlgLogFNGE | edtHCDirGE.Text | FileOrg.GetCategoryPath(hclLogs) |
| dlgIterFNGE | edtHCDirGE.Text | Context-dependent: current scenario's SavedGames path |
| dlgLogMLFNGE | edtHCDirGE.Text | FileOrg.GetCategoryPath(hclLogs) |

**Context-dependent dialogs:** Scenario and SavedGame dialogs need to know which BattleSet or PlatformDB is currently selected to navigate to the right nested path. When no context is available, fall back to the top-level category.

**Fallback:** If the managed directory doesn't exist yet (user hasn't created the tree), fall back to `edtHCDirGE.Text` as today.

---

## Phase 3 — Directory Creation and First-Run ✓ COMPLETE

### 3.1 Auto-Create on First Use

When the launcher starts and the managed root doesn't exist:
- Prompt the user: "Create managed file directory at `<path>`?"
- If yes, call `EnsureAllCategoriesExist`
- If no, continue with flat HC dir behavior (graceful degradation)

### 3.2 Menu/Button to Re-Create

A button or menu item to manually trigger directory creation if the user declined at first run or changed basedir.

---

## Phase 4 — Future Work (out of scope for this plan)

- **Metadata/catalog layer**: Track BattleSet-to-PlatformDB associations for commondb scenarios. Sources: filename convention, BattleSet number in scenario file content, harpgamer metadata, distributed READMEs. Possibly a `catalog.json` or `catalog.ini` at the managed root.
- ~~ZIP extraction from cache into category directories~~ — ✓ implemented via `uHCLArchive.pas`/`uHCLImport.pas` (see `PLAN-HARPGAMER-DOWNLOADS.md` Phase 4)
- Drag-drop import of downloaded files
- Category browser panels (tree view or list view of managed content)
- Deploy-to-GE: copy/symlink from managed tree into `<gamedir>` for ExportDLLs, Sounds, Graphics
- Integrity checking (hash verification of cached downloads)
- Cleanup tools (orphan cache files, empty directories)
- Additional artifact categories as they emerge

---

## Dependency Order

```
Phase 1 (uHCLFileOrganization + tests)
    ↓
Phase 2 (UI: basedir control + dialog defaults)
    ↓
Phase 3 (directory creation + first-run UX)
```

---

## Risk Register

| Risk | Mitigation |
|------|-----------|
| User sets basedir to a read-only or network path | EnsureCategoryExists returns Boolean; UI shows clear error if directory creation fails |
| Changing basedir orphans existing managed files | Document that changing basedir does not move files; consider a "migrate" feature in Phase 4 |
| File dialogs point to empty managed dirs (confusing UX) | Fall back to HC dir if category dir is empty or nonexistent |
| ExportDLLs structure diverges from GE expectations | Mirror GE's exact subdirectory names (ExportDLLs/, GE/, SE/) |
| Platform DB version naming conflicts | Use exact version string as directory name (e.g., HCDB-160414); no normalization |

---

## Implementation Log

- **2026-04-14**: Phases 1–3 implemented and committed.
  - `uHCLFileOrganization.pas` (607 lines): THCLCategory enum, IHCLFileOrganization interface, THCLFileOrganization class with path builders, directory creation, file/directory listing with Windows wildcard post-filtering.
  - `tests/test_FileOrganization.pas`: 26 FPCUnit tests (path construction, directory creation, listing, edge cases).
  - UI: basedir override checkbox + edit + browse button on main form row 3. `UpdateFileOrganization` method. INI persistence (`[Main] BaseDirOverride`, `[Main] BaseDir`). First-run directory creation prompt.
  - Bug fixes: file dialog filters corrected (`.hcb`→`.res`, `.hcs`→`.sc?`, `.sav`→`.hp?`).
  - All 106 tests pass (79 cmd-line + 1 settings + 26 file org).

## Iterative autosave cleanup (2026-09-26)

The GE does not write iterative saves into `Scenarios\<name>\SavedGames\AutoSaves\`: with `-S` it writes to `<GE folder>\ITER_SAVE_GAMETIME\<base>.<NNNN><ext>` (HC `libge/src/Command.c`), base being the `-k` name, else the user scenario's file name, else `<battleset>-<scenario>` for a built-in one (`026-000` = WestPac, scenario 1). The counter restarts at 0001 on every GE run, so a base mixes runs and "newest" means file time. The launcher's **Clean up autosaves…** window (Game Engine tab; `uHCLAutosaves`, `uHCLAutosaveCleanup`) groups them per base with the scenario each belongs to, and offers keep-newest-N, older-than-N-days, delete, and **move to the scenario's `SavedGames\AutoSaves`** for bases matching an installed scenario file. Decisions (Tony): removals go to the **Recycle Bin**; **manual only**, nothing pruned automatically. First look at a real install: 130 saves, 6.1 MB, two WestPac runs.
