# -*- coding: utf-8 -*-

"""
***************************************************************************
    CommanderWindow.py
    ---------------------
    Date                 : April 2013
    Copyright            : (C) 2012 by Victor Olaya
    Email                : volayaf at gmail dot com
***************************************************************************
*                                                                         *
*   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.                                   *
*                                                                         *
***************************************************************************
"""

__author__ = 'Victor Olaya'
__date__ = 'April 2013'
__copyright__ = '(C) 2013, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '93c55caa41f16a598bbdb1893892cbb342e150cf'

import types
import os
import imp

from qgis.PyQt.QtCore import Qt, QSize
from qgis.PyQt.QtWidgets import QDialog, QLabel, QSpacerItem, QHBoxLayout, QVBoxLayout, QSizePolicy, QComboBox, QCompleter
from qgis.PyQt.QtCore import QSortFilterProxyModel
from qgis.utils import iface
from processing.core.alglist import algList
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.tools.system import userFolder, mkdir

ITEMHEIGHT = 30
OFFSET = 20
HEIGHT = 60


class CommanderWindow(QDialog):

    def __init__(self, parent, canvas):
        self.canvas = canvas
        QDialog.__init__(self, parent, Qt.FramelessWindowHint)
        self.commands = imp.load_source('commands', self.commandsFile())
        self.initGui()

    def commandsFolder(self):
        folder = unicode(os.path.join(userFolder(), 'commander'))
        mkdir(folder)
        return os.path.abspath(folder)

    def commandsFile(self):
        f = os.path.join(self.commandsFolder(), 'commands.py')
        if not os.path.exists(f):
            out = open(f, 'w')
            out.write('from qgis.core import *\n')
            out.write('import processing\n\n')
            out.write('def removeall():\n')
            out.write('\tmapreg = QgsMapLayerRegistry.instance()\n')
            out.write('\tmapreg.removeAllMapLayers()\n\n')
            out.write('def load(*args):\n')
            out.write('\tprocessing.load(args[0])\n')
            out.close()
        return f

    def algsListHasChanged(self):
        self.fillCombo()

    def initGui(self):
        self.combo = ExtendedComboBox()
        self.fillCombo()

        self.combo.setEditable(True)
        self.label = QLabel('Enter command:')
        self.errorLabel = QLabel('Enter command:')
        self.vlayout = QVBoxLayout()
        self.vlayout.setSpacing(2)
        self.vlayout.setMargin(0)
        self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET,
                                               QSizePolicy.Maximum, QSizePolicy.Expanding))
        self.hlayout = QHBoxLayout()
        self.hlayout.addWidget(self.label)
        self.vlayout.addLayout(self.hlayout)
        self.hlayout2 = QHBoxLayout()
        self.hlayout2.addWidget(self.combo)
        self.vlayout.addLayout(self.hlayout2)
        self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET,
                                               QSizePolicy.Maximum, QSizePolicy.Expanding))
        self.setLayout(self.vlayout)
        self.combo.lineEdit().returnPressed.connect(self.run)
        self.prepareGui()

    def fillCombo(self):
        self.combo.clear()

        # Add algorithms
        for provider in algList.algs.values():
            for alg in provider:
                self.combo.addItem('Processing algorithm: ' + alg)

        # Add functions
        for command in dir(self.commands):
            if isinstance(self.commands.__dict__.get(command),
                          types.FunctionType):
                self.combo.addItem('Command: ' + command)

        # Add menu entries
        menuActions = []
        actions = iface.mainWindow().menuBar().actions()
        for action in actions:
            menuActions.extend(self.getActions(action))
        for action in menuActions:
            self.combo.addItem('Menu action: ' + unicode(action.text()))

    def prepareGui(self):
        self.combo.setEditText('')
        self.combo.setMaximumSize(QSize(self.canvas.rect().width() - 2 * OFFSET, ITEMHEIGHT))
        self.combo.view().setStyleSheet('min-height: 150px')
        self.combo.setFocus(Qt.OtherFocusReason)
        self.label.setMaximumSize(self.combo.maximumSize())
        self.label.setVisible(False)
        self.adjustSize()
        pt = self.canvas.rect().topLeft()
        absolutePt = self.canvas.mapToGlobal(pt)
        self.move(absolutePt)
        self.resize(self.canvas.rect().width(), HEIGHT)
        self.setStyleSheet('CommanderWindow {background-color: #e7f5fe; \
                            border: 1px solid #b9cfe4;}')

    def getActions(self, action):
        menuActions = []
        menu = action.menu()
        if menu is None:
            menuActions.append(action)
            return menuActions
        else:
            actions = menu.actions()
            for subaction in actions:
                if subaction.menu() is not None:
                    menuActions.extend(self.getActions(subaction))
                elif not subaction.isSeparator():
                    menuActions.append(subaction)

        return menuActions

    def run(self):
        s = unicode(self.combo.currentText())
        if s.startswith('Processing algorithm: '):
            algName = s[len('Processing algorithm: '):]
            alg = algList.getAlgorithm(algName)
            if alg is not None:
                self.close()
                self.runAlgorithm(alg)
        elif s.startswith("Command: "):
            command = s[len("Command: "):]
            try:
                self.runCommand(command)
                self.close()
            except Exception as e:
                self.label.setVisible(True)
                self.label.setText('Error:' + unicode(e))

        elif s.startswith('Menu action: '):
            actionName = s[len('Menu action: '):]
            menuActions = []
            actions = iface.mainWindow().menuBar().actions()
            for action in actions:
                menuActions.extend(self.getActions(action))
            for action in menuActions:
                if action.text() == actionName:
                    self.close()
                    action.trigger()
                    return
        else:
            try:
                self.runCommand(s)
                self.close()
            except Exception as e:
                self.label.setVisible(True)
                self.label.setText('Error:' + unicode(e))

    def runCommand(self, command):
        tokens = command.split(' ')
        if len(tokens) == 1:
            method = self.commands.__dict__.get(command)
            if method is not None:
                method()
            else:
                raise Exception('Wrong command')
        else:
            method = self.commands.__dict__.get(tokens[0])
            if method is not None:
                method(*tokens[1:])
            else:
                raise Exception('Wrong command')

    def runAlgorithm(self, alg):
        alg = alg.getCopy()
        message = alg.checkBeforeOpeningParametersDialog()
        if message:
            dlg = MessageDialog()
            dlg.setTitle(self.tr('Missing dependency'))
            dlg.setMessage(message)
            dlg.exec_()
            return
        dlg = alg.getCustomParametersDialog()
        if not dlg:
            dlg = AlgorithmDialog(alg)
        canvas = iface.mapCanvas()
        prevMapTool = canvas.mapTool()
        dlg.show()
        dlg.exec_()
        if canvas.mapTool() != prevMapTool:
            try:
                canvas.mapTool().reset()
            except:
                pass
            canvas.setMapTool(prevMapTool)


class ExtendedComboBox(QComboBox):

    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.popup().setStyleSheet('min-height: 150px')
        self.completer.popup().setAlternatingRowColors(True)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited[unicode].connect(self.pFilterModel.setFilterFixedString)
