# data import dialog

#    Copyright (C) 2004 Jeremy S. Sanders
#    Email: Jeremy Sanders <jeremy@jeremysanders.net>
#
#    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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
##############################################################################

"""Module for implementing dialog boxes for importing data in Veusz."""

import os.path
import sys

from .. import qtall as qt
from .. import setting
from .. import utils
from .. import plugins
from . import exceptiondialog
from .veuszdialog import VeuszDialog

def _(text, disambiguation=None, context="ImportDialog"):
    """Translate text."""
    return qt.QCoreApplication.translate(context, text, disambiguation)

class ImportTab(qt.QWidget):
    """Tab for a particular import type."""

    resource = ''
    filetypes = ()       # list of file types handled
    filefilter = None    # name of filter for types for open dialog

    def __init__(self, importdialog, *args):
        """Initialise dialog. importdialog is the import dialog itself."""
        qt.QWidget.__init__(self, *args)
        self.dialog = importdialog
        self.uiloaded = False

    def loadUi(self):
        """Load up UI file."""
        qt.loadUi(os.path.join(
            utils.resourceDirectory, 'ui', self.resource), self)
        self.uiloaded = True

    def reset(self):
        """Reset controls to initial conditions."""
        pass

    def doPreview(self, filename, encoding):
        """Update the preview window, returning whether import
        should be attempted."""
        pass

    def doImport(self, doc, filename, linked, encoding, prefix, suffix, tags):
        """Do the import iteself."""
        pass

    def okToImport(self):
        """Secondary check (after preview) for enabling import button."""
        return True

    def isFiletypeSupported(self, ftype):
        """Is the filetype supported by this tab?"""
        return ftype in self.filetypes

    def useFiletype(self, ftype):
        """If the tab can do something with the selected filetype,
        update itself."""
        pass

importtabs = []
def registerImportTab(name, klass):
    """Register an import tab for the dialog."""
    importtabs.append((name, klass))

