# 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 wx
import wx.lib.newevent


from timelinelib.config.dotfile import read_config
from timelinelib.config.wxlocale import set_wx_locale
from timelinelib.db import db_open
from timelinelib.features.experimental.experimentalfeatures import ExperimentalFeatures
from timelinelib.meta.about import APPLICATION_NAME
from timelinelib.wxgui.frames.mainframe.mainframecontroller import MainFrameController
from timelinelib.wxgui.frames.mainframe.alertcontroller import AlertController
from timelinelib.wxgui.utils import load_icon_bundle
from timelinelib.wxgui.components.mainpanel import MainPanel
from timelinelib.wxgui.components.statusbaradapter import StatusBarAdapter
from timelinelib.wxgui.frames.mainframe.menus.filemenu import FileMenu
from timelinelib.wxgui.frames.mainframe.menus.editmenu import EditMenu
from timelinelib.wxgui.frames.mainframe.menus.viewmenu import ViewMenu
from timelinelib.wxgui.frames.mainframe.menus.timelinemenu import TimelineMenu
from timelinelib.wxgui.frames.mainframe.menus.navigatemenu import NavigateMenu
from timelinelib.wxgui.frames.mainframe.menus.helpmenu import HelpMenu
from timelinelib.wxgui.frames.mainframe.menucontroller import MenuController
from timelinelib.config.shortcut import ShortcutController


CatsViewChangedEvent, EVT_CATS_VIEW_CHANGED = wx.lib.newevent.NewCommandEvent()
LabelsChangedEvent, EVT_LABELS_CHANGED = wx.lib.newevent.NewCommandEvent()


