#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
"""
This module contains the implementation of a home widget suitable for IDE to
show the recent project list and the quick start action they propose.

This widget is based on https://github.com/ColinDuquesnoy/QWelcomeWindow
"""
import os
import sys
from pyqode.qt import QtGui, QtCore
from pyqode.widgets.ui.home_ui import Ui_Form


# needed to build doc on readthedocs; should be fixed with the next version
# of pyqode.core
try:
    from pyqode.qt.QtCore import Property, QPoint
    from pyqode.qt.QtGui import QIcon, QListWidgetItem
except:
    class Property(object):
        def __init__(self, *args, **kwargs):
            pass

    class QPoint(object):
        pass

    class QIcon(object):
        def __init__(self, *args, **kwargs):
            pass

    class QListWidgetItem(object):
        pass


class ColorScheme(object):
    """
    Define a color scheme for easy customisation of the QWelcomeWidget's
    stylesheet.

    There are 7 colors to define:
        - background color
        - title background color
        - text_color
        - border_color:
        - selection_background_color
        - selection_color
        - hover_color: The hover background color

    Color are defined as string with web/hex format: "#rrggbbb"

    The default colors define a white/light gray color scheme.
    """

    def __init__(self):
        #: widgets background
        self.background_color = "#FFFFFF"
        #: titles background (app title, recent title, quick start action title)
        if sys.platform == "win32":
            self.title_background_color = "#EEEEEE"
        else:
            self.title_background_color = "#DDDDDD"
        #: texts color
        self.text_color = "#555555"
        # frames border color
        self.border_color = "#cccccc"
        # item selection background color
        self.selection_bck_color = "#aaaaaa"
        #: selected item text color
        self.selection_color = "#FFFFFF"
        #: selected item hover background color
        self.hover_color = "#bbbbbb"


class DarkColorScheme(ColorScheme):
    """
    Define a dark color scheme for easy customization of the stylesheet.
    """

    def __init__(self):
        super(DarkColorScheme, self).__init__()
        self.background_color = "#3C3F41"
        self.title_background_color = "#4b4b4b"
        self.text_color = "#C5C5C5"
        self.border_color = "#555555"
        self.selection_bck_color = "#343434"
        self.selection_color = "#C5C5C5"
        self.hover_color = "#343434"


STYLESHEET = """
QWidget
{
    background-color: %(background_color)s;
    color: %(text_color)s;
    selection-background-color: %(selection_bck_color)s;
    selection-color: %(selection_color)s;
}

QFrame
{
    border: 1px solid %(border_color)s;
    background-color: %(background_color)s;
}

QListWidget
{
    border: none;
}

QListView::item
{
    padding: 5px;
}

QListView::item:selected
{
    border: 1px solid %(border_color)s;
}

QListView::item:selected:!active
{
    background: %(selection_bck_color)s;
    color: %(selection_color)s;
}

QListView::item:selected:active
{
    background: %(selection_bck_color)s;
    color: %(selection_color)s;
}

QListView::item:hover
{
    background: %(hover_color)s;
}

QLabel
{
    padding-top: 8px;
    padding-bottom: 8px;
    padding-left: 3px;
    padding-right: 0px;
    border: none;
    background-color: %(title_background_color)s;
};
"""


