# 機能設計書 12-お気に入り管理

## 概要

本ドキュメントは、K-Shoot MANIA の選曲画面における「お気に入り管理」機能の設計を記述する。楽曲のお気に入り登録・解除をFavoriteファイル(.fav)を介して管理する機能である。

### 本機能の処理概要

本機能は、選曲画面でEnterキーを長押しすることでダイアログを表示し、楽曲をお気に入りフォルダに登録したり、お気に入りフォルダ内で楽曲を削除したりする機能を提供する。お気に入りは複数のFavoriteグループ(Favorite1〜Favorite9)で管理され、`.fav`ファイルに楽曲パスを改行区切りで保存する。

**業務上の目的・背景**：大量の楽曲ライブラリの中から、プレイヤーがよくプレイする楽曲やお気に入りの楽曲を分類・管理できるようにすることで、選曲の利便性を向上させる。最大9つのお気に入りグループを使い分けることで、ジャンル別・難易度別・練習中など多様な分類が可能。

**機能の利用シーン**：
- 通常フォルダ内の楽曲を選択中にEnterキーを長押し: お気に入り追加ダイアログが表示される
- お気に入りフォルダ内の楽曲を選択中にEnterキーを長押し: お気に入り削除ダイアログが表示される

**主要な処理内容**：
1. Enterキー長押し(750ms以上)の検出と追加/削除ダイアログの表示切替
2. お気に入りグループ番号(1-9)の選択UI表示
3. `.fav`ファイルへの楽曲パス追加(notesel/notesave)
4. `.fav`ファイルからの楽曲パス削除(notedel/notesave)
5. お気に入りフォルダ自体の曲リスト再構築(refreshfilelist)

**関連システム・外部連携**：ファイルシステム(`songs/FavoriteN.fav`ファイル)。

**権限による制御**：なし。全プレイヤーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 曲選択画面 | 主画面 | Favoriteファイル(.fav)の読み書きによる楽曲のお気に入り登録・解除(favselnow/favselnum制御) |

## 機能種別

CRUD操作(ファイルベース) / UI操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stat2a | int | Yes | Enterキー状態(0:未押下, 1:押下中) | - |
| stat2astartt | int | Yes | Enterキー押下開始時刻 | - |
| timenow | int | Yes | 現在時刻(ms) | - |
| dir | string | Yes | 現在のディレクトリ種別("?"で始まる場合はFavoriteフォルダ) | - |
| favselnow | int | Yes | 現在選択中のFavoriteグループ番号(0始まり) | 0 <= favselnow < favselnum |
| favselnow2 | int | Yes | 削除確認選択(0:No, 1:Yes) | 0 or 1 |

### 入力データソース

- キーボード/ジョイスティックの入力(Enterキー長押し、方向キー、Escキー)
- `songs/FavoriteN.fav`ファイル(既存のお気に入りデータ)

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FavoriteN.fav | ファイル | お気に入り楽曲パスの改行区切りリスト |
| dialognow | int | ダイアログ表示状態(0:非表示, 1:追加, 2:削除) |

### 出力先

- ファイルシステム: `songs/FavoriteN.fav`ファイルへの書き込み
- 画面表示: お気に入り追加/削除ダイアログの描画

## 処理フロー

### 処理シーケンス

```
1. Enterキー長押し検出(stat2ap=1, stat2a=1, timenow-stat2astartt>750)
   └─ 長押し条件を満たした場合にダイアログ表示
2. 現在のディレクトリ種別を判定
   ├─ 通常フォルダ(dir先頭が"?"でない): dialognow=1(追加ダイアログ)
   │   └─ favselnum: Favorite1-9のうち存在するファイル数+1を設定
   └─ Favoriteフォルダ(dir先頭が"?"): dialognow=2(削除ダイアログ)
       └─ favselnow2=0(No)で初期化
3. ダイアログ操作
   ├─ 追加ダイアログ(dialognow=1):
   │   ├─ 上下キーでFavoriteグループ選択(favselnow切替)
   │   ├─ Enterキーで追加実行
   │   │   ├─ .favファイル読み込み
   │   │   ├─ 重複チェック
   │   │   └─ 未登録なら楽曲パスを追加して保存
   │   └─ Escキーでキャンセル
   └─ 削除ダイアログ(dialognow=2):
       ├─ 左右キーでYes/No切替(favselnow2)
       ├─ Enterキー+Yes選択で削除実行
       │   ├─ .favファイル読み込み
       │   ├─ 該当楽曲パスを検索・削除(notedel)
       │   └─ ファイル保存後、曲リスト再構築
       └─ Escキーでキャンセル
```

