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

# Copyright (c) 2005 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to configure the PyLint process
"""

import os
import sys
import copy

from qt import *

from KdeQt import KQFileDialog, KQMessageBox

from PyLintConfigForm import PyLintConfigForm


class PyLintConfigDialog(PyLintConfigForm):
    """
    Class implementing a dialog to configure the PyLint process
    """
    def __init__(self, ppath, parms = None, parent = None):
        """
        Constructor
        
        @param ppath project path (string or QString)
            Used to set the default path for the rcfile selection dialog
        @param parms parameters to set in the dialog
        @param parent reference to the parent widget (QWidget)
        """
        PyLintConfigForm.__init__(self, parent, modal=1)
        
        self.pylintProc = None
        self.lint = 'pylint'
        if sys.platform == "win32":
            self.lint = os.path.join(sys.exec_prefix, "Scripts", self.lint + '.bat')
        
        self.initializeDefaults()
        
        # get a copy of the defaults to store the user settings
        self.parameters = copy.deepcopy(self.defaults)
        
        # combine it with the values of parms
        if parms is not None:
            for key, value in parms.items():
                self.parameters[key] = parms[key]
        
        # initialize general tab
        self.configfileEdit.setText(self.parameters['configFile'])
        self.txtOutputButton.setChecked(self.parameters['txtReport'])
        self.htmlOutputButton.setChecked(self.parameters['htmlReport'])
        self.dialogOutputButton.setChecked(self.parameters['dialogReport'])
        self.reportfileEdit.setText(self.parameters['reportFile'])
        
        # initialize checkers tab
        self.basicCheckBox.setChecked(self.parameters['enableBasic'])
        self.classesCheckBox.setChecked(self.parameters['enableClasses'])
        self.designCheckBox.setChecked(self.parameters['enableDesign'])
        self.exceptionsCheckBox.setChecked(self.parameters['enableExceptions'])
        self.formatCheckBox.setChecked(self.parameters['enableFormat'])
        self.importsCheckBox.setChecked(self.parameters['enableImports'])
        self.metricsCheckBox.setChecked(self.parameters['enableMetrics'])
        self.miscellaneousCheckBox.setChecked(self.parameters['enableMiscellaneous'])
        self.similaritiesCheckBox.setChecked(self.parameters['enableSimilarities'])
        self.variablesCheckBox.setChecked(self.parameters['enableVariables'])
        
        self.ppath = ppath

    def initializeDefaults(self):
        """
        Private method to set the default values. 
        
        These are needed later on to generate the commandline
        parameters.
        """
        self.defaults = {
            # general options
            'configFile' : '',
            'reportFile' : '',
            'txtReport' : 0,
            'htmlReport' : 1,
            'dialogReport' : 0,
            
            # enabled checkers
            'enableBasic'         : 0,
            'enableClasses'       : 0,
            'enableDesign'        : 0,
            'enableExceptions'    : 0,
            'enableFormat'        : 0,
            'enableImports'       : 0,
            'enableMetrics'       : 1,
            'enableMiscellaneous' : 0,
            'enableSimilarities'  : 0,
            'enableVariables'     : 0,
        }

    def generateParameters(self):
        """
        Public method that generates the commandline parameters.
        
        It generates a QStringList to be used
        to set the QProcess arguments for the cxfreeze call and
        a list containing the non default parameters. The second
        list can be passed back upon object generation to overwrite
        the default settings.
        
        @return a tuple of the commandline parameters and non default parameters
            (QStringList, dictionary)
        """
        parms = {}
        args = QStringList()
        
        # 1. the program name
        if sys.platform == "win32":
            args.append(sys.executable)
        args.append(self.lint)
        
        # 2. the commandline options
        # 2.1 general options
        if self.parameters['configFile'] != self.defaults['configFile']:
            parms['configFile'] = self.parameters['configFile']
##            args.append('--rcfile=%s' % self.parameters['configFile'])
            args.append('--rcfile')
            args.append(self.parameters['configFile'])
        parms['txtReport'] = self.parameters['txtReport']
        parms['htmlReport'] = self.parameters['htmlReport']
        parms['dialogReport'] = self.parameters['dialogReport']
        if self.parameters['htmlReport']:
            args.append('--html=y')
        elif self.parameters['dialogReport']:
            args.append('--parseable=y')
            args.append('--report=n')
        if self.parameters['reportFile'] != self.defaults['reportFile']:
            parms['reportFile'] = self.parameters['reportFile']
        
        # 2.2 checkers options
        parms['enableBasic'] = self.parameters['enableBasic']
        parms['enableClasses'] = self.parameters['enableClasses']
        parms['enableDesign'] = self.parameters['enableDesign']
        parms['enableExceptions'] = self.parameters['enableExceptions']
        parms['enableFormat'] = self.parameters['enableFormat']
        parms['enableImports'] = self.parameters['enableImports']
        parms['enableMetrics'] = self.parameters['enableMetrics']
        parms['enableMiscellaneous'] = self.parameters['enableMiscellaneous']
        parms['enableSimilarities'] = self.parameters['enableSimilarities']
        parms['enableVariables'] = self.parameters['enableVariables']
        
        args.append('--disable-all')
        if self.parameters['enableBasic']:
            args.append('--enable-basic=y')
        if self.parameters['enableClasses']:
            args.append('--enable-classes=y')
        if self.parameters['enableDesign']:
            args.append('--enable-design=y')
        if self.parameters['enableExceptions']:
            args.append('--enable-exceptions=y')
        if self.parameters['enableFormat']:
            args.append('--enable-format=y')
        if self.parameters['enableImports']:
            args.append('--enable-imports=y')
        if self.parameters['enableMetrics']:
            args.append('--enable-metrics=y')
        if self.parameters['enableMiscellaneous']:
            args.append('--enable-miscellaneous=y')
        if self.parameters['enableSimilarities']:
            args.append('--enable-similarities=y')
        if self.parameters['enableVariables']:
            args.append('--enable-variables=y')
        
        return (args, parms)

    def handleConfigfile(self):
        """
        Private slot to select the configuration file.
        
        It displays a file selection dialog to select the configuration file.
        """
        startWith = self.configfileEdit.text()
        if startWith.isEmpty():
            startWith = self.ppath
        config = KQFileDialog.getOpenFileName(\
            startWith,
            self.trUtf8('Configuration Files (*.cfg *.cnf *.rc);;All Files (*)'),
            None, None,
            self.trUtf8("Select configuration file"),
            None, 1)
        if not config.isEmpty():
            self.configfileEdit.setText(QDir.convertSeparators(config))
    
    def handleReportfile(self):
        """
        Private slot to select the report file.
        
        It displays a file selection dialog to select the report file.
        """
        report = KQFileDialog.getSaveFileName(\
            self.reportfileEdit.text(),
            QString.null,
            None, None,
            self.trUtf8("Select report file"),
            None, 1)
        
        if not report.isEmpty():
            self.reportfileEdit.setText(QDir.convertSeparators(report))
    
    def handleTextChanged(self, txt):
        """
        Private slot to handle the TextChanged signal of configfileEdit.
        
        @param txt contents of configfileEdit (QString)
        """
        self.okButton.setEnabled(not txt.isEmpty())
        
    def accept(self):
        """
        Protected slot called by the Ok button. 
        
        It saves the values in the parameters dictionary.
        """
        # get data of general tab
        self.parameters['configFile'] = unicode(self.configfileEdit.text())
        self.parameters['txtReport'] = self.txtOutputButton.isChecked()
        self.parameters['htmlReport'] = self.htmlOutputButton.isChecked()
        self.parameters['dialogReport'] = self.dialogOutputButton.isChecked()
        self.parameters['reportFile'] = unicode(self.reportfileEdit.text())
        
        # get data of checkers tab
        self.parameters['enableBasic'] = self.basicCheckBox.isChecked()
        self.parameters['enableClasses'] = self.classesCheckBox.isChecked()
        self.parameters['enableDesign'] = self.designCheckBox.isChecked()
        self.parameters['enableExceptions'] = self.exceptionsCheckBox.isChecked()
        self.parameters['enableFormat'] = self.formatCheckBox.isChecked()
        self.parameters['enableImports'] = self.importsCheckBox.isChecked()
        self.parameters['enableMetrics'] = self.metricsCheckBox.isChecked()
        self.parameters['enableMiscellaneous'] = self.miscellaneousCheckBox.isChecked()
        self.parameters['enableSimilarities'] = self.similaritiesCheckBox.isChecked()
        self.parameters['enableVariables'] = self.variablesCheckBox.isChecked()
        
        # call the accept slot of the base class
        PyLintConfigForm.accept(self)

    ############################################################################
    # Methods below are needed to generate a configuration file template
    ############################################################################

    def handleCreateConfig(self):
        """
        Public slot to handle the generation of a sample configuration.
        """
        self.buf = QString("")
        self.pylintProc = QProcess()
        
        if sys.platform == "win32":
            self.pylintProc.addArgument(sys.executable)
        self.pylintProc.addArgument(self.lint)
        self.pylintProc.addArgument('--generate-rcfile')
        
        self.connect(self.pylintProc, SIGNAL('processExited()'), self.handleCreateConfigDone)
        self.connect(self.pylintProc, SIGNAL('readyReadStdout()'), self.handleStdout)
        self.connect(self.pylintProc, SIGNAL('readyReadStderr()'), self.handleStderr)
        
        if self.pylintProc.start():
            qApp.mainWidget().getViewManager().enableEditorsCheckFocusIn(0)
        else:
            KQMessageBox.critical(self,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'Could not start %1.<br>'
                    'Ensure that it is in the search path.'
                ).arg(self.lint),
                self.trUtf8('OK'))
    
    def handleCreateConfigDone(self):
        """
        Private slot to handle the the processExit signal of the pylint process.
        """
        vm = qApp.mainWidget().getViewManager()
        vm.enableEditorsCheckFocusIn(1)
        if self.pylintProc.normalExit():
            vm.newEditor()
            aw = vm.activeWindow()
            aw.insertAt(self.buf, 0, 0)
            aw.setLanguage('dummy.rc')
        self.reject()
    
    def handleStdout(self):
        """
        Private slot to handle the readyReadStdout signal of the pylint process.
        """
        while self.pylintProc and self.pylintProc.canReadLineStdout():
            self.buf.append(self.pylintProc.readLineStdout())
            self.buf.append(os.linesep)
        
    def handleStderr(self):
        """
        Private slot to handle the readyReadStderr signal of the pylint process.
        """
        while self.pylintProc and self.pylintProc.canReadLineStderr():
            s = QString('pylint: ')
            s.append(self.pylintProc.readLineStderr())
            qApp.mainWidget().emit(PYSIGNAL('appendStderr'), (s,))
        