class MainFrame(wx.Frame):
    """
    The application main frame window contains
        * menu
        * main panel (:class:`~timelinelib.wxgui.components.mainpanel.MainPanel`)
        * status bar

    The business logic for this window is found in the class
    :class:`~timelinelib.wxgui.frames.mainframe.mainframecontroller.MainFrameController`.

    Events handled by this window:

        EVT_LABELS_CHANGED
            Triggered when the Enter key is pressed in the label filtering textbox in the
            :class:`~timelinelib.wxgui.components.sidebar.Sidebar`.

        EVT_CATS_VIEW_CHANGED
            Triggered when the checkbox "View Categories Individually" in the
            :class:`~timelinelib.wxgui.components.sidebar.Sidebar` is clicked.

        wx.EVT_CLOSE
            Triggered when the application is closed.

    """

    def __init__(self):
        self._config = read_config()
        wx.Frame.__init__(self, None, size=self._config.get_window_size(),
                          pos=self._config.get_window_pos(),
                          style=wx.DEFAULT_FRAME_STYLE, name="main_frame")
        self.locale = set_wx_locale()
        self._controller = MainFrameController(self, db_open, self._config)
        self._shortcut_controller = ShortcutController(self.config)
        self._timeline = None
        self._menu_controller = None
        ExperimentalFeatures().set_active_state_on_all_features_from_config_string(
            self._config.experimental_features)
        self._create_gui()
        self._bind_events()
        self._main_panel.DisplayWelcomePanel()
        self._controller.populate()
        self._alert_controller = AlertController(self).start_timer()

    @property
    def config(self):
        """
        The :class:`~timelinelib.config.dotfile.Config` object, created by the main frame,
        that hold user settings stored in persistent storage.
        """
        return self._config

    @property
    def controller(self):
        """
        The :class:`~timelinelib.wxgui.frames.mainframe.mainframecontroller.MainFrameController` object
        , created by the main frame,
        containing the business logic for the MainFrame window (view).
        """
        return self._controller

    @property
    def shortcut_controller(self):
        """
        The :class:`~timelinelib.config.shortcut.ShortcutController` object
        , created by the main frame, containing the shortcuts in the menus.
        """
        return self._shortcut_controller

    @property
    def menu_controller(self):
        """
        The :class:`~timelinelib.wxgui.frames.mainframe.menucontroller.MenuController` object
        , created by the main frame, containing menu operations.
        """
        return self._menu_controller

    @property
    def timeline(self):
        """
        The :class:`~timelinelib.canvas.data.memorydb.db.MemoryDB` object representing the data shown on
        the timeline.
        This object is passed in to the main frame through the function
        :obj:`~timelinelib.wxgui.frames.mainframe.mainframe.MainFrame.DisplayTimeline`
        """
        return self._timeline

    @property
    def main_panel(self):
        """
        The :class:`~timelinelib.wxgui.components.mainpanel.MainPanel` object
        , created by the main frame,
        where the timeline and the sidebar is found.
        """
        return self._main_panel

    @property
    def canvas(self):
        """
        The :class:`~timelinelib.canvas.timelinecanvas.TimelineCanvas` object
        where the timeline is drawn. It is actually a property of the main_panel.
        """
        return self._main_panel.timeline_panel.timeline_canvas

    @property
    def view_properties(self):
        """
        The :class:`~timelinelib.canvas.drawing.viewproperties.ViewProperties` object
        where the timeline is drawn. It is actually a property of the canvas object.
        """
        return self.canvas.GetViewProperties()

    def DisplayTimeline(self, timeline):
        """Render a new timeline."""
        self._timeline = timeline
        self._menu_controller.on_timeline_change(timeline)
        self._main_panel.DisplayTimelinePanel(timeline)

    def DisplayStatus(self, message):
        """Set the text in the first column of the status bar."""
        self.status_bar_adapter.set_text(message)

    def DisplayHiddenCount(self, message):
        """Set the text in the second column of the status bar."""
        self.status_bar_adapter.set_hidden_event_count_text(message)

    def DisplayReadonly(self, text):
        """Set the text in the third column of the status bar."""
        self.status_bar_adapter.set_read_only_text(text)

    def EnableDisableMenus(self):
        """Enable/Disable menus depending on number of selected events."""
        timeline_view_visible = self._main_panel.TimelinePanelVisible()
        nbr_of_selected_events = len(self.view_properties.get_selected_event_ids())
        self._menu_controller.update_menus_enabled_state(timeline_view_visible, nbr_of_selected_events)

    def UpdateOpenRecentSubmenu(self):
        """Update the submenu that has a list of recent opened timeline files."""
        self._get_file_menu().UpdateRecentSubmenu()

    def UpdateNavigationMenuItems(self):
        """
        Updates the naivigation menu when a timeline with another timetype than
        the current timeline is opened.
        """
        if self._timeline:
            self._get_navigate_menu().UpdateMenuItems()

    def GetTimelinePath(self):
        """Return the path to current timeline or None if there is no current timeline."""
        if self.timeline:
            return self.timeline.path

    def Exit(self, evt):
        """Clean up at application exit."""
        self.canvas.StopHighlightTimer()
        self._alert_controller.stop_timer()
        self._controller.exit()

    def _get_navigate_menu(self):
        return self._get_menu_by_name(_("&Navigate"))

    def _get_file_menu(self):
        return self._get_menu_by_name(_("&File"))

    def _get_menu_by_name(self, name):
        menu_bar = self.GetMenuBar()
        if menu_bar:
            menu_inx = menu_bar.FindMenu(name)
            return menu_bar.GetMenu(menu_inx)

    #
    # GUI
    #

    def _create_gui(self):
        # main panel must be created before the menu bar!!!
        self._create_main_panel()
        self._create_main_menu_bar()
        self._create_status_bar()
        self.SetTitle(APPLICATION_NAME)
        self.SetIcons(load_icon_bundle())
        self.Maximize(self._config.window_maximized)

    def _create_status_bar(self):
        self.status_bar_adapter = StatusBarAdapter(self.CreateStatusBar())

    def _create_main_panel(self):
        self._main_panel = MainPanel(self)

    def _create_main_menu_bar(self):
        self.SetMenuBar(self._create_menu_bar())
        self.UpdateNavigationMenuItems()
        self.UpdateOpenRecentSubmenu()
        self.EnableDisableMenus()

    def _create_menu_bar(self):
        main_menu_bar = wx.MenuBar()
        self._menu_controller = MenuController(main_menu_bar)
        main_menu_bar.Append(FileMenu(self), _("&File"))
        main_menu_bar.Append(EditMenu(self), _("&Edit"))
        main_menu_bar.Append(ViewMenu(self), _("&View"))
        main_menu_bar.Append(TimelineMenu(self, self._main_panel.timeline_panel), _("&Timeline"))
        main_menu_bar.Append(NavigateMenu(self), _("&Navigate"))
        main_menu_bar.Append(HelpMenu(self), _("&Help"))
        return main_menu_bar

    def _bind_events(self):
        self.Bind(EVT_CATS_VIEW_CHANGED, self._on_cats_view_changed)
        self.Bind(EVT_LABELS_CHANGED, self._on_labels_changed)
        self.Bind(wx.EVT_CLOSE, self.Exit)

    def _on_cats_view_changed(self, evt):
        self.view_properties.change_view_cats_individually(evt.is_checked)

    def _on_labels_changed(self, evt):
        self.view_properties.change_labels(evt.filter_labels_controller)
