# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline 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.
#
# Timeline 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 Timeline.  If not, see <http://www.gnu.org/licenses/>.


import timelinelib.wxgui.frames.mainframe.menus as mid
from timelinelib.wxgui.frames.mainframe.menus.menubase import MenuBase
from timelinelib.wxgui.dialogs.editevent.view import open_create_event_editor
from timelinelib.db.utils import safe_locking
from timelinelib.wxgui.dialogs.eventduration.view import open_measure_duration_dialog
from timelinelib.wxgui.dialogs.eventsmove.view import open_events_move_dialog
from timelinelib.wxgui.dialogs.eraseditor.view import oped_edit_eras_dialog
from timelinelib.wxgui.dialogs.duplicateevent.view import open_duplicate_event_dialog_for_event
from timelinelib.wxgui.dialogs.setcategory.view import open_set_category_dialog_for_selected_events
from timelinelib.wxgui.dialogs.setcategory.view import open_set_category_dialog
from timelinelib.wxgui.utils import display_information_message
from timelinelib.wxgui.dialogs.editevent.view import open_event_editor_for
from timelinelib.wxgui.dialogs.milestone.view import open_milestone_editor_for
from timelinelib.config.menuiteminfo import MenuItemInfo
from timelinelib.config.shortcut import CTRL_MODIFIER, LABEL_TIMELINE, ALT_MODIFIER


REQUIRING_TIMELINE = (mid.ID_MEASURE_DURATION,)
REQUIRING_WRITEABLE_TIMELINE = (mid.ID_CREATE_EVENT, mid.ID_EDIT_EVENT, mid.ID_CREATE_MILESTONE, mid.ID_DUPLICATE_EVENT,
                                mid.ID_SET_CATEGORY_ON_SELECTED, mid.ID_MOVE_EVENT_UP, mid.ID_MOVE_EVENT_DOWN,
                                mid.ID_MOVE_EVENTS,
                                mid.ID_MEASURE_DISTANCE, mid.ID_SET_CATEGORY_ON_WITHOUT,
                                mid.ID_SET_READONLY, mid.ID_EDIT_ERAS, mid.ID_COMPRESS, mid.ID_UNDO, mid.ID_REDO)
MENU_LABELS = {
    mid.ID_CREATE_EVENT: _("Create &Event") + "...",
    mid.ID_EDIT_EVENT: _("&Edit Selected Event") + "...",
    mid.ID_DUPLICATE_EVENT: _("&Duplicate Selected Event") + "...",
    mid.ID_SET_CATEGORY_ON_SELECTED: _("Set Category on Selected Events") + "...",
    mid.ID_MOVE_EVENT_UP: _("Move event up"),
    mid.ID_MOVE_EVENT_DOWN: _("Move event down"),
    mid.ID_MOVE_EVENTS: _("Move events") + "...",
    mid.ID_CREATE_MILESTONE: _("Create &Milestone") + "...",
    mid.ID_COMPRESS: _("&Compress timeline Events"),
    mid.ID_MEASURE_DISTANCE: _("&Measure Distance between two Events") + "...",
    mid.ID_MEASURE_DURATION: _("Measure Duration of Events") + "...",
    mid.ID_SET_CATEGORY_ON_WITHOUT: _("Set Category on events &without category") + "...",
    mid.ID_EDIT_ERAS: _("Edit Era's") + "...",
    mid.ID_SET_READONLY: _("&Read Only"),
    mid.ID_UNDO: _("&Undo"),
    mid.ID_REDO: _("&Redo"),
}

