module menu.browser.select;

/*  class BrowserHighlightSelect
 *
 *      Guarantee for all inherited classes: onFileHighlight will be called
 *      for every file on which possibly on_file_select could be called later.
 *      Whenever on_file_select is called, onFileHighlight has been called
 *      on the same filename before, and no other onFileHighlight calls have
 *      been made in the meantime.
 *      Implemented by private BrowserHighlightSelect._fileRecent.
 */

import std.conv;
static import std.file;

import optional;

import file.option; // hotkeys
import file.filename;
import file.language;
import file.log;
import gui;
import gui.picker;
import hardware.semantic; // up/down change of highlighted file
import hardware.sound;
import menu.browser.highli;

class BrowserHighlightSelect : BrowserHighlight {
private:
    // highlight, not select. May be in different dir. Never a directory.
    MutFilename _fileRecent;

    // Last-highlit dir or file with up/down keys.
    // We need this because it may point to dirs, not only to files as
    // _fileRecent would allow.
    // _upDownToCanBeNull cannot be Optional because Optional doesn't behave
    // well with Rebindable!Filename == MutFilename: Both together corrupt RAM.
    MutFilename _upDownToCanBeNull;

    TextButton _buttonPlay;

public:
    // See constructor comment in menu.browser.highli.
    this(SomePickerConfig)(
        in string title,
        Filename  baseDir,
        SomePickerConfig cfg
    ) {
        super(title, baseDir, cfg);
        _buttonPlay = new TextButton(new Geom(infoX, 20,
            infoXl/2, 40, From.BOTTOM_LEFT), Lang.browserPlay.transl);
        _buttonPlay.hotkey = file.option.keyMenuOkay;
        addChildren(_buttonPlay);
    }

    @property Filename fileRecent() inout { return _fileRecent; }

    final void highlightNone()
    {
        _buttonPlay.hide();
        // keep _fileRecent as it is, we might highlight that again later
        onHighlightNone();
    }

    final void highlight(Filename fn)
    in { assert (fn, "call highlightNone() instead"); }
    body {
        if (super.navigateToAndHighlightFile(fn)) {
            _buttonPlay.show();
            _fileRecent = fn;
            _upDownToCanBeNull = fn;
            onHighlight(fn);
        }
        else
            highlightNone();
    }

protected:
    abstract void onHighlightNone();
    abstract void onHighlight(Filename);
    abstract void onPlay(Filename);

    final void buttonPlayYFromBottom(in float newY)
    {
        _buttonPlay.move(_buttonPlay.geom.x, newY);
    }

    final void buttonPlayText(in string s) { _buttonPlay.text = s; }

    final void deleteFileRecentHighlightNeighbor()
    {
        Optional!Filename opt = super.deleteFileHighlightNeighbor(_fileRecent);
        // Super class only tells the picker to highlight the neighbor.
        // We, as a browser, must highlight the neighbor, too. Bad OO? <_<
        if (opt.empty)
            highlightNone();
        else
            highlight(opt.unwrap);
        _upDownToCanBeNull = null;
        playLoud(Sound.SCISSORS);
    }

    final override void onPickerExecuteFile(Filename executeFileFilename)
    {
        MutFilename clicked = executeFileFilename;
        assert (clicked !is null);
        if (clicked != _fileRecent)
            highlight(clicked);
        else
            onPlay(_fileRecent);
    }

    final override void onPickerExecuteDir()
    {
        highlightIfInCurrentDir(_fileRecent);
        _upDownToCanBeNull = null;
    }

    override void calcSelf()
    {
        super.calcSelf();
        if (gotoMainMenu) {
            return;
        }
        else if (_buttonPlay.execute) {
            assert (_fileRecent !is null);
            onPlay(_fileRecent);
        }
        else if (keyMenuOkay.keyTapped && _upDownToCanBeNull) {
            super.navigateTo(_upDownToCanBeNull);
            highlightIfInCurrentDir(_fileRecent);
            _upDownToCanBeNull = null;
        }
        else if (keyMenuMoveByTotal() != 0) {
            _upDownToCanBeNull = super.moveHighlightBy(
                _upDownToCanBeNull ? _upDownToCanBeNull
                : _fileRecent, keyMenuMoveByTotal);
            highlightIfInCurrentDir(_upDownToCanBeNull); // may be null here
        }
    }

private:
    @property void highlightIfInCurrentDir(Filename fn)
    {
        if (fn && fn.dirRootless == currentDir.dirRootless)
            highlight(fn);
        else
            highlightNone();
    }
}
