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

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

"""
Module implementing a dialog to enter the parameters for cxfreeze.
"""

import sys
import os
import copy

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from KdeQt import KQFileDialog

from E4Gui.E4Completers import E4FileCompleter, E4DirCompleter

from Ui_CxfreezeConfigDialog import Ui_CxfreezeConfigDialog

import Utilities

class CxfreezeConfigDialog(QDialog, Ui_CxfreezeConfigDialog):
    """
    Class implementing a dialog to enter the parameters for cxfreeze.
    """
    def __init__(self, ppath, parms = None, parent = None):
        """
        Constructor
        
        @param ppath project path of the current project (string)
        @param parms parameters to set in the dialog
        @param parent parent widget of this dialog
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        
        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]
        
        self.ppath = ppath
        
        self.exe = "FreezePython"
        if sys.platform == "win32":
            self.exe += '.exe'
        self.exePath = os.path.dirname(Utilities.getExecutablePath(self.exe))
        
        # populate combo boxes
        d = QDir(os.path.join(self.exePath, 'bases'))
        basesList = d.entryList(QDir.Filters(QDir.Files))
        basesList.prepend('')
        self.basenameCombo.addItems(basesList)
        
        d = QDir(os.path.join(self.exePath, 'initscripts'))
        initList = d.entryList(QStringList('*.py'))
        initList.prepend('')
        self.initscriptCombo.addItems(initList)
        
        self.targetDirCompleter = E4DirCompleter(self.targetDirEdit)
        self.sharedLibCompleter = E4FileCompleter(self.sharedLibEdit)
        self.extListFileCompleter = E4FileCompleter(self.extListFileEdit)
        
        # initialize general tab
        self.targetDirEdit.setText(self.parameters['targetDirectory'])
        self.targetNameEdit.setText(self.parameters['targetName'])
        self.basenameCombo.setEditText(self.parameters['baseName'])
        self.initscriptCombo.setEditText(self.parameters['initScript'])
        self.keeppathCheckBox.setChecked(self.parameters['keepPath'])
        if self.parameters['optimize'] == 0:
            self.nooptimizeRadioButton.setChecked(True)
        elif self.parameters['optimize'] == 1:
            self.optimizeRadioButton.setChecked(True)
        else:
            self.optimizeDocRadioButton.setChecked(True)
        
        # initialize advanced tab
        self.sharedLibEdit.setText(self.parameters['sharedLib'])
        self.defaultPathEdit.setText(os.pathsep.join(self.parameters['defaultPath']))
        self.includePathEdit.setText(os.pathsep.join(self.parameters['includePath']))
        self.replacePathsEdit.setText(os.pathsep.join(self.parameters['replacePaths']))
        self.includeModulesEdit.setText(','.join(self.parameters['includeModules']))
        self.excludeModulesEdit.setText(','.join(self.parameters['excludeModules']))
        self.extListFileEdit.setText(self.parameters['extListFile'])

    def __initializeDefaults(self):
        """
        Private method to set the default values. 
        
        These are needed later on to generate the commandline
        parameters.
        """
        self.defaults = {
            # general options
            'targetDirectory' : '',
            'targetName' : '',
            'baseName' : '',
            'initScript' : '',
            'keepPath' : False,
            'optimize' : 0,     # 0, 1 or 2
            
            # advanced options
            'sharedLib' : '',
            'defaultPath' : [],
            'includePath' : [],
            'replacePaths' : [],
            'includeModules' : [],
            'excludeModules' : [],
            'extListFile' : '',
        }
    
    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
        args.append(self.exe)
        
        # 2. the commandline options
        # 2.1 general options
        if self.parameters['targetDirectory'] != self.defaults['targetDirectory']:
            parms['targetDirectory'] = self.parameters['targetDirectory']
            args.append('--target-dir=%s' % self.parameters['targetDirectory'])
        if self.parameters['targetName'] != self.defaults['targetName']:
            parms['targetName'] = self.parameters['targetName'][:]
            args.append('--target-name=%s' % self.parameters['targetName'])
        if self.parameters['baseName'] != self.defaults['baseName']:
            parms['baseName'] = self.parameters['baseName'][:]
            args.append('--base-name=%s' % self.parameters['baseName'])
        if self.parameters['initScript'] != self.defaults['initScript']:
            parms['initScript'] = self.parameters['initScript'][:]
            args.append('--init-script=%s' % self.parameters['initScript'])
        if self.parameters['keepPath'] != self.defaults['keepPath']:
            parms['keepPath'] = self.parameters['keepPath']
            args.append('--keep-path')
        if self.parameters['optimize'] != self.defaults['optimize']:
            parms['optimize'] = self.parameters['optimize']
            if self.parameters['optimize'] == 1:
                args.append('-O')
            elif self.parameters['optimize'] == 2:
                args.append('-OO')
        
        # 2.2 advanced options
        if self.parameters['sharedLib'] != self.defaults['sharedLib']:
            parms['sharedLib'] = self.parameters['sharedLib']
            args.append('--shared-lib-name=%s' % self.parameters['sharedLib'])
        if self.parameters['defaultPath'] != self.defaults['defaultPath']:
            parms['defaultPath'] = self.parameters['defaultPath'][:]
            args.append('--default-path=%s' % \
                        os.pathsep.join(self.parameters['defaultPath']))
        if self.parameters['includePath'] != self.defaults['includePath']:
            parms['includePath'] = self.parameters['includePath'][:]
            args.append('--include-path=%s' % \
                        os.pathsep.join(self.parameters['includePath']))
        if self.parameters['replacePaths'] != self.defaults['replacePaths']:
            parms['replacePaths'] = self.parameters['replacePaths'][:]
            args.append('--replace-paths=%s' % \
                        os.pathsep.join(self.parameters['replacePaths']))
        if self.parameters['includeModules'] != self.defaults['includeModules']:
            parms['includeModules'] = self.parameters['includeModules'][:]
            args.append('--include-modules=%s' % \
                        ','.join(self.parameters['includeModules']))
        if self.parameters['excludeModules'] != self.defaults['excludeModules']:
            parms['excludeModules'] = self.parameters['excludeModules'][:]
            args.append('--exclude-modules=%s' % \
                        ','.join(self.parameters['excludeModules']))
        if self.parameters['extListFile'] != self.defaults['extListFile']:
            parms['extListFile'] = self.parameters['extListFile']
            args.append('--ext-list-file=%s' % self.parameters['extListFile'])
        
        return (args, parms)

    @pyqtSignature("")
    def on_targetDirButton_clicked(self):
        """
        Private slot to select the target directory.
        
        It displays a directory selection dialog to
        select the directory the files are written to.
        """
        directory = KQFileDialog.getExistingDirectory(\
            self,
            self.trUtf8("Select target directory"),
            self.targetDirEdit.text(),
            QFileDialog.Options(QFileDialog.ShowDirsOnly))
        
        if not directory.isNull():
            # make it relative, if it is a subdirectory of the project path 
            dn = unicode(Utilities.toNativeSeparators(directory))
            dn = dn.replace(self.ppath+os.sep, '')
            while dn.endswith(os.sep):
                dn = dn[:-1]
            self.targetDirEdit.setText(dn)

    @pyqtSignature("")
    def on_sharedLibButton_Clicked(self):
        """
        Private slot to select the Python shared library.
        
        It displays a file selection dialog to select the Python shared library.
        """
        sharedLib = KQFileDialog.getOpenFileName(\
            self,
            self.trUtf8("Select Python shared library"),
            self.sharedLibEdit.text(),
            QString())
        
        if not sharedLib.isEmpty():
            # make it relative, if it is in a subdirectory of the project path 
            sl = unicode(Utilities.toNativeSeparators(sharedLib))
            sl = sl.replace(self.ppath+os.sep, '')
            self.sharedLibEdit.setText(sl)
    
    @pyqtSignature("")
    def on_extListFileButton_clicked(self):
        """
        Private slot to select the external list file.
        
        It displays a file selection dialog to select the external list file,
        the list of include modules is written to.
        """
        extList = KQFileDialog.getOpenFileName(\
            self,
            self.trUtf8("Select external list file"),
            self.extListFileEdit.text(),
            QString())
        
        if not extList.isEmpty():
            # make it relative, if it is in a subdirectory of the project path 
            lf = unicode(Utilities.toNativeSeparators(extList))
            lf = lf.replace(self.ppath+os.sep, '')
            self.extListFileEdit.setText(lf)
    
    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['targetDirectory'] = unicode(self.targetDirEdit.text())
        self.parameters['targetName'] = unicode(self.targetNameEdit.text())
        self.parameters['baseName'] = unicode(self.basenameCombo.currentText())
        self.parameters['initScript'] = unicode(self.initscriptCombo.currentText())
        self.parameters['keepPath'] = self.keeppathCheckBox.isChecked()
        if self.nooptimizeRadioButton.isChecked():
            self.parameters['optimize'] = 0
        elif self.optimizeRadioButton.isChecked():
            self.parameters['optimize'] = 1
        else:
            self.parameters['optimize'] = 2
        
        # get data of advanced tab
        self.parameters['sharedLib'] = unicode(self.sharedLibEdit.text())
        self.parameters['defaultPath'] = \
            self.__splitIt(unicode(self.defaultPathEdit.text()), os.pathsep)
        self.parameters['includePath'] = \
            self.__splitIt(unicode(self.includePathEdit.text()), os.pathsep)
        self.parameters['replacePaths'] = \
            self.__splitIt(unicode(self.replacePathsEdit.text()), os.pathsep)
        self.parameters['includeModules'] = \
            self.__splitIt(unicode(self.includeModulesEdit.text()), ',')
        self.parameters['excludeModules'] = \
            self.__splitIt(unicode(self.excludeModulesEdit.text()), ',')
        self.parameters['extListFile'] = unicode(self.extListFileEdit.text())
        
        # call the accept slot of the base class
        QDialog.accept(self)

    def __splitIt(self, s, sep):
        """
        Private method to split a string.
        
        It differs from Pythons implementation in the way, that it returns
        an empty list, if the split is attempted on an empty string.
        
        @param s string to split (string)
        @param sep separator string (string)
        @return list of split values
        """
        if s == "" or s is None:
            return []
        
        if s.endswith(sep):
            s = s[:-1]
        
        return s.split(sep)
