# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
# See http://www.gnu.org/licenses/ for more information.

"""
The PDF preview panel.

This file loads even if popplerqt5 is absent, although the PDF preview
panel only shows a message about missing the popplerqt5 module.

The widget module contains the real widget, the documents module a simple
abstraction and caching of Poppler documents with their filename,
and the printing module contains code to print a Poppler document, either
via a PostScript rendering or by printing raster images to a QPrinter.

All the point & click stuff is handled in the pointandclick module.

"""


import functools
import os
import weakref

from PyQt5.QtCore import QSettings, QTimer, Qt, pyqtSignal
from PyQt5.QtGui import QColor, QKeySequence, QPalette
from PyQt5.QtWidgets import (
    QAction, QActionGroup, QApplication, QComboBox, QLabel, QSpinBox,
    QWidgetAction)

import app
import actioncollection
import actioncollectionmanager
import icons
import job
import qutil
import panel
import listmodel
import gadgets.drag

from . import documents


# default zoom percentages
_zoomvalues = [50, 75, 100, 125, 150, 175, 200, 250, 300]

# viewModes from qpopplerview:
from qpopplerview import FixedScale, FitWidth, FitHeight, FitBoth


def activate(func):
    """Decorator for MusicViewPanel methods/slots.

    The purpose is to first activate the widget and only perform an action
    when the event loop starts. This gives the PDF widget the chance to resize
    and position itself correctly.

    """
    @functools.wraps(func)
    def wrapper(self):
        instantiated = bool(super(panel.Panel, self).widget())
        self.activate()
        if instantiated:
            func(self)
        else:
            QTimer.singleShot(0, lambda: func(self))
    return wrapper


class MusicViewPanel(panel.Panel):
    def __init__(self, mainwindow):
        super(MusicViewPanel, self).__init__(mainwindow)
        self.toggleViewAction().setShortcut(QKeySequence("Meta+Alt+M"))
        mainwindow.addDockWidget(Qt.RightDockWidgetArea, self)

        ac = self.actionCollection = Actions(self)
        actioncollectionmanager.manager(mainwindow).addActionCollection(ac)
        ac.music_print.triggered.connect(self.printMusic)
        ac.music_zoom_in.triggered.connect(self.zoomIn)
        ac.music_zoom_out.triggered.connect(self.zoomOut)
        ac.music_zoom_original.triggered.connect(self.zoomOriginal)
        ac.music_zoom_combo.zoomChanged.connect(self.slotZoomChanged)
        ac.music_fit_width.triggered.connect(self.fitWidth)
        ac.music_fit_height.triggered.connect(self.fitHeight)
        ac.music_fit_both.triggered.connect(self.fitBoth)
        ac.music_single_pages.triggered.connect(self.viewSinglePages)
        ac.music_two_pages_first_right.triggered.connect(self.viewTwoPagesFirstRight)
        ac.music_two_pages_first_left.triggered.connect(self.viewTwoPagesFirstLeft)
        ac.music_maximize.triggered.connect(self.maximize)
        ac.music_jump_to_cursor.triggered.connect(self.jumpToCursor)
        ac.music_sync_cursor.triggered.connect(self.toggleSyncCursor)
        ac.music_copy_image.triggered.connect(self.copyImage)
        ac.music_copy_text.triggered.connect(self.copyText)
        ac.music_document_select.documentsChanged.connect(self.updateActions)
        ac.music_copy_image.setEnabled(False)
        ac.music_next_page.tri
ggered.connect(self.slotNextPage)
        ac.music_prev_page.triggered.connect(self.slotPreviousPage)
        self.slotPageCountChanged(0)
        ac.music_next_page.setEnabled(False)
        ac.music_prev_page.setEnabled(False)
        ac.music_si
ngle_pages.setChecked(True) # default to single pages
        ac.music_reload.triggered.connect(self.reloadView)
        self.actionCollection.music_sync_cursor.setChecked(
            QSettings().value("musicview/sync_cursor", False, bool))

        mode = QSettings().value("muziekview/layoutmode", "single", str)
        if mode == "double_left":
            ac.music_two_pages_first_left.setChecked(True)
        elif mode == "double_right":
            ac.music_two_pages_first_right.setChecked(True)
        else: # mode == "single":
            ac.music_single_pages.setChecked(True)

    def translateUI(self):
        self.setWindowTitle(_("window title", "Music View"))
        self.toggleViewAction().setText(_("&Music View"))

    def createWidget(self):
        from . import widget
        w = widget.MusicView(self)
        w.zoomChanged.connect(self.slotMusicZoomChanged)
        w.updateZoomInfo()
        w.view.surface().selectionChanged.connect(self.updateSelection)

        # read layout mode setting before using the widget
        layout = w.view.surface().pageLayout()
        if self.actionCollection.music_two_pages_first_right.isChecked():
            layout.setPagesPerRow(2)
            layout.setPagesFirstRow(1)
        elif self.actionCollection.music_two_pages_first_left.isChecked():
            layout.setPagesPerRow(2)
            layout.setPagesFirstRow(0)
        else: # "single"
            layout.setPagesPerRow(1)   # default to single
            layout.setPagesFirstRow(0) # pages

        import qpopplerview.pager
        self._pager = p = qpopplerview.pager.Pager(w.view)
        p.pageCountChanged.connect(self.slotPageCountChanged)
        p.currentPageChanged.connect(self.slotCurrentPageChanged)
        app.languageChanged.connect(self.updatePagerLanguage)

        selector = self.actionCollection.music_document_select
        selector.currentDocumentChanged.connect(w.openDocument)
        selector.documentClosed.connect(w.clear)

        if selector.currentDocument():
            # open a document only after the widget has been created;
            # this prevents many superfluous resizes
            def open():
                if selector.currentDocument():
                    w.openDocument(selector.currentDocument())
            QTimer.singleShot(0, open)
        return w

    def setPageLayoutMode(self, mode):
        """Change the page layout and store the setting as well.

        The mode is "single", "double_left" or "double_right".

        "single": a vertical row of single pages
        "double_left": two pages besides each other, first page is a left page
        "double_right": two pages, first page is a right page.

        """
        layout = self.widget().view.surface().pageLayout()
        if mode == "double_right":
            layout.setPagesPerRow(2)
            layout.setPagesFirstRow(1)
        elif mode == "double_left":
            layout.setPagesPerRow(2)
            layout.setPagesFirstRow(0)
        elif mode == "single":
            layout.setPagesPerRow(1)
            layout.setPagesFirstRow(0)
        else:
            raise ValueError("wrong mode value")
        QSettings().setValue("muziekview/layoutmode", mode)
        layout.update()

    def updateSelection(self, rect):
        self.actionCollection.music_copy_image.setEnabled(bool(rect))
        self.actionCollection.music_copy_text.setEnabled(bool(rect))

    def updatePagerLanguage(self):
        self.actionCollection.music_pager.setPageCount(self._pager.pageCount())

    def slotPageCountChanged(self, total):
        self.actionCollection.music_pager.setPageCount(total)

    def slotCurrentPageChanged(self, num):
        self.actionCollection.music_pager.setC