class ImportDialog(VeuszDialog):
    """Dialog box for importing data.
    See ImportTab classes above which actually do the work of importing
    """

    dirname = '.'

    def __init__(self, parent, document):

        VeuszDialog.__init__(self, parent, 'import.ui')
        self.document = document

        # whether file import looks likely to work
        self.filepreviewokay = False

        # tabs loaded currently in dialog
        self.tabs = {}
        for tabname, tabclass in importtabs:
            w = tabclass(self)
            self.methodtab.addTab(w, tabname)

        # add promoted plugins
        for p in plugins.importpluginregistry:
            if p.promote_tab is not None:
                from ..dataimport.dialog_plugin import ImportTabPlugins
                w = ImportTabPlugins(self, promote=p.name)
                self.methodtab.addTab(w, p.name)

        self.methodtab.currentChanged.connect(self.slotTabChanged)
        self.browsebutton.clicked.connect(self.slotBrowseClicked)
        self.filenameedit.editTextChanged.connect(self.slotUpdatePreview)

        self.importbutton = self.buttonBox.addButton(
            _("&Import"), qt.QDialogButtonBox.ButtonRole.ApplyRole)
        self.importbutton.clicked.connect(self.slotImport)

        self.buttonBox.button(
            qt.QDialogButtonBox.StandardButton.Reset).clicked.connect(
                self.slotReset)
        self.encodingcombo.currentIndexChanged.connect(self.slotUpdatePreview)

        # change to tab last used
        self.methodtab.setCurrentIndex(
            setting.settingdb.get('import_lasttab', 0))

        # defaults for prefix and suffix
        self.prefixcombo.default = self.suffixcombo.default = ['', '$FILENAME']

        # default state for check boxes
        # add completion for filename
        c = self.filenamecompleter = qt.QCompleter(self.filenameedit)
        self.filenameedit.setCompleter(c)

        self.linkcheckbox.default = True

        # further defaults
        self.encodingcombo.defaultlist = utils.encodings
        self.encodingcombo.defaultval = 'utf_8'

        # load icon for clipboard
        self.clipbutton.setIcon( utils.getIcon('kde-clipboard') )
        qt.QApplication.clipboard().dataChanged.connect(
            self.updateClipPreview)
        self.clipbutton.clicked.connect(self.slotClipButtonClicked)
        self.updateClipPreview()

    def slotBrowseClicked(self):
        """Browse for a data file."""

        fd = qt.QFileDialog(self, _('Browse data file'))
        fd.setFileMode( qt.QFileDialog.FileMode.ExistingFile )

        # collect filters from tabs
        filters = [_('All files (*)')]
        for i in range(self.methodtab.count()):
            w = self.methodtab.widget(i)
            if w.filefilter:
                ftypes = ' '.join(['*'+t for t in w.filetypes])
                f = '%s (%s)' % (w.filefilter, ftypes)
                filters.append(f)
        fd.setNameFilters(filters)

        lastfilt = setting.settingdb.get('import_filterbrowse')
        if lastfilt in filters:
            fd.selectNameFilter(lastfilt)

        # use filename to guess a path if possible
        filename = self.filenameedit.text()
        if os.path.isdir(filename):
            ImportDialog.dirname = filename
        elif os.path.isdir( os.path.dirname(filename) ):
            ImportDialog.dirname = os.path.dirname(filename)

        fd.setDirectory(ImportDialog.dirname)

        # update filename if changed
        if fd.exec() == qt.QDialog.DialogCode.Accepted:
            ImportDialog.dirname = fd.directory().absolutePath()
            self.filenameedit.replaceAndAddHistory( fd.selectedFiles()[0] )
            setting.settingdb['import_filterbrowse'] = fd.selectedNameFilter()
            self.guessImportTab()

    def guessImportTab(self):
        """Guess import tab based on filename."""
        filename = self.filenameedit.text()

        ftype = os.path.splitext(filename)[1]
        # strip off any gz, bz2 extensions to get real extension
        while ftype.lower() in ('.gz', '.bz2'):
            ftype = os.path.splitext(filename)[1]
        ftype = ftype.lower()

        # examine from left to right
        # promoted plugins come after plugins
        idx = -1
        for i in range(self.methodtab.count()):
            w = self.methodtab.widget(i)
            if w.isFiletypeSupported(ftype):
                idx = i

        if idx >= 0:
            self.methodtab.setCurrentIndex(idx)
            self.methodtab.widget(idx).useFiletype(ftype)

    def slotUpdatePreview(self, *args):
        """Update preview window when filename or tab changed."""

        # save so we can restore later
        tab = self.methodtab.currentIndex()
        setting.settingdb['import_lasttab'] = tab
        filename = self.filenameedit.text()
        encoding = str(self.encodingcombo.currentText())
        importtab = self.methodtab.currentWidget()

        if encoding == '':
            return

        if isinstance(importtab, ImportTab):
            if not importtab.uiloaded:
                importtab.loadUi()
            self.filepreviewokay = importtab.doPreview(
                filename, encoding)

        # enable or disable import button
        self.enableDisableImport()

    def slotTabChanged(self, tabindex):
        """Change completer depending on tab."""
        self.slotUpdatePreview()
        w = self.methodtab.widget(tabindex)

        if w.filetypes is None:
            filters = ['*.*']
        else:
            filters = ['*'+t for t in w.filetypes]

        # FIXME: doesn't seem to work
        model = qt.QFileSystemModel()
        model.setRootPath(ImportDialog.dirname)
        model.setNameFilters(filters)
        completer = qt.QCompleter()
        completer.setModel(model)
        self.filenameedit.setCompleter(completer)

    def enableDisableImport(self, *args):
        """Disable or enable import button if allowed."""

        importtab = self.methodtab.currentWidget()
        enabled = self.filepreviewokay and importtab.okToImport()

        # actually enable or disable import button
        self.importbutton.setEnabled( enabled )

    def slotImport(self):
        """Do the importing"""

        filename = self.filenameedit.text()
        linked = self.linkcheckbox.isChecked()
        encoding = str(self.encodingcombo.currentText())
        if filename == '{clipboard}':
            linked = False
        else:
            # normalise filename
            filename = os.path.abspath(filename)

        # import according to tab selected
        importtab = self.methodtab.currentWidget()
        prefix, suffix = self.getPrefixSuffix(filename)
        tags = self.tagcombo.currentText().split()

        try:
            with utils.OverrideCursor():
                with self.document.suspend():
                    importtab.doImport(
                        self.document, filename, linked, encoding,
                        prefix, suffix, tags)
        except IOError:
            qt.QMessageBox.warning(
                self, _("Veusz"), _("Could not read file"))
        except Exception:
            # show exception dialog
            d = exceptiondialog.ExceptionDialog(sys.exc_info(), self)
            d.exec()

    def retnDatasetInfo(self, dsnames, linked, filename):
        """Return a list of information for the dataset names given."""

        lines = [_('Imported data for datasets:')]
        dsnames.sort()
        for name in dsnames:
            ds = self.document.getData(name)
            # build up description
            lines.append(_('%s: %s') % (name, ds.description()))

        # whether the data were linked
        if linked:
            lines.append('')
            lines.append(_('Datasets were linked to file "%s"') % filename)

        return lines

    def getPrefixSuffix(self, filename):
        """Get prefix and suffix values."""
        f = utils.cleanDatasetName( os.path.basename(filename) )
        prefix = self.prefixcombo.lineEdit().text()
        prefix = prefix.replace('$FILENAME', f)
        suffix = self.suffixcombo.lineEdit().text()
        suffix = suffix.replace('$FILENAME', f)
        return prefix, suffix

    def slotReset(self):
        """Reset input fields."""

        self.filenameedit.setText("")
        self.encodingcombo.setCurrentIndex(
            self.encodingcombo.findText("utf_8"))
        self.linkcheckbox.setChecked(True)
        self.prefixcombo.setEditText("")
        self.suffixcombo.setEditText("")

        importtab = self.methodtab.currentWidget()
        importtab.reset()

    def slotClipButtonClicked(self):
        """Clicked clipboard button."""
        self.filenameedit.setText("{clipboard}")

    def updateClipPreview(self):
        """Clipboard contents changed, so update preview if showing clipboard."""

        filename = self.filenameedit.text()
        if filename == '{clipboard}':
            self.slotUpdatePreview()