### フローチャート

```mermaid
flowchart TD
    A[Enterキー長押し 750ms超] --> B{dir先頭が '?' ?}
    B -->|No| C1[dialognow=1: 追加ダイアログ表示]
    B -->|Yes| C2[dialognow=2: 削除ダイアログ表示]
    C1 --> D1[上下キーでFavoriteグループ選択]
    D1 --> E1{Enterキー?}
    E1 -->|Yes| F1[.favファイル読み込み]
    F1 --> G1{重複あり?}
    G1 -->|No| H1[楽曲パス追加・保存]
    G1 -->|Yes| I[ダイアログ閉じる]
    H1 --> I
    E1 -->|Esc| I
    C2 --> D2[左右キーでYes/No選択]
    D2 --> E2{Enterキー?}
    E2 -->|Yes| F2{favselnow2=1: Yes?}
    F2 -->|Yes| G2[該当楽曲削除・保存]
    G2 --> H2[refreshfilelist実行]
    H2 --> I
    F2 -->|No| I
    E2 -->|Esc| I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-12-1 | 重複登録防止 | 同一楽曲パスが既にFavoriteファイルに存在する場合は追加しない | 追加ダイアログでEnter押下時 |
| BR-12-2 | Favoriteグループ数 | 最大9グループ(Favorite1-Favorite9)まで作成可能 | 追加ダイアログ表示時 |
| BR-12-3 | パス正規化 | パス区切り文字を`\\`から`/`に統一してから保存する(`replace(buf,"\\\\","/")`) | .favファイル保存時 |
| BR-12-4 | 空ファイル削除判定 | 削除後にFavoriteファイルが空になった場合、dirを""にリセット | 削除実行後 |
| BR-12-5 | 不正エントリ自動削除 | .favファイル読み込み時に実際に存在しないファイルパスを自動で削除する | Favoriteフォルダ表示時(*refreshfilelist内) |

### 計算ロジック

Favoriteグループ数の算出:
```
favselnum = 1 (初期値)
repeat 9
    exist dir_default + "\\songs\\Favorite" + cnt + ".fav"
    if strsize > 0: favselnum = cnt + 1