class QHomeWidget(QtGui.QWidget, Ui_Form):
    """
    A QWidget for displaying a home page. It lets you add your custom quick
    start actions and manage the list of recent files for you (and store them
    in the QSettings you specified).

    The only things you need to do is to is to call setup
    :meth:`pyqode.widgets.QHomeWidget.setupRecentFiles` to setup the recent file
    menu (and select the QSettings to use to store the list of recent files).

    You can also set :attr:`pyqode.widgets.QHomeWidget.title` and
    :attr:`pyqode.widgets.QHomeWidget.icon`

    Then you must call :meth:`pyqode.widgets.QHomeWidget.setCurrentFile`
    everytime you open a file and connect to
    :attr:`pyqode.widgets.QHomeWidget.fileOpenRequested` to know when the user
    wants to open a recent file.

    To add a quick start actions, you just have to call
    :meth:`pyqode.widgets.QHomeWidget.addAction`.
    """
    #: Defines the maximum number of recent files memorized in the app settings
    MaxRecentFiles = 10

    #: Signal emitted when a recent file action is triggered (from you QMenu
    #: or from the widget recent file list
    fileOpenRequested = QtCore.Signal(object)

    def __getTitle(self):
        return self.lblTitle.text()

    def __setTitle(self, value):
        self.lblTitle.setText(value)
        self.__appName = value

    #: Text displayed on the title zone
    title = Property(str, __getTitle, __setTitle)

    def __getIcon(self):
        return self.app_icon

    def __setIcon(self, value):
        self.setApplicationIcon(value)

    #: Icon displayed on the tile zone
    icon = Property(QIcon, __getIcon, __setIcon)

    def __init__(self,  parent=None, appName="YouAppName",
                 appIcon=None, colorScheme=None):
        """
        :param appName: Your application name. Displayed in the homepage and
                        used to open the application settings.

        :param appIcon: Your application icon.

        :param colorScheme: A color scheme to easily customize the widget's
                             stylesheet

        :param menuRecentFiles: Your recent files menu.

        :param actionClearMnuRecentFiles: The optional action used to clear the
                                          menu.
        """
        QtGui.QWidget.__init__(self, parent)
        Ui_Form.__init__(self)
        self.setupUi(self)
        self.setAutoFillBackground(True)
        self.__actions = []
        self.__appName = appName
        self.setColorScheme(colorScheme)
        self.app_icon = appIcon
        self.setApplicationIcon(appIcon)
        self.title %= appName
        # setup context menu
        self.lwRecents.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.lwRecents.customContextMenuRequested.connect(
            self.__handleContextMenu)
        self.__contextMenu = QtGui.QMenu("Context Menu", self.lwRecents)
        self.__actionRemoveRecentFile = QtGui.QAction(
            "Remove", self)
        self.__actionRemoveRecentFile.triggered.connect(
            self.__removeCurrentFile)
        self.actionClearMnuRecentFiles = None

    @property
    def recentFiles(self):
        """
        Returns the list of recent files
        :return: a list of strings
        """
        ret_val = []
        files = self.__settings().value('recentFileList', [])
        if files is None:
            files = []
        if sys.version_info[0] == 2:
            if isinstance(files, unicode):
                files = [files]
        elif sys.version_info[0] == 3:
            if isinstance(files, str):
                files = [files]
        for f in files:
            if os.path.exists(f):
                ret_val.append(f)
        return ret_val

    @recentFiles.setter
    def recentFiles(self, files):
        """
        Save the list of rece,t files
        :param files: list of strings
        """
        self.__settings().setValue('recentFileList', files)

    def clearRecentFiles(self):
        """
        Clear the list of recent files
        :return:
        """
        self.recentFiles = []
        self.lwRecents.clear()
        self.__updateRecentFileActions()

    def setApplicationIcon(self, app_icon):
        if app_icon:
            self.lblIcon.setPixmap(app_icon.pixmap(32, 32))

    def changeApplicationLabel(self, app_name):
        self.lblTitle.setText("Welcome to %s" % app_name)

    def setColorScheme(self, color_scheme):
        """
        Sets the widget color scheme

        :param color_scheme: Color scheme instance
        :type color_scheme: pyqode.widgets.ColorScheme
        """
        if color_scheme is None:
            color_scheme = ColorScheme()
        stylesheet = STYLESHEET % {
            "background_color": color_scheme.background_color,
            "title_background_color": color_scheme.title_background_color,
            "text_color": color_scheme.text_color,
            "border_color": color_scheme.border_color,
            "selection_bck_color": color_scheme.selection_bck_color,
            "selection_color": color_scheme.selection_color,
            "hover_color": color_scheme.hover_color}
        self.setStyleSheet(stylesheet)
        p = self.palette()
        p.window().setColor(QtGui.QColor(color_scheme.background_color))
        self.setPalette(p)

    def addAction(self, action):
        """
        Adds a quick start action.

        :param action: QAction
        """
        assert isinstance(action, QtGui.QAction)
        self.__actions.append(action)
        item = QtGui.QListWidgetItem(action.text())
        item.setIcon(action.icon())
        self.lwQuickStart.addItem(item)
        QtGui.QWidget.addAction(self, action)

    def setActionIcon(self, action, icon):
        for i in range(self.lwQuickStart.count()):
            item = self.lwQuickStart.item(i)
            if item.text() == action.text():
                item.setIcon(action.icon())
                break

    def setCurrentFile(self, fileName):
        """
        Set the current filename (move it to the top of the stack of recent
        files)
        """
        self.curFile = fileName
        files = self.recentFiles
        try:
            files.remove(fileName)
        except ValueError:
            pass
        files.insert(0, fileName)
        del files[self.MaxRecentFiles:]
        self.recentFiles = files
        self.__updateRecentFileActions()

    def setActionText(self, index, text):
        """
        Changes visible text of a specific quick start action.
        """
        item = self.lwQuickStart.item(index)
        if not item:
            raise IndexError(index)
        item.setText(text)
        self.__actions[index].setText(text)

    def setupRecentFiles(self, organization="YourOrg", app="YourAppName",
                         menuRecentFiles=None, actionClearMnuRecentFiles=None):
        """
        Loads the recent file list, create its recent actions and create the
        recent files menu.
        """
        self.__org = organization
        self.__app = app
        self.actionClearMnuRecentFiles = actionClearMnuRecentFiles
        if actionClearMnuRecentFiles:
            actionClearMnuRecentFiles.triggered.connect(self.clearRecentFiles)
        self.menuRecentFiles = menuRecentFiles
        self.actionClearMnuRecentFiles = actionClearMnuRecentFiles
        self.separatorAct = None

        self.recentFileActs = []
        self.__createActions()
        self.__createMenus()

    def __addRecentFileAction(self, filePath):
        fileName = QtCore.QFileInfo(filePath).fileName()
        item = QtGui.QListWidgetItem(fileName)
        item.setData(32, filePath)
        self.lwRecents.addItem(item)

    def __settings(self):
        return QtCore.QSettings(self.__org, self.__app)

    def __createActions(self):
        """
        Create recent file actions
        """
        for i in range(self.MaxRecentFiles):
            self.recentFileActs.append(
                QtGui.QAction(self, visible=False,
                              triggered=self.__onOpenRecentFile))

    def __onOpenRecentFile(self):
        """
        Slot called when a recent file action is triggered, emits the
        recent_action_triggered.
        """
        action = self.sender()
        if action:
            path = action.data()
            if os.path.exists(path):
                self.fileOpenRequested.emit(path)

    def __createMenus(self):
        """
        Create menus
        """
        if self.menuRecentFiles:
            self.menuRecentFiles.clear()
            for i in range(self.MaxRecentFiles):
                self.menuRecentFiles.addAction(self.recentFileActs[i])
            self.separatorAct = self.menuRecentFiles.addSeparator()
            self.menuRecentFiles.addAction(self.actionClearMnuRecentFiles)
        self.__updateRecentFileActions()

    def __updateRecentFileActions(self):
        """
        Update the recent file actions.

        Clears the menu and the recent actions, then fill them with the list
        stored in the app settings
        """
        files = self.recentFiles
        files_no = 0
        if files:
            files_no = len(files)
        numRecentFiles = min(files_no, self.MaxRecentFiles)
        self.lwRecents.clear()
        for i in range(numRecentFiles):
            text = "%s" % self.__strippedName(files[i])
            self.recentFileActs[i].setText(text)
            self.recentFileActs[i].setData(files[i])
            self.recentFileActs[i].setVisible(True)
            self.__addRecentFileAction(files[i])
        for j in range(numRecentFiles, self.MaxRecentFiles):
            self.recentFileActs[j].setVisible(False)
        if self.separatorAct:
            self.separatorAct.setVisible((numRecentFiles > 0))

    def __strippedName(self, fullFileName):
        """
        Returs  the stripped filename (name + extension)

        :param fullFileName: The full filename to strip

        :return: The stripped name
        """
        return QtCore.QFileInfo(fullFileName).fileName()

    def __removeCurrentFile(self):
        fn = self.lwRecents.currentItem().data(32)
        files = self.recentFiles
        try:
            files.remove(fn)
        except ValueError:
            pass
        del files[self.MaxRecentFiles:]
        self.recentFiles = files
        self.__updateRecentFileActions()

    @QtCore.Slot(QListWidgetItem)
    def on_lwRecents_itemClicked(self, item=None):
        if self.lwRecents.mouseButton == QtCore.Qt.LeftButton:
            if item is None:
                item = self.lwRecents.currentItem()
            self.lwRecents.clearSelection()
            path = item.data(32)
            if os.path.exists(path):
                self.fileOpenRequested.emit(path)
            else:
                QtGui.QMessageBox.information(
                    self.parent(), "File does not exits",
                    "The file %s does not exists, it will be removed from the "
                    "recent files list" % path)
                self.__updateRecentFileActions()

    @QtCore.Slot(QListWidgetItem)
    def on_lwQuickStart_itemClicked(self, item):
        if self.lwQuickStart.mouseButton == QtCore.Qt.LeftButton:
            self.lwQuickStart.clearSelection()
            for action in self.__actions:
                if action.text() == item.text():
                    if os.environ['QT_API'] == "PySide":
                        action.triggered.emit()
                    else:
                        action.triggered.emit(True)

    @QtCore.Slot(QPoint)
    def __handleContextMenu(self, pos):
        self.__contextMenu.clear()
        item = self.lwRecents.itemAt(pos)
        if item is not None:
            self.__contextMenu.addAction(self.__actionRemoveRecentFile)
        if self.actionClearMnuRecentFiles:
            self.__contextMenu.addAction(self.actionClearMnuRecentFiles)
        self.__contextMenu.exec_(self.lwRecents.mapToGlobal(pos))


