//! Eine Befehlsliste für Menü, Tastatur und Statusleiste.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Command {
    NewProject,
    OpenProject,
    SaveProject,
    NewForm,
    NewModule,
    AddFile,
    RemoveFile,
    SaveFile,
    SaveAs,
    LoadText,
    SaveText,
    Print,
    Shell,
    Exit,
    Undo,
    Cut,
    Copy,
    Paste,
    Clear,
    Procedures,
    PreviousCode,
    Diagnostics,
    NewSub,
    NewFunction,
    Events,
    Code,
    Form,
    NextStatement,
    OutputScreen,
    IncludedFile,
    IncludedLines,
    MenuBar,
    Grid,
    Find,
    SelectedText,
    FindNext,
    Replace,
    Start,
    Restart,
    Continue,
    Pause,
    CommandLine,
    MakeExe,
    MakeLibrary,
    Startup,
    AddWatch,
    InstantWatch,
    Watchpoint,
    DeleteWatch,
    DeleteWatches,
    Trace,
    History,
    Breakpoint,
    ClearBreakpoints,
    BreakErrors,
    SetStatement,
    RunToCursor,
    Step,
    ProcedureStep,
    HistoryBack,
    HistoryForward,
    Display,
    Paths,
    RightMouse,
    SaveOptions,
    SyntaxChecking,
    NewWindow,
    Arrange,
    Calls,
    Debug,
    HelpWindow,
    Immediate,
    Output,
    Project,
    Palette,
    MenuDesign,
    Toolbox,
    Tool(&'static str),
    HelpIndex,
    HelpContents,
    Keyboard,
    Topic,
    UsingHelp,
    Tutorial,
    About,
    NextWindow,
    PreviousWindow,
    CloseWindow,
    MoveWindow,
    SizeWindow,
    Minimize,
    Maximize,
    Restore,
    ControlMenu,
    FocusWindow(u64),
}
impl Command {
    pub fn feature_phase(self) -> Option<u8> {
        use Command::*;
        match self {
            NextStatement | AddWatch | InstantWatch | Watchpoint | DeleteWatch | DeleteWatches
            | Trace | History | Breakpoint | ClearBreakpoints | BreakErrors | SetStatement
            | RunToCursor | Step | ProcedureStep | HistoryBack | HistoryForward => Some(6),
            HelpIndex | HelpContents | Keyboard | Topic | UsingHelp | Tutorial => Some(7),
            _ => None,
        }
    }
}
#[derive(Debug, Clone)]
pub struct Item {
    /// & markiert das sichtbare Mnemonic, … einen Dialog.
    pub label: String,
    pub command: Option<Command>,
}
impl Item {
    pub fn text(&self) -> String {
        self.label.replace('&', "")
    }
    pub fn mnemonic(&self) -> Option<char> {
        self.label
            .split_once('&')?
            .1
            .chars()
            .next()
            .map(|c| c.to_ascii_lowercase())
    }
}
pub struct Menu {
    pub title: &'static str,
    pub mnemonic: char,
    pub items: Vec<Item>,
}
pub fn menus(designer: bool) -> Vec<Menu> {
    use Command::*;
    let item = |label: &str, command| Item {
        label: label.into(),
        command: Some(command),
    };
    let sep = || Item {
        label: "────────".into(),
        command: None,
    };
    let menu = |title, mnemonic, items| Menu {
        title,
        mnemonic,
        items,
    };
    let mut result = vec![
        menu(
            "File",
            'f',
            vec![
                item("&New Project", NewProject),
                item("&Open Project…", OpenProject),
                item("Save &Project", SaveProject),
                sep(),
                item("New &Form", NewForm),
                item("New &Module…", NewModule),
                item("&Add File…", AddFile),
                item("&Remove File…", RemoveFile),
                item("&Save File", SaveFile),
                item("Sa&ve File As…", SaveAs),
                sep(),
                item("&Load Text…", LoadText),
                item("Save &Text…", SaveText),
                sep(),
                item("Pr&int…", Print),
                item("S&hell", Shell),
                sep(),
                item("E&xit", Exit),
            ],
        ),
        menu(
            "Edit",
            'e',
            vec![
                item("&Undo", Undo),
                sep(),
                item("Cu&t", Cut),
                item("&Copy", Copy),
                item("&Paste", Paste),
                item("C&lear", Clear),
                sep(),
                item("New &Sub…", NewSub),
                item("New &Function…", NewFunction),
                item("&Event Procedures…", Events),
            ],
        ),
        menu(
            "View",
            'v',
            vec![
                item("&Code…", Code),
                item("&Procedures…", Procedures),
                item("Diagno&stics…", Diagnostics),
                item("&Form…", Form),
                sep(),
                item("&Next Statement", NextStatement),
                item("&Output Screen", OutputScreen),
                sep(),
                item("&Included File", IncludedFile),
                item("Included &Lines", IncludedLines),
            ],
        ),
    ];
    if designer {
        result[2]
            .items
            .extend([sep(), item("&Menu Bar", MenuBar), item("&Grid Lines", Grid)]);
        result.push(menu("Tools", 't', {
            let mut used = std::collections::BTreeSet::new();
            crate::designer::tools()
                .into_iter()
                .map(|(name, _, _)| {
                    let mut label = name.to_owned();
                    if let Some((at, c)) = name
                        .char_indices()
                        .find(|(_, c)| !used.contains(&c.to_ascii_lowercase()))
                    {
                        used.insert(c.to_ascii_lowercase());
                        label.insert(at, '&');
                    } else {
                        let c = ('1'..='9').find(|c| !used.contains(c)).unwrap();
                        used.insert(c);
                        label = format!("&{c} {label}");
                    }
                    Item {
                        label,
                        command: Some(Tool(name)),
                    }
                })
                .collect()
        }));
    } else {
        result.extend([
            menu(
                "Search",
                's',
                vec![
                    item("&Find…", Find),
                    item("&Selected Text", SelectedText),
                    item("&Repeat Last Find", FindNext),
                    item("&Change…", Replace),
                ],
            ),
            menu(
                "Run",
                'r',
                vec![
                    item("&Start", Start),
                    item("&Restart", Restart),
                    item("&Continue", Continue),
                    item("&Pause (Ctrl+Break)", Pause),
                    item("Modify COMMAND&$…", CommandLine),
                    sep(),
                    item("Make &EXE File…", MakeExe),
                    item("Make &Library…", MakeLibrary),
                    sep(),
                    item("Set Start-&up File…", Startup),
                ],
            ),
            menu(
                "Debug",
                'd',
                vec![
                    item("&Add Watch…", AddWatch),
                    item("&Instant Watch…", InstantWatch),
                    item("&Watchpoint…", Watchpoint),
                    item("&Delete Watch…", DeleteWatch),
                    item("Delete A&ll Watch", DeleteWatches),
                    sep(),
                    item("&Trace On", Trace),
                    item("&History On", History),
                    sep(),
                    item("Toggle &Breakpoint", Breakpoint),
                    item("&Clear All Breakpoints", ClearBreakpoints),
                    item("Break on &Errors", BreakErrors),
                    item("Set &Next Statement", SetStatement),
                ],
            ),
        ]);
    }
    result.push(menu(
        "Options",
        'o',
        vec![
            item("&Display…", Display),
            item("Set &Paths…", Paths),
            item("&Right Mouse…", RightMouse),
            item("&Save…", SaveOptions),
            item("S&yntax Checking", SyntaxChecking),
        ],
    ));
    result.push(if designer {
        menu(
            "Window",
            'w',
            vec![
                item("&Color Palette", Palette),
                item("&Menu Design Window", MenuDesign),
                item("&Toolbox", Toolbox),
                item("&Help", HelpWindow),
            ],
        )
    } else {
        menu(
            "Window",
            'w',
            vec![
                item("&New Window", NewWindow),
                item("&Arrange All", Arrange),
                sep(),
                item("&Calls", Calls),
                item("&Debug", Debug),
                item("&Help", HelpWindow),
                item("&Immediate", Immediate),
                item("&Output", Output),
                item("&Project", Project),
                sep(),
            ],
        )
    });
    result.push(menu(
        "Help",
        'h',
        vec![
            item("&Index", HelpIndex),
            item("&Contents", HelpContents),
            sep(),
            item("&Keyboard", Keyboard),
            sep(),
            item("&Topic", Topic),
            item("&Using Help", UsingHelp),
            item("Tuto&rial", Tutorial),
            sep(),
            item("&About…", About),
        ],
    ));
    result
}
