// subtitleeditor -- a tool to create or edit subtitle
//
// https://kitone.github.io/subtitleeditor/
// https://github.com/kitone/subtitleeditor/
//
// Copyright @ 2005-2018, kitone
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <extension/action.h>
#include <gui/dialogfilechooser.h>
#include <player.h>
#include <utility.h>

// Video Player Management
class VideoPlayerManagement : public Action {
 public:
  VideoPlayerManagement() {
    activate();
    update_ui();
  }

  ~VideoPlayerManagement() {
    deactivate();
  }

  void activate() {
    se_dbg(SE_DBG_PLUGINS);

    // actions
    action_group = Gtk::ActionGroup::create("VideoPlayerManagement");

    // Already create in MenuBar.cc
    action_group->add(Gtk::Action::create("menu-video", _("_Video")));

    action_group->add(Gtk::Action::create("video-player/open", Gtk::Stock::OPEN,
                                          "",  // _("_Open Media"),
                                          _("Open a multimedia file")),
                      Gtk::AccelKey("<Shift><Control>M"),
                      sigc::mem_fun(*this, &VideoPlayerManagement::on_open));

    action_group->add(
        Gtk::Action::create("video-player/close", Gtk::Stock::CLOSE,
                            "",  // _("_Close Media"),
                            _("Close a multimedia file")),
        Gtk::AccelKey("<Shift><Control>C"),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_close));