class TimelineMenu(MenuBase):
    """The Timeline menu (a wx.Menu)."""

    def __init__(self, main_frame, timeline_panel):
        MenuBase.__init__(self, main_frame, REQUIRING_TIMELINE,
                          requiring_writeable_timeline=REQUIRING_WRITEABLE_TIMELINE)
        self._menu_items_info = self._create_menu_items_info(main_frame, timeline_panel)
        self._create_menu()
        self._bind_event_handlers()
        self._register_shortcuts()
        self._register_menus_requiring_timeline()

    def _create_menu_items_info(self, main_frame, timeline_panel):
        return [
            MenuItemInfo(wxid=mid.ID_CREATE_EVENT,
                         event_handler=lambda evt: open_create_event_editor(main_frame.controller, main_frame, main_frame.config, main_frame.timeline),
                         config_key="shortcut_create_event",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_CREATE_EVENT],
                         sort_order=1),
            MenuItemInfo(wxid=mid.ID_EDIT_EVENT,
                         event_handler=lambda evt: self._open_event_editor(),
                         config_key="shortcut_edit_event",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_EDIT_EVENT],
                         sort_order=2),
            MenuItemInfo(wxid=mid.ID_DUPLICATE_EVENT,
                         event_handler=lambda evt: open_duplicate_event_dialog_for_event(main_frame),
                         config_key="shortcut_duplicate_event",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_DUPLICATE_EVENT],
                         sort_order=3),
            MenuItemInfo(wxid=mid.ID_SET_CATEGORY_ON_SELECTED,
                         event_handler=lambda evt: safe_locking(main_frame.controller, lambda: open_set_category_dialog_for_selected_events(main_frame)),
                         config_key="shortcut_set_category_on_selected",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_SET_CATEGORY_ON_SELECTED],
                         sort_order=4),
            MenuItemInfo(wxid=mid.ID_MOVE_EVENT_UP,
                         event_handler=lambda evt: timeline_panel.move_selected_event_up(),
                         config_key="shortcut_move_event_up",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_MOVE_EVENT_UP],
                         shortcut_key="Up",
                         shortcut_modifier=ALT_MODIFIER,
                         sort_order=5),
            MenuItemInfo(wxid=mid.ID_MOVE_EVENT_DOWN,
                         event_handler=lambda evt: timeline_panel.move_selected_event_down(),
                         config_key="shortcut_move_event_down",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_MOVE_EVENT_DOWN],
                         shortcut_key="Down",
                         shortcut_modifier=ALT_MODIFIER,
                         sort_order=6),
            MenuItemInfo(wxid=mid.ID_MOVE_EVENTS,
                         event_handler=lambda evt: open_events_move_dialog(main_frame),
                         config_key="shortcut_events_move",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_MOVE_EVENTS],
                         sort_order=7),
            MenuItemInfo(wxid=mid.ID_CREATE_MILESTONE,
                         event_handler=lambda evt: open_milestone_editor_for(main_frame),
                         config_key="shortcut_create_milestone",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_CREATE_MILESTONE],
                         sort_order=8),
            MenuItemInfo(wxid=mid.ID_COMPRESS,
                         event_handler=lambda evt: safe_locking(main_frame.controller, main_frame.timeline.compress),
                         config_key="shortcut_compress",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_COMPRESS],
                         sort_order=9),
            MenuItemInfo(wxid=mid.ID_MEASURE_DISTANCE,
                         event_handler=lambda evt: self._measure_distance_between_two_events(),
                         config_key="shortcut_measure_distance",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_MEASURE_DISTANCE],
                         sort_order=10),
            MenuItemInfo(wxid=mid.ID_MEASURE_DURATION,
                         event_handler=lambda evt: open_measure_duration_dialog(main_frame),
                         config_key="shortcut_measure_duration",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_MEASURE_DURATION],
                         sort_order=11),
            MenuItemInfo(wxid=mid.ID_SET_CATEGORY_ON_WITHOUT,
                         event_handler=lambda evt: safe_locking(main_frame.controller, lambda: open_set_category_dialog(main_frame)),
                         config_key="shortcut_set_category_on_without",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_SET_CATEGORY_ON_WITHOUT],
                         sort_order=12),
            MenuItemInfo(wxid=mid.ID_EDIT_ERAS,
                         event_handler=lambda evt: safe_locking(main_frame.controller, lambda: oped_edit_eras_dialog(main_frame)),
                         config_key="shortcut_edit_eras",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_EDIT_ERAS],
                         sort_order=13),
            MenuItemInfo(wxid=mid.ID_SET_READONLY,
                         event_handler=lambda evt: main_frame.controller.set_timeline_in_readonly_mode(),
                         config_key="shortcut_set_readonly",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_SET_READONLY],
                         sort_order=14),
            MenuItemInfo(wxid=mid.ID_UNDO,
                         event_handler=lambda evt: safe_locking(main_frame.controller, main_frame.timeline.undo),
                         config_key="shortcut_undo",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_UNDO],
                         shortcut_key="Z",
                         shortcut_modifier=CTRL_MODIFIER,
                         sort_order=15),
            MenuItemInfo(wxid=mid.ID_REDO,
                         event_handler=lambda evt: safe_locking(main_frame.controller, main_frame.timeline.redo),
                         config_key="shortcut_redo",
                         config_display_name=LABEL_TIMELINE % MENU_LABELS[mid.ID_REDO],
                         shortcut_key="Z",
                         shortcut_modifier=ALT_MODIFIER,
                         sort_order=16),
        ]

    def _create_menu(self):
        self._append_menu_item(mid.ID_CREATE_EVENT)
        self._append_menu_item(mid.ID_EDIT_EVENT)
        self._append_menu_item(mid.ID_DUPLICATE_EVENT)
        self._append_menu_item(mid.ID_SET_CATEGORY_ON_SELECTED)
        self._append_menu_item(mid.ID_MOVE_EVENT_UP)
        self._append_menu_item(mid.ID_MOVE_EVENT_DOWN)
        self._append_menu_item(mid.ID_MOVE_EVENTS)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_CREATE_MILESTONE)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_COMPRESS)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_MEASURE_DISTANCE)
        self._append_menu_item(mid.ID_MEASURE_DURATION)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_SET_CATEGORY_ON_WITHOUT)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_EDIT_ERAS)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_SET_READONLY)
        self.AppendSeparator()
        self._append_menu_item(mid.ID_UNDO)
        self._append_menu_item(mid.ID_REDO)

    def _measure_distance_between_two_events(self):
        """
        Display an information message box that describes the distance between two selected events in the timeline.
        """
        event_ids = self._get_ids_of_two_first_selected_events()
        caption = _("Distance between selected events")
        display_information_message(caption, self._main_frame.timeline.get_distance_info(event_ids))

    def _get_ids_of_two_first_selected_events(self):
        view_properties = self._main_frame.view_properties
        return (view_properties.selected_event_ids[0],
                view_properties.selected_event_ids[1])

    def _open_event_editor(self):
        event = self._get_first_selected_event()
        if event:
            if event.is_milestone():
                open_milestone_editor_for(self._main_frame, event)
            else:
                open_event_editor_for(self._main_frame, event)

    def _get_first_selected_event(self):
        return self._main_frame.timeline.find_event_with_id(self._get_id_of_first_selected_event())

    def _get_id_of_first_selected_event(self):
        return self._main_frame.view_properties.get_selected_event_ids()[0]

    def _append_menu_item(self, wxid):
        self.Append(wxid, MENU_LABELS[wxid])