loop
```

## データベース操作仕様

### 操作別データベース影響一覧

本機能ではデータベースは使用しない。ファイルシステム上の`.fav`ファイルを使用する。

| 操作 | 対象ファイル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 追加 | songs/FavoriteN.fav | 追記(notesel+notesave) | 楽曲パスを末尾に追加 |
| 削除 | songs/[dir名].fav | 更新(notedel+notesave) | 該当楽曲パスを削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル不在 | .favファイルが存在しない場合 | 新規作成として扱い、楽曲パスのみを書き込む |
| - | 重複登録 | 同じ楽曲パスが既に登録済みの場合 | 追加をスキップ(エラー表示なし) |

### リトライ仕様

なし。

## トランザクション仕様

ファイル単位での読み込み・書き込み。HSPのnotesel/notesave命令によるアトミックな書き込みに依存する。

## パフォーマンス要件

- .favファイルの読み込み・書き込みは即座に完了する(楽曲数は通常数十〜数百程度)
- 追加時は全エントリとの重複チェック(線形探索)が発生する

## セキュリティ考慮事項

特になし。ローカルファイルシステムへの読み書きのみ。

## 備考

- お気に入りフォルダはルートメニューに`?FavoriteN`の形式で表示される
- .favファイルの各行は`楽曲フォルダパス`または`楽曲フォルダパス/ファイル名.ksh`の形式
- 削除後に曲リストが空になった場合は自動的にルートメニューに戻る

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.hsp | `src/scene/select.hsp` | `favselnow`(現在選択中のFavoriteグループ)、`favselnum`(グループ総数)、`favselnow2`(削除確認のYes/No)、`dialognow`(ダイアログ状態)の変数を理解する |

**読解のコツ**: `dialognow`は0:非表示, 1:追加ダイアログ, 2:削除ダイアログの3状態を取る。dirの先頭文字が"?"の場合はFavoriteフォルダを示す。

#### Step 2: 長押しトリガーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.hsp | `src/scene/select.hsp` | 1735-1751行目のEnterキー長押し検出とダイアログ表示開始処理 |

**主要処理フロー**:
1. **1735行目**: `timenow-stat2astartt>750` - 750ms以上の長押し判定
2. **1737行目**: `favstartt=timenow` - お気に入りダイアログ開始時刻記録
3. **1739-1747行目**: 通常フォルダ時(dialognow=1) - Favoriteグループ数の算出
4. **1748-1751行目**: Favoriteフォルダ時(dialognow=2) - 削除ダイアログ初期化

#### Step 3: 追加ダイアログ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.hsp | `src/scene/select.hsp` | 2303-2354行目のdialognow=1処理 |

**主要処理フロー**:
- **2309-2320行目**: 上下キーによるFavoriteグループ選択(favselnowの増減)
- **2323-2348行目**: Enterキーによる追加実行
- **2329-2331行目**: .favファイルの読み込み(exist + noteload)
- **2333-2336行目**: 重複チェック(全エントリとの比較)
- **2337-2341行目**: 未登録の場合、楽曲パスを追加して保存(notesave)
- **2351-2353行目**: Escキーによるキャンセル

#### Step 4: 削除ダイアログ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | select.hsp | `src/scene/select.hsp` | 2355-2444行目のdialognow=2処理 |

**主要処理フロー**:
- **2365-2366行目**: 左右キーによるYes/No切替(favselnow2 = 1-favselnow2)
- **2374-2392行目**: Yes選択時の削除処理
- **2377-2378行目**: .favファイル読み込み
- **2380-2387行目**: 該当楽曲パスの検索と削除(notedel)
- **2392行目**: ファイル保存(notesave)
- **2397行目**: refreshfilelist呼び出しで曲リスト再構築

#### Step 5: Favoriteフォルダの曲リスト生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | select.hsp | `src/scene/select.hsp` | 2671-2835行目の*refreshfilelist内dirtype=2(Favorite)処理 |

**主要処理フロー**:
- **2675-2680行目**: .favファイルの読み込みとパス正規化
- **2693-2787行目**: 各エントリの存在確認とfilelistへの展開
- **2789-2834行目**: 存在しないエントリの自動削除(f=1の場合)

### プログラム呼び出し階層図

```
start_select (メインループ)
    |
    +-- [Enterキー長押し判定] (1735行目)
    |       |
    |       +-- dialognow=1 設定 (通常フォルダ時)
    |       +-- dialognow=2 設定 (Favoriteフォルダ時)
    |
    +-- [dialognow=1: 追加ダイアログ処理] (2303行目)
    |       |
    |       +-- 上下キーでFavoriteグループ選択
    |       +-- Enter: .fav読み込み -> 重複チェック -> 追加 -> notesave
    |       +-- Esc: dialognow=0
    |
    +-- [dialognow=2: 削除ダイアログ処理] (2355行目)
    |       |
    |       +-- 左右キーでYes/No選択
    |       +-- Enter+Yes: .fav読み込み -> 検索 -> notedel -> notesave
    |       |       +-- *refreshfilelist
    |       |       +-- *refreshjacket
    |       |       +-- *refreshscore
    |       |       +-- *refreshsonginfo
    |       +-- Esc: dialognow=0
    |
    +-- [ダイアログ描画] (2447行目)
            |
            +-- dialognow=1: IMG119/IMG120のお気に入り追加UI描画
            +-- dialognow=2: IMG121のお気に入り削除UI描画
```

### データフロー図

```
[入力]                      [処理]                         [出力]

Enterキー長押し(750ms) --> ダイアログ表示判定 ---------> dialognow
                                |
上下/左右キー入力 ----------> グループ/Yes-No選択 ------> favselnow / favselnow2
                                |
Enterキー押下 --------------> 追加/削除実行
    |                           |
    |  songs/FavoriteN.fav <--> .favファイル読み書き ----> songs/FavoriteN.fav
    |                           |
    +-- minfostr配列 --------> 楽曲パス取得 -----------> 重複チェック
                                |
                            *refreshfilelist -----------> 曲リスト再構築
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.hsp | `src/scene/select.hsp` | ソース | お気に入り管理のダイアログ処理、追加/削除ロジック、Favoriteフォルダの曲リスト生成 |
| FavoriteN.fav | `songs/FavoriteN.fav` | データ | お気に入り楽曲パスの保存ファイル(N=1-9) |
| [dir名].fav | `songs/[dir名].fav` | データ | フォルダ単位のお気に入り楽曲パス保存ファイル |