#///////////////////////////////////////////////////////////////////////////////
# Example
#///////////////////////////////////////////////////////////////////////////////
_widget = None
_theme = None


def onChangeTheme():
    global _widget, _theme
    if _theme is None:
        _theme = DarkColorScheme()
        _widget.setColorScheme(_theme)
        _widget.setActionText(2, "Try white theme")
    else:
        _widget.setColorScheme(ColorScheme())
        _theme = None
        _widget.setActionText(2, "Try dark theme")


def showHelp():
    QtGui.QMessageBox.information(
        None, "QWelcomeWindow",
        "QHomeWidget is a simple widget that you can use to quickly "
        "create a home window for your PySide/PyQt4 application.")


def openFile():
    fn = QtGui.QFileDialog.getOpenFileName(None)
    if fn:
        global _widget
        if os.environ['QT_API'] == "PySide":
            _widget.setCurrentFile(fn[0])
        else:
            _widget.setCurrentFile(fn)


def onOpenRecentFileRequested(filePath):
    print("User requested to open %s" % filePath)


def main():
    """
    Simple example
    """
    global _widget


    app = QtGui.QApplication(sys.argv)
    style = app.style()

    # create the widget
    _widget = QHomeWidget(appName="YourAppName",
                          appIcon=style.standardIcon(style.SP_ComputerIcon))

    # setup recent files actions
    actionClearRecents = QtGui.QAction("Clear", _widget)
    actionClearRecents.triggered.connect(_widget.clearRecentFiles)
    _widget.setupRecentFiles(organization="YourOrg",
                             actionClearMnuRecentFiles=actionClearRecents)
    _widget.fileOpenRequested.connect(onOpenRecentFileRequested)

    # Quick start actions
    openAction = QtGui.QAction(
        style.standardIcon(style.SP_DialogOpenButton), "Open", _widget)
    openAction.triggered.connect(openFile)
    _widget.addAction(openAction)

    helpAction = QtGui.QAction(
        style.standardIcon(style.SP_DialogHelpButton), "Help", _widget)
    helpAction.triggered.connect(showHelp)
    _widget.addAction(helpAction)

    reloadAction = QtGui.QAction(
        style.standardIcon(style.SP_BrowserReload), "Try dark theme", _widget)
    reloadAction.triggered.connect(onChangeTheme)
    _widget.addAction(reloadAction)

    # run the gui app
    _widget.show()
    app.exec_()


if __name__ == "__main__":
    main()