    action_group->add(
        Gtk::Action::create("video-player/play", Gtk::Stock::MEDIA_PLAY),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play));

    action_group->add(
        Gtk::Action::create("video-player/pause", Gtk::Stock::MEDIA_PAUSE),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_pause));

    action_group->add(
        Gtk::Action::create("video-player/play-pause", _("_Play / Pause"),
                            _("Play or make a pause")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_pause));

    // Seek Backwards
    action_group->add(Gtk::Action::create("video-player/menu-skip-backwards",
                                          Gtk::Stock::MEDIA_REWIND,
                                          _("Skip _Backwards")));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-frame",
                            Gtk::Stock::MEDIA_REWIND, _("Frame"),
                            _("Frame skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            FRAME));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-tiny",
                            Gtk::Stock::MEDIA_REWIND, _("Tiny"),
                            _("Tiny skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            TINY));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-very-short",
                            Gtk::Stock::MEDIA_REWIND, _("Very Short"),
                            _("Very short skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            VERY_SHORT));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-short",
                            Gtk::Stock::MEDIA_REWIND, _("Short"),
                            _("Short skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            SHORT));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-medium",
                            Gtk::Stock::MEDIA_REWIND, _("Medium"),
                            _("Medium skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            MEDIUM));

    action_group->add(
        Gtk::Action::create("video-player/skip-backwards-long",
                            Gtk::Stock::MEDIA_REWIND, _("Long"),
                            _("Long skip backwards")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_backwards),
            LONG));

    // Seek Forward
    action_group->add(Gtk::Action::create("video-player/menu-skip-forward",
                                          Gtk::Stock::MEDIA_FORWARD,
                                          _("Skip _Forward")));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-frame",
                            Gtk::Stock::MEDIA_FORWARD, _("Frame"),
                            _("Frame skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            FRAME));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-tiny",
                            Gtk::Stock::MEDIA_FORWARD, _("Tiny"),
                            _("Tiny skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            TINY));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-very-short",
                            Gtk::Stock::MEDIA_FORWARD, _("Very Short"),
                            _("Very short skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            VERY_SHORT));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-short",
                            Gtk::Stock::MEDIA_FORWARD, _("Short"),
                            _("Short skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            SHORT));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-medium",
                            Gtk::Stock::MEDIA_FORWARD, _("Medium"),
                            _("Medium skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            MEDIUM));

    action_group->add(
        Gtk::Action::create("video-player/skip-forward-long",
                            Gtk::Stock::MEDIA_FORWARD, _("Long"),
                            _("Long skip forward")),
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::on_skip_forward),
            LONG));

    // Rate Slower & Faster
    action_group->add(Gtk::Action::create("video-player/menu-rate", _("Rate"),
                                          _("Define the playback rate")));

    action_group->add(
        Gtk::Action::create("video-player/rate-slower", _("_Slower"),
                            _("Define the playback rate")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_playback_rate_slower));

    action_group->add(
        Gtk::Action::create("video-player/rate-faster", _("_Faster"),
                            _("Define the playback rate")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_playback_rate_faster));

    action_group->add(
        Gtk::Action::create("video-player/rate-normal", _("_Normal"),
                            _("Define the playback rate")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_playback_rate_normal));

    // Seek to Selection
    action_group->add(
        Gtk::Action::create("video-player/seek-to-selection",
                            _("_Seek To Selection"),
                            _("Seek to the first selected subtitle")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_seek_to_selection));

    // Seek to Selection End
    action_group->add(
        Gtk::Action::create("video-player/seek-to-selection-end",
                            _("_Seek To Selection End"),
                            _("Seek to the end of the last selected subtitle")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_seek_to_selection_end));

    // Repeat
    bool video_repeat_state = cfg::get_boolean("video-player", "repeat");

    action_group->add(
        Gtk::ToggleAction::create("video-player/repeat", _("_Repeat"),
                                  _("Enable or disable the repeat mode"),
                                  video_repeat_state),
        sigc::mem_fun(*this,
                      &VideoPlayerManagement::on_video_player_repeat_toggled));

    // Play Subtitle
    action_group->add(
        Gtk::Action::create(
            "video-player/play-previous-subtitle", Gtk::Stock::MEDIA_PREVIOUS,
            _("Play _Previous Subtitle"),
            _("Play previous subtitle from the first selected subtitle")),
        sigc::mem_fun(*this,
                      &VideoPlayerManagement::on_play_previous_subtitle));

    action_group->add(
        Gtk::Action::create("video-player/play-current-subtitle",
                            Gtk::Stock::MEDIA_PLAY, _("Play _Selection"),
                            _("Play the selected subtitle")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_current_subtitle));

    action_group->add(
        Gtk::Action::create(
            "video-player/play-next-subtitle", Gtk::Stock::MEDIA_NEXT,
            _("Play _Next Subtitle"),
            _("Play next subtitle from the first selected subtitle")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_next_subtitle));

    // Play Second
    action_group->add(
        Gtk::Action::create(
            "video-player/play-previous-second", _("Play Previous Second"),
            _("Play the second preceding the first selected subtitle")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_previous_second));

    action_group->add(
        Gtk::Action::create(
            "video-player/play-first-second", _("Play First Second"),
            _("Play the first second of the subtitle currently selected")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_first_second));

    action_group->add(
        Gtk::Action::create(
            "video-player/play-last-second", _("Play Last Second"),
            _("Play the last second of the subtitle currently selected")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_last_second));

    action_group->add(
        Gtk::Action::create(
            "video-player/play-next-second", _("Play Next Second"),
            _("Play the second following the subtitle currently selected")),
        sigc::mem_fun(*this, &VideoPlayerManagement::on_play_next_second));

    // Display Video Player
    bool vp_display_state = cfg::get_boolean("video-player", "display");

    action_group->add(
        Gtk::ToggleAction::create(
            "video-player/display", _("_Video Player"),
            _("Show or hide the video player in the current window"),
            vp_display_state),
        sigc::mem_fun(*this,
                      &VideoPlayerManagement::on_video_player_display_toggled));

    action_group->add(Gtk::Action::create("menu-audio-track", _("Audio Track"),
                                          _("Choice of an audio track")));

    // Recent files
    Glib::RefPtr<Gtk::RecentAction> recentAction = Gtk::RecentAction::create(
        "video-player/recent-files", _("_Recent Files"));

    Glib::RefPtr<Gtk::RecentFilter> filter = Gtk::RecentFilter::create();
    filter->set_name("subtitleeditor");
    filter->add_group("subtitleeditor-video-player");
    recentAction->set_filter(filter);
    recentAction->set_show_icons(false);
    recentAction->set_show_numbers(true);
    recentAction->set_show_tips(true);
    // recentAction->set_show_not_found(false);
    recentAction->set_sort_type(Gtk::RECENT_SORT_MRU);

    recentAction->signal_item_activated().connect(
        sigc::mem_fun(*this, &VideoPlayerManagement::on_recent_item_activated));
    action_group->add(recentAction);

    // ui
    Glib::RefPtr<Gtk::UIManager> ui = get_ui_manager();

    ui->insert_action_group(action_group);

    Glib::ustring submenu = R"(
      <ui>
        <menubar name='menubar'>
          <menu name='menu-video' action='menu-video'>
            <placeholder name='video-player-management'>
              <menuitem action='video-player/open'/>
              <menuitem action='video-player/recent-files'/>
              <menuitem action='video-player/close'/>
              <separator/>
              <menu action='menu-audio-track'>
                <placeholder name='audio-track-placeholder'/>
              </menu>
              <separator/>
              <menuitem action='video-player/play'/>
              <menuitem action='video-player/pause'/>
              <menuitem action='video-player/play-pause'/>
              <separator/>
              <menu action='video-player/menu-skip-forward'>
                <menuitem action='video-player/skip-forward-frame'/>
                <menuitem action='video-player/skip-forward-tiny'/>
                <menuitem action='video-player/skip-forward-very-short'/>
                <menuitem action='video-player/skip-forward-short'/>
                <menuitem action='video-player/skip-forward-medium'/>
                <menuitem action='video-player/skip-forward-long'/>
              </menu>
              <menu action='video-player/menu-skip-backwards'>
                <menuitem action='video-player/skip-backwards-frame'/>
                <menuitem action='video-player/skip-backwards-tiny'/>
                <menuitem action='video-player/skip-backwards-very-short'/>
                <menuitem action='video-player/skip-backwards-short'/>
                <menuitem action='video-player/skip-backwards-medium'/>
                <menuitem action='video-player/skip-backwards-long'/>
              </menu>
              <menu action='video-player/menu-rate'>
                <menuitem action='video-player/rate-slower'/>
                <menuitem action='video-player/rate-faster'/>
                <menuitem action='video-player/rate-normal'/>
              </menu>
              <separator/>
              <menuitem action='video-player/seek-to-selection'/>
              <menuitem action='video-player/seek-to-selection-end'/>
              <separator/>
              <menuitem action='video-player/play-current-subtitle'/>
              <menuitem action='video-player/play-next-subtitle'/>
              <menuitem action='video-player/play-previous-subtitle'/>
              <menuitem action='video-player/repeat'/>
              <separator/>
              <menuitem action='video-player/play-previous-second'/>
              <menuitem action='video-player/play-first-second'/>
              <menuitem action='video-player/play-last-second'/>
              <menuitem action='video-player/play-next-second'/>
            </placeholder>
          </menu>
        </menubar>
      </ui>
    )";

    ui_id = ui->add_ui_from_string(submenu);
    ui_id_audio = ui->new_merge_id();

    // Show/Hide video player
    ui->add_ui(ui_id, "/menubar/menu-view/display-placeholder",
               "video-player/display", "video-player/display");

    //
    player()->signal_message().connect(
        sigc::mem_fun(*this, &VideoPlayerManagement::on_player_message));

    cfg::signal_changed("video-player")
        .connect(sigc::mem_fun(
            *this, &VideoPlayerManagement::on_config_video_player_changed));
  }

  void deactivate() {
    se_dbg(SE_DBG_PLUGINS);

    Glib::RefPtr<Gtk::UIManager> ui = get_ui_manager();

    remove_menu_audio_track();
    ui->remove_ui(ui_id);
    ui->remove_action_group(action_group);
  }

  // Update the user interface with the state of subtitle (has document)
  // and the state of the player (has media)
  void update_ui() {
    se_dbg(SE_DBG_PLUGINS);

    bool has_doc = (get_current_document() != NULL);
    bool has_media = player()->get_state() != Player::NONE;

#define SET_SENSITIVE(action, state)                                  \
  {                                                                   \
    Glib::RefPtr<Gtk::Action> act = action_group->get_action(action); \
    if (act)                                                          \
      act->set_sensitive(state);                                      \
    else                                                              \
      g_warning(action);                                              \
  }

    SET_SENSITIVE("video-player/play", has_media);
    SET_SENSITIVE("video-player/close", has_media);
    SET_SENSITIVE("video-player/pause", has_media);
    SET_SENSITIVE("video-player/play-pause", has_media);

    SET_SENSITIVE("video-player/rate-slower", has_media);
    SET_SENSITIVE("video-player/rate-faster", has_media);
    SET_SENSITIVE("video-player/rate-normal", has_media);

    SET_SENSITIVE("video-player/skip-forward-frame", has_media);
    SET_SENSITIVE("video-player/skip-forward-tiny", has_media);
    SET_SENSITIVE("video-player/skip-forward-very-short", has_media);
    SET_SENSITIVE("video-player/skip-forward-short", has_media);
    SET_SENSITIVE("video-player/skip-forward-medium", has_media);
    SET_SENSITIVE("video-player/skip-forward-long", has_media);

    SET_SENSITIVE("video-player/skip-backwards-frame", has_media);
    SET_SENSITIVE("video-player/skip-backwards-tiny", has_media);
    SET_SENSITIVE("video-player/skip-backwards-very-short", has_media);
    SET_SENSITIVE("video-player/skip-backwards-short", has_media);
    SET_SENSITIVE("video-player/skip-backwards-medium", has_media);
    SET_SENSITIVE("video-player/skip-backwards-long", has_media);

    SET_SENSITIVE("video-player/repeat", has_media);

    SET_SENSITIVE("video-player/seek-to-selection", has_media && has_doc);
    SET_SENSITIVE("video-player/seek-to-selection-end", has_media && has_doc);

    SET_SENSITIVE("video-player/play-previous-subtitle", has_media && has_doc);
    SET_SENSITIVE("video-player/play-current-subtitle", has_media && has_doc);
    SET_SENSITIVE("video-player/play-next-subtitle", has_media && has_doc);

    SET_SENSITIVE("video-player/play-previous-second", has_media && has_doc);
    SET_SENSITIVE("video-player/play-first-second", has_media && has_doc);
    SET_SENSITIVE("video-player/play-last-second", has_media && has_doc);
    SET_SENSITIVE("video-player/play-next-second", has_media && has_doc);

#undef SET_SENSITIVE
  }

  // Check the state of the player.
  // Display the video player if need and update the menu.
  void on_player_message(Player::Message msg) {
    if (msg == Player::STATE_NONE || msg == Player::STREAM_READY) {
      // only if the player is enable or disable
      // don't update if is playing or paused

      if (msg == Player::STATE_NONE) {
        remove_menu_audio_track();
      } else if (msg == Player::STREAM_READY) {
        build_menu_audio_track();
        add_in_recent_manager(player()->get_uri());
      }
      update_ui();
      // If need, ask to display the video player
      if (msg == Player::STREAM_READY) {
        if (cfg::get_boolean("video-player", "display") == false) {
          cfg::set_boolean("video-player", "display", true);
        }
      }
    } else if (msg == Player::STREAM_AUDIO_CHANGED) {
      // The player emit the signal audio changed.
      // We update the current audio if need.
      update_audio_track_from_player();
    }
  }

  // Show or hide the video player, update hte config.
  void on_video_player_display_toggled() {
    Glib::RefPtr<Gtk::ToggleAction> action =
        Glib::RefPtr<Gtk::ToggleAction>::cast_static(
            action_group->get_action("video-player/display"));
    if (action) {
      bool state = action->get_active();
      if (cfg::get_boolean("video-player", "display") != state) {
        cfg::set_boolean("video-player", "display", state);
      }
    }
  }

  // The state of reapet has changed, update the config.
  void on_video_player_repeat_toggled() {
    Glib::RefPtr<Gtk::ToggleAction> action =
        Glib::RefPtr<Gtk::ToggleAction>::cast_static(
            action_group->get_action("video-player/repeat"));
    if (action) {
      bool state = action->get_active();
      if (cfg::get_boolean("video-player", "repeat") != state) {
        cfg::set_boolean("video-player", "repeat", state);
      }
    }
  }

  // The video player config has changed.
  // Update the menu.
  void on_config_video_player_changed(const Glib::ustring &key,
                                      const Glib::ustring &value) {
    if (key == "display") {
      bool state = utility::string_to_bool(value);

      Glib::RefPtr<Gtk::ToggleAction> action =
          Glib::RefPtr<Gtk::ToggleAction>::cast_static(
              action_group->get_action("video-player/display"));
      if (action) {
        if (action->get_active() != state)
          action->set_active(state);
      }
    } else if (key == "repeat") {
      bool state = utility::string_to_bool(value);

      Glib::RefPtr<Gtk::ToggleAction> action =
          Glib::RefPtr<Gtk::ToggleAction>::cast_static(
              action_group->get_action("video-player/repeat"));
      if (action) {
        if (action->get_active() != state)
          action->set_active(state);
      }
    }
  }

  // We remove the ActionGroup "VideoPlayerManagementAudioTrack"
  // and the ui.
  void remove_menu_audio_track() {
    se_dbg(SE_DBG_PLUGINS);
    if (action_group_audio) {
      get_ui_manager()->remove_ui(ui_id_audio);
      get_ui_manager()->remove_action_group(action_group_audio);
      action_group_audio.reset();
    }
  }

  // Remove old menu items (tracks) and actions
  // and create a new one.
  void build_menu_audio_track() {
    se_dbg(SE_DBG_PLUGINS);
    // We clean the old audio menu
    remove_menu_audio_track();
    // Create audio actions
    action_group_audio =
        Gtk::ActionGroup::create("VideoPlayerManagementAudioTrack");
    get_ui_manager()->insert_action_group(action_group_audio);

    Gtk::RadioButtonGroup group;
    // A default track "Auto"
    add_audio_track_entry(group, "audio-track-auto", _("Auto"), -1);
    // Now we build an entry for each audio track
    gint n_audio = player()->get_n_audio();
    for (gint i = 0; i < n_audio; ++i) {
      Glib::ustring track = Glib::ustring::compose("audio-track-%1", i);
      Glib::ustring track_name = Glib::ustring::compose("Track %1", i + 1);

      add_audio_track_entry(group, track, track_name, i);
    }
    // active the good track
    update_audio_track_from_player();
  }

  // Update the radio item with the current audio track
  // from the player.
  void update_audio_track_from_player() {
    se_dbg(SE_DBG_PLUGINS);

    if (!action_group_audio)
      return;

    gint current_audio = player()->get_n_audio();
    // If it's < -1, we choose the track "Auto"
    Glib::ustring track_action =
        (current_audio < 0)
            ? "audio-track-auto"
            : Glib::ustring::compose("audio-track-%1", current_audio);

    Glib::RefPtr<Gtk::ToggleAction> action =
        Glib::RefPtr<Gtk::ToggleAction>::cast_static(
            action_group_audio->get_action(track_action));
    if (action) {
      if (action->get_active() == false)  // Only if need
        action->set_active(true);
    }
  }

  // Create a new track entry (action and menu item).
  void add_audio_track_entry(Gtk::RadioButtonGroup &group,
                             const Glib::ustring &track_action,
                             const Glib::ustring &track_label,
                             gint track_number) {
    // action
    Glib::RefPtr<Gtk::RadioAction> action =
        Gtk::RadioAction::create(group, track_action, track_label);
    action_group_audio->add(
        action,
        sigc::bind(
            sigc::mem_fun(*this, &VideoPlayerManagement::set_current_audio),
            track_number, action));
    // menuitem
    get_ui_manager()->add_ui(ui_id_audio,
                             "/menubar/menu-video/video-player-management/"
                             "menu-audio-track/audio-track-placeholder",
                             track_action, track_action, Gtk::UI_MANAGER_AUTO,
                             false);
    // update
    get_ui_manager()->ensure_update();
  }

  // The user choose a new track from the track menu,
  // we update the player.
  void set_current_audio(gint track, Glib::RefPtr<Gtk::RadioAction> action) {
    se_dbg(SE_DBG_PLUGINS);
    // Switching a toggle button launch two signal,
    // one for the button toggle to unactivated and an other to activated.
    // We need to check only for the signal activate.
    if (!action->get_active())
      return;
    player()->set_current_audio(track);
  }

 protected:
  // Return the GStreamer Player.
  Player *player() {
    return get_subtitleeditor_window()->get_player();
  }

  // Open the dialog "Open Video" and initialize the player with the new uri.
  void on_open() {
    DialogOpenVideo ui;

    if (ui.run() == Gtk::RESPONSE_OK) {
      ui.hide();

      Glib::ustring uri = ui.get_uri();

      player()->open(uri);

      add_in_recent_manager(uri);
    }
  }

  // Close the player
  void on_close() {
    player()->close();
  }

  // Reinitialize the current position for disable the repeat method
  // and sets the player state to playing.
  void on_play() {
    player()->seek(player()->get_position());
    player()->play();
  }

  // Sets the player state to paused.
  void on_pause() {
    player()->pause();
  }

  // Toggled the player state.
  // Paused to playing or playing to paused.
  void on_play_pause() {
    if (player()->is_playing()) {
      player()->pause();
    } else {
      player()->seek(player()->get_position());
      player()->play();
    }
  }

  // Skip type, look the config for the value of the time.
  enum SkipType { FRAME, TINY, VERY_SHORT, SHORT, MEDIUM, LONG };

  long get_skip_as_msec(SkipType skip) {
    if (skip == FRAME) {
      int numerator = 0, denominator = 0;
      if (player()->get_framerate(&numerator, &denominator) > 0)
        return denominator * 1000 / numerator;
    } else if (skip == TINY) {
      return cfg::get_int("video-player", "skip-tiny");
    } else if (skip == VERY_SHORT) {
      return cfg::get_int("video-player", "skip-very-short") * 1000;
    } else if (skip == SHORT) {
      return cfg::get_int("video-player", "skip-short") * 1000;
    } else if (skip == MEDIUM) {
      return cfg::get_int("video-player", "skip-medium") * 1000;
    } else if (skip == LONG) {
      return cfg::get_int("video-player", "skip-long") * 1000;
    }
    return 0;
  }

  // Make a skip backwards depending on the type.
  void on_skip_backwards(SkipType skip) {
    long newpos = player()->get_position() - get_skip_as_msec(skip);

    player()->seek(newpos);
  }

  // make a skip forward depending on the type.
  void on_skip_forward(SkipType skip) {
    long newpos = player()->get_position() + get_skip_as_msec(skip);

    player()->seek(newpos);
  }

  // Increase the playback rate.
  void on_playback_rate_faster() {
    double rate = player()->get_playback_rate();

    rate += 0.1;

    player()->set_playback_rate(rate);
  }

  // Decreases the playback rate.
  void on_playback_rate_slower() {
    double rate = player()->get_playback_rate();

    rate -= 0.1;

    player()->set_playback_rate(rate);
  }

  // Sets the playback rate to 1.0 (default).
  void on_playback_rate_normal() {
    player()->set_playback_rate(1.0);
  }

  // Seek to the first selected subtitle.
  // The state of the player isn't modified.
  void on_seek_to_selection() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      player()->seek(selected.get_start().totalmsecs);
    }
  }

  // Seek to the last selected subtitle.
  // The state of the player isn't modified.
  void on_seek_to_selection_end() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_last_selected();
    if (selected) {
      player()->seek(selected.get_end().totalmsecs);
    }
  }

  // Method for playing subtitle.

  // Select and play the previous subtitle.
  // Repeat is supported.
  void on_play_previous_subtitle() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      Subtitle previous = doc->subtitles().get_previous(selected);
      if (previous) {
        doc->subtitles().select(previous);
        player()->play_subtitle(previous);
      }
    }
  }

  // Play the current subtitle.
  // Repeat is supported.
  void on_play_current_subtitle() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      player()->play_subtitle(selected);
    }
  }

  // Select and play the next subtitle.
  // Repeat is supported.
  void on_play_next_subtitle() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      Subtitle next = doc->subtitles().get_next(selected);
      if (next) {
        doc->subtitles().select(next);
        player()->play_subtitle(next);
      }
    }
  }

  // Method for playing second.

  // Play the second preceding the first selected subtitle.
  void on_play_previous_second() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      SubtitleTime start = selected.get_start() - SubtitleTime(0, 0, 1, 0);
      SubtitleTime end = selected.get_start();

      player()->play_segment(start, end);
    }
  }

  // Play the first second of the subtitle currently selected.
  void on_play_first_second() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      SubtitleTime start = selected.get_start();
      SubtitleTime end = selected.get_start() + SubtitleTime(0, 0, 1, 0);

      player()->play_segment(start, end);
    }
  }

  // Play the last second of the subtitle currently selected
  void on_play_last_second() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      SubtitleTime start = selected.get_end() - SubtitleTime(0, 0, 1, 0);
      SubtitleTime end = selected.get_end();

      player()->play_segment(start, end);
    }
  }

  // Play the second following the subtitle currently selected
  void on_play_next_second() {
    Document *doc = get_current_document();

    Subtitle selected = doc->subtitles().get_first_selected();
    if (selected) {
      SubtitleTime start = selected.get_end();
      SubtitleTime end = selected.get_end() + SubtitleTime(0, 0, 1, 0);

      player()->play_segment(start, end);
    }
  }

  void add_in_recent_manager(const Glib::ustring &uri) {
    se_dbg_msg(SE_DBG_PLUGINS, "uri=%s", uri.c_str());

    Gtk::RecentManager::Data data;
    // data.mime_type = "subtitle/";
    data.app_name = Glib::get_application_name();
    data.app_exec = Glib::get_prgname();
    data.groups.push_back("subtitleeditor-video-player");
    data.is_private = false;
    Gtk::RecentManager::get_default()->add_item(uri, data);
  }

  // Open a recent video
  void on_recent_item_activated() {
    se_dbg(SE_DBG_PLUGINS);

    Glib::RefPtr<Gtk::Action> action =
        action_group->get_action("video-player/recent-files");

    Glib::RefPtr<Gtk::RecentAction> recentAction =
        Glib::RefPtr<Gtk::RecentAction>::cast_static(action);

    Glib::RefPtr<Gtk::RecentInfo> cur = recentAction->get_current_item();
    if (cur) {
      se_dbg_msg(SE_DBG_PLUGINS, "uri=%s", cur->get_uri().c_str());

      player()->open(cur->get_uri());
    }
  }

 protected:
  Gtk::UIManager::ui_merge_id ui_id;
  Gtk::UIManager::ui_merge_id ui_id_audio;
  Glib::RefPtr<Gtk::ActionGroup> action_group;
  Glib::RefPtr<Gtk::ActionGroup> action_group_audio;
};

REGISTER_EXTENSION(VideoPlayerManagement)